请用“Hugo Elias”算法制作波浪! Java的

问题描述 投票:6回答:1

在我最近的一个涉及图像波浪/纹波生成的项目中,我似乎遇到了障碍。我在网格上制作了一个可以完美运行的基本颜色;哎呀,我甚至根据波浪的高度添加了颜色。

但是,我的总体目标是使这个效果在像你看到here的图像上工作。我正在遵循人们称之为Hugo Elias方法的算法(尽管如果他真的想出了设计,那就是idk)。他的教程可以找到here

在遵循该教程时,我发现他的伪代码难以理解。我的意思是大多数情况下的概念是有意义的,直到我在图像上击中高度图部分。问题是x和y偏移会抛出一个ArrayIndexOutOfBoundsException,因为他将偏移量添加到相应的x或y。如果波太大(即在我的情况下为512),则会抛出错误;然而,如果它太小你就看不到它。

我试图实现他的算法的任何想法或修复?

所以我不能真正制作一个小的可编译版本并显示问题,但我会给出我在算法中使用的三种方法。还要记住,buffer1和buffer2是wave(current和previous)的高度图,imgArray是一个bufferedImage,由一个充满ARGB值的int [img.getWidth()* img.getHeight()]表示。

无论如何你去:

public class WaveRippleAlgorithmOnImage extends JPanel implements Runnable, MouseListener, MouseMotionListener
{
    private int[] buffer1;
    private int[] buffer2;

    private int[] imgArray;
    private int[] movedImgArray;

    private static double dampening = 0.96;
    private BufferedImage img;

    public WaveRippleAlgorithmOnImage(BufferedImage img)
    {
        this.img = img;

        imgArray = new int[img.getHeight()*img.getWidth()];
        movedImgArray = new int[img.getHeight()*img.getWidth()];

        imgArray = img.getRGB(0, 0, 
                img.getWidth(), img.getHeight(), 
                null, 0, img.getWidth()); 

        //OLD CODE
        /*for(int y = 0; y < img.getHeight(); y++)
        {
            for(int x = 0; x < img.getWidth(); x++)
            {
                imgArray[y][x] = temp[0 + (y-0)*img.getWidth() + (x-0)];
            }
        }*/

        buffer1 = new int[img.getHeight()*img.getWidth()];
        buffer2 = new int[img.getHeight()*img.getWidth()];

        buffer1[buffer1.length/2] = (img.getWidth() <= img.getHeight() ? img.getWidth() / 3 : img.getHeight() / 3);
        //buffer1[25][25] = 10;

        back = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);

        this.addMouseListener(this);
        this.addMouseMotionListener(this);

    }

    //<editor-fold defaultstate="collapsed" desc="Used Methods">
    @Override
    public void run()
    {
        while(true)
        {
            this.update();
            this.repaint();
            this.swap();
        }
    }

    //Called from Thread to update movedImgArray prior to being drawn.
    private void update()
    {
        //This is my attempt of trying to convert his code to java.
        for (int i=img.getWidth(); i < imgArray.length - 1; i++)
        {
            if(i % img.getWidth() == 0 || i >= imgArray.length - img.getWidth())
                continue;

            buffer2[i] = (
                        ((buffer1[i-1]+
                          buffer1[i+1]+
                          buffer1[i-img.getWidth()]+
                          buffer1[i+img.getWidth()]) >> 1)) - buffer2[i];

            buffer2[i] -= (buffer2[i] >> 5);
        }

        //Still my version of his code, because of the int[] instead of int[][].
        for (int y = 1; y < img.getHeight() - 2; y++)
        {
            for(int x = 1; x < img.getWidth() - 2; x++)
            {
                int xOffset = buffer1[((y)*img.getWidth()) + (x-1)] - buffer1[((y)*img.getWidth()) + (x+1)];
                int yOffset = buffer1[((y-1)*img.getWidth()) + (x)] - buffer1[((y+1)*img.getWidth()) + (x)];

                int shading = xOffset;

                //Here is where the error occurs (after a click or wave started), because yOffset becomes -512; which in turn gets
                //multiplied by y... Not good... -_-
                movedImgArray[(y*img.getWidth()) + x] = imgArray[((y+yOffset)*img.getWidth()) + (x+xOffset)] + shading;
            }
        }

        //This is my OLD code that kidna worked...
        //I threw in here to show you how I was doing it before I switched to images.
        /*
        for(int y = 1; y < img.getHeight() - 1; y++)
        {
            for(int x = 1; x < img.getWidth() - 1; x++)
            {
                //buffer2[y][x] = ((buffer1[y][x-1] +
                //buffer1[y][x+1] +
                //buffer1[y+1][x] +
                //buffer1[y-1][x]) / 4) - buffer2[y][x];
                buffer2[y][x] = ((buffer1[y][x-1] +
                        buffer1[y][x+1] +
                        buffer1[y+1][x] +
                        buffer1[y-1][x] +
                        buffer1[y + 1][x-1] +
                        buffer1[y + 1][x+1] +
                        buffer1[y - 1][x - 1] +
                        buffer1[y - 1][x + 1]) / 4) - buffer2[y][x];

                buffer2[y][x] = (int)(buffer2[y][x] * dampening);
            }
        }*/
    }

    //Swaps buffers
    private void swap()
    {
        int[] temp;

        temp = buffer2;
        buffer2 = buffer1;
        buffer1 = temp;
    }

    //This creates a wave upon clicking.  It also is where that 512 is coming from.
    //512 was about right in my OLD code shown above, but helps to cause the Exeception now.
    @Override
    public void mouseClicked(MouseEvent e)
    {
        if(e.getX() > 0 && e.getY() > 0 && e.getX() < img.getWidth() && e.getY() < img.getHeight())
            buffer2[((e.getY())*img.getWidth()) + (e.getX())] = 512;
    }

    private BufferedImage back;
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        back.setRGB(0, 0, img.getWidth(), img.getHeight(), movedImgArray, 0, img.getWidth());
        g.drawImage(back, 0, 0, null);
    }
}

附:这是旧代码工作的两个图像。

java algorithm graphics procedural-generation
1个回答
4
投票

看看我原来的伪代码,我假设当您尝试根据偏移量查找纹理时,会发生Array Out Of Bounds错误。问题的发生是因为水中的折射使我们能够看到纹理之外。

for every pixel (x,y) in the buffer

  Xoffset = buffer(x-1, y) - buffer(x+1, y)
  Yoffset = buffer(x, y-1) - buffer(x, y+1)

  Shading = Xoffset

  t = texture(x+Xoffset, y+Yoffset)  // Array out of bounds?

  p = t + Shading

  plot pixel at (x,y) with colour p

end loop

解决这个问题的方法就是钳制纹理坐标,或让它们换行。此外,如果您发现折射量太大,可以通过稍微移位Xoffset和Yoffset值来减少折射量。

int clamp(int x, int min, int max)
{
    if (x < min) return min;
    if (x > max) return max;
    return x;
}

int wrap(int x, int min, int max)
{
    while (x<min)
       x += (1+max-min);

    while (x>max)
       x -= (1+max-min);

    return x;
}


for every pixel (x,y) in the buffer

    Xoffset = buffer(x-1, y) - buffer(x+1, y)
    Yoffset = buffer(x, y-1) - buffer(x, y+1)

    Shading = Xoffset

    Xoffset >>= 1                              // Halve the amount of refraction
    Yoffset >>= 1                              // if you want.

    Xcoordinate = clamp(x+Xoffset, 0, Xmax)    // Use clamp() or wrap() here
    Ycoordinate = clamp(y+Yoffset, 0, Ymax)    // 
    t = texture(Xcoordinate, Ycoordinate)  

    p = t + Shading

    plot pixel at (x,y) with colour p

end loop
© www.soinside.com 2019 - 2024. All rights reserved.