2014-07-15 17 views
5

Ich habe in meinem letzten Projekt, bei dem eine Welle/Welligkeit über ein Bild erzeugt wurde, eine Wand getroffen. Ich habe eine gemacht, die mit Grundfarben auf einem Gitter funktioniert, das perfekt funktioniert; Verdammt, ich fügte den Farben je nach Höhe der Welle sogar Schatten hinzu.Wellenerzeugung mit dem "Hugo Elias" Algorithmus bitte! Java

Mein Hauptziel war jedoch, diesen Effekt über ein Bild wie Sie here sehen. Ich folgte einem Algorithmus, den die Leute die Hugo-Elias-Methode nennen (obwohl IDK, wenn er wirklich mit dem Design kam). Sein Tutorial finden Sie here!

Als ich diesem Tutorial folgte, fand ich seinen Pseudocode herausfordernd zu folgen. Ich meine, das Konzept macht größtenteils Sinn, bis ich den Höhenkartenabschnitt über einem Bild getroffen habe. Das Problem, dass die x- und y-Offsets eine ArrayIndexOutOfBoundsException auslösen, liegt daran, dass er den Offset zu dem entsprechenden x oder y addiert. Wenn die Welle zu groß ist (d. H. In meinem Fall 512), wird ein Fehler ausgegeben; Wenn es jedoch zu klein ist, können Sie es nicht sehen.

Irgendwelche Ideen oder Korrekturen zu meiner versuchten Implementierung seines Algorithmus würden meinen Tag machen. Vielen Dank!

So kann ich nicht wirklich eine compile-fähige Version machen, die klein ist und das Problem zeigt, aber ich werde die drei Methoden geben, die ich im Algorithmus verwende. Beachten Sie auch, dass buffer1 und buffer2 die Höhenkarten für die Welle (current und previous) sind und imgArray eine gepufferteImage ist, die durch eine int [img.getWidth() * img.getHeight()] voller ARGB-Werte dargestellt wird.

hier Anyways Sie gehen:

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); 
    } 
} 

Also irgendwelche Vorschläge oder Ideen wäre sehr dankbar. Danke noch einmal!

P.S. Hier sind zwei Bilder vom alten Code, der funktioniert.

enter image description here enter image description here

+1

Möchten Sie Ihren Code eingrenzen und Fragen stellen? –

+0

Wie ich schon sagte, ich habe wirklich versucht, es so weit wie möglich einzugrenzen, um die SSCCE-Richtlinie zu erfüllen, aber ich möchte wirklich nur besser verstehen, wie man den Bildteil seines Algorithmus implementiert. Ich platzierte nur die Methoden, die ich für wichtig hielt, um es zu reparieren. ^ _^ –

+0

+1 Leider ist dieser ausgezeichnete Artikel nicht mehr verfügbar, ich wünschte, ich hätte ihn offline gespeichert, aber ich tat es nicht. Durch diesen Algorithmus habe ich meinen eigenen naiven Blur-Algorithmus realisiert und implementiert (dachte schneller als Gauß) und dann die "trennbare 3-Pass-Box-Unschärfe" entdeckt - einen viel schneller als Gaußschen Ansatz. – Nolo

Antwort

2

bei meinem ursprünglichen Pseudo-Code Sehen, gehe ich davon aus dem Array Out Of Bounds Fehlern passieren, wenn Sie versuchen, die Textur zu sehen, basierend auf dem Offset. Das Problem tritt auf, weil die Brechung im Wasser uns erlaubt, außerhalb der Textur zu sehen.

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 

Der Weg, um dies zu beheben, ist einfach entweder die Textur Koordinaten zu klemmen, oder lassen Sie sie wickeln. Wenn Sie feststellen, dass die Refraktion zu groß ist, können Sie sie reduzieren, indem Sie die Xoffset- und Yoffset-Werte ein wenig verschieben.

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