2016-04-18 5 views
1

Ich habe versucht, ein Reaktions-Diffusions-Modell auf der GPU mit JOGL und GLSL zu implementieren.GP/GPU: Ping-Pong-Technik mit JOGL

Ich benutze eine Ping-Pong-Technik mit 2 FramebufferObject (Ich habe es auch mit einem FBO und 2 Farben Attachements versucht, ohne Erfolg). Shader scheint richtig, da ich es in der Einheit (mit einigen Anpassungen) versucht habe und es funktioniert. Nach einer Woche, in der ich viele Dinge ausprobiert habe, habe ich keine Ahnung, dass dieser Code funktioniert. Ich bin wirklich kein Spezialist für JOGL, also vermisse ich vielleicht etwas Offensichtliches.

Das Ergebnis ist ein Bild, das mit der Zeit weiß wird: keine Reaktion-Diffusions-Verhalten und ich verstehe nicht warum!

Vielen Dank im Voraus für hilft. Hier ist mein Code:

package gpu2; 

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

import java.nio.IntBuffer; 
import java.nio.FloatBuffer; 
import java.io.File; 

import com.jogamp.opengl.GL2; 
import com.jogamp.opengl.GLAutoDrawable; 
import com.jogamp.opengl.GLEventListener; 
import com.jogamp.opengl.awt.GLCanvas; 
import com.jogamp.opengl.glu.GLU; 
import com.jogamp.opengl.util.FPSAnimator; 
import com.jogamp.opengl.GLFBODrawable; 
import com.jogamp.opengl.FBObject; 
import com.jogamp.opengl.FBObject.Colorbuffer; 
import com.jogamp.opengl.FBObject.ColorAttachment; 
import com.jogamp.opengl.FBObject.TextureAttachment; 
import com.jogamp.opengl.util.glsl.ShaderCode; 
import com.jogamp.opengl.util.glsl.ShaderProgram; 
import com.jogamp.opengl.util.glsl.ShaderUtil; 
import com.jogamp.opengl.util.GLBuffers; 
import com.jogamp.opengl.util.texture.Texture; 
import com.jogamp.opengl.util.texture.TextureIO; 

import com.jogamp.opengl.GLCapabilities; 
import com.jogamp.opengl.GLOffscreenAutoDrawable; 
import com.jogamp.opengl.GLProfile; 
import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil; 
import com.jogamp.opengl.GLDrawableFactory; 

import static com.jogamp.opengl.GL.*; // GL constants 
import static com.jogamp.opengl.GL2.*; // GL2 constants 

import gpu2.ModelParam; 

/** 
* JOGL 2.0 Program Template (GLCanvas) 
* This is a "Component" which can be added into a top-level "Container". 
* It also handles the OpenGL events to render graphics. 
*/ 
@SuppressWarnings("serial") 
public class JOGL2Setup_GLCanvas extends GLCanvas implements GLEventListener { 
    // Define constants for the top-level container 
    private static String TITLE = "JOGL 2.0 Setup (GLCanvas)"; // window's title 
    private static final int CANVAS_WIDTH = 512; // width of the drawable 
    private static final int CANVAS_HEIGHT = 512; // height of the drawable 
    private static final int FPS = 30; // animator's target frames per second 

    private final float[] canvasVertices = { 
      -1f, -1f, 0.0f, 
      -1f, 1f, 0.0f, 
      1f, -1f, 0.0f, 
      1f, 1f, 0.0f, 
    }; 

    private final float[] canvasTexCoords = { 
      0.0f, 0.0f, 
      0.0f, 1.0f, 
      1.0f, 0.0f, 
      1.0f, 1.0f, 
}; 

    /** The entry main() method to setup the top-level container and animator */ 
    public static void main(String[] args) { 
     // Run the GUI codes in the event-dispatching thread for thread safety 
     SwingUtilities.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      // Create the OpenGL rendering canvas 
      GLCanvas canvas = new JOGL2Setup_GLCanvas(); 
      canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT)); 

      // Create a animator that drives canvas' display() at the specified FPS. 
      final FPSAnimator animator = new FPSAnimator(canvas, FPS, true); 

      // Create the top-level container 
      final JFrame frame = new JFrame(); // Swing's JFrame or AWT's Frame 
      frame.getContentPane().add(canvas); 
      frame.addWindowListener(new WindowAdapter() { 
       @Override 
       public void windowClosing(WindowEvent e) { 
        // Use a dedicate thread to run the stop() to ensure that the 
        // animator stops before program exits. 
        new Thread() { 
        @Override 
        public void run() { 
         if (animator.isStarted()) animator.stop(); 
         System.exit(0); 
        } 
        }.start(); 
       } 
      }); 
      frame.setTitle(TITLE); 
      frame.pack(); 
      frame.setVisible(true); 
      animator.start(); // start the animation loop 
     } 
     }); 
    } 

    // Setup OpenGL Graphics Renderer 

    private GLU glu; // for the GL Utility 
    private GL2 gl; 

    //OpenGl data 
    private int vboVertices; 
    private int vboTextCoord; 
    private Texture textureFile; 

    private FBObject fbo[]; 

    private ShaderProgram shaderCompute; 
    private ShaderProgram shaderVisu; 
    private ShaderProgram shaderComputeInit; 

    private int currentSourceBuffer = 0; 
    private int currentDestBuffer = 1; 

    private int currentFrame = 0; 
    private int maxFrameCount = 5000000; 
    private float clearUniform = 0; 

    ModelParam params = new ModelParam(); 

    public JOGL2Setup_GLCanvas() { 
     this.addGLEventListener(this); 
    } 

    @Override 
    public void init(GLAutoDrawable drawable) { 
     gl = drawable.getGL().getGL2();  // get the OpenGL graphics context 
     glu = new GLU();       // get GL Utilities 
     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color 

     gl.glEnable(GL_TEXTURE_2D); 

     gl.glEnable(GL_COLOR_MATERIAL); 
     gl.glEnable(GL_FRAMEBUFFER); 
     gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NEAREST); // best perspective correction 

     viewOrtho(gl); 

     gl.glViewport(0,0,CANVAS_WIDTH,CANVAS_HEIGHT); 

     int[] buffers = new int[2]; 
     gl.glGenBuffers(2, buffers, 0); 

     vboVertices = buffers[0]; 
     vboTextCoord = buffers[1]; 

     gl.glBindBuffer(GL_ARRAY_BUFFER, vboVertices); 
     gl.glBufferData(GL_ARRAY_BUFFER, canvasVertices.length*(Float.SIZE/Byte.SIZE)*3, FloatBuffer.wrap(canvasVertices), GL_STATIC_DRAW); 

     gl.glBindBuffer(GL_ARRAY_BUFFER, vboTextCoord); 
     gl.glBufferData(GL_ARRAY_BUFFER, canvasTexCoords.length*(Float.SIZE/Byte.SIZE)*2, FloatBuffer.wrap(canvasTexCoords), GL_STATIC_DRAW); 

     gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 

     // ------------ create Texture Source------------------------ 
     textureFile = initializeTexture(); 
     if (textureFile==null) { 
     System.out.println("cannot load texture from disk"); 
     } 

     // ------------ load shaders ------------------------ 
     shaderCompute = loadShader(gl, "compute.vsh", "compute.fsh"); 
     shaderComputeInit = loadShader(gl, "compute.vsh", "computeInit.fsh"); 
     shaderVisu = loadShader(gl, "visu.vsh", "visu.fsh"); 

     // ------------ create FBO ------------------------ 

     initFBO(); 


    } 

    /** 
    * Called back by the animator to perform rendering. 
    */ 
    @Override 
    public void display(GLAutoDrawable drawable) { 

     if (currentFrame < maxFrameCount) { 
      prepareNextStep(); 

      renderToFBO(); 
      currentFrame++; 

     } 
     renderFBOToScreen(); 
    } 

    private void prepareNextStep() { 
      currentSourceBuffer = 1 - currentSourceBuffer; 
      currentDestBuffer = 1 - currentDestBuffer; 
     } 

    private void renderToFBO() 
    { 
     fbo[currentDestBuffer].bind(gl); 
     //gl.glClear(GL_COLOR_BUFFER_BIT); 

     viewOrtho(gl); 

     shaderCompute.useProgram(gl, true); 

     setShaderUniformFloat(gl, shaderCompute.program(), "diffuseU", 0.211f); 
     setShaderUniformFloat(gl, shaderCompute.program(), "diffuseV", 0.088f); 
     setShaderUniformFloat(gl, shaderCompute.program(), "feed", 0.007f); 
     setShaderUniformFloat(gl, shaderCompute.program(), "kill", 0.08f); 
     setShaderUniformFloat(gl, shaderCompute.program(), "Tech", 1f); 

     setShaderUniformFloat(gl, shaderCompute.program(), "currentFrame", currentFrame); 
     setShaderUniformFloat2(gl, shaderCompute.program(), "resolution", CANVAS_WIDTH, CANVAS_HEIGHT); 

     drawDataBuffer(shaderCompute, true); 

     shaderCompute.useProgram(gl, false); 
     fbo[currentDestBuffer].unbind(gl); 
    } 

    void drawDataBuffer(ShaderProgram currentShader, boolean sencondImage) { 
     // --- draw vbo 
     gl.glEnableClientState(GL_VERTEX_ARRAY); 
     gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
     //textcoords 
     gl.glBindBuffer(GL_ARRAY_BUFFER,vboTextCoord); 
     gl.glTexCoordPointer(2, GL_FLOAT, 0, 0); 
     //vertices 
     gl.glBindBuffer(GL_ARRAY_BUFFER, vboVertices); 
     gl.glVertexPointer(3, GL_FLOAT, 0, 0); 

     //activate texture data from last fbo 
     final FBObject.Colorbuffer texSource = (FBObject.Colorbuffer) fbo[currentSourceBuffer].getColorbuffer(0); 
     gl.glActiveTexture(GL_TEXTURE0); 
     gl.glBindTexture(GL_TEXTURE_2D, texSource.getName()); 
     setShaderUniform1i(gl, currentShader.program(), "textureData", 0); 

     if (sencondImage) { 
      //activate texture with image from file 
      gl.glActiveTexture(GL_TEXTURE1); 
      gl.glBindTexture(GL_TEXTURE_2D, textureFile.getTextureObject()); 
      textureFile.bind(gl); 
      setShaderUniform1i(gl, currentShader.program(), "textureImage", 1); 
     } 

     //draw buffer on screens 
     gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, canvasVertices.length/3); 

     //disable texture image 
     if (sencondImage) { 
      gl.glActiveTexture(GL_TEXTURE1); 
      textureFile.disable(gl); 
     } 
     //disable texture data 
     gl.glActiveTexture(GL_TEXTURE0); 
     gl.glDisable(texSource.getName()); 

     gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
     gl.glDisableClientState(GL_VERTEX_ARRAY); 

    } 

    public void renderFBOToScreen() 
    { 
     gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers 
     gl.glLoadIdentity(); // reset the model-view matrix 

     viewOrtho(gl); 
     gl.glEnable(GL_TEXTURE_2D); 

     final FBObject.Colorbuffer tex0 = (FBObject.Colorbuffer) fbo[currentDestBuffer].getColorbuffer(0); 
     gl.glActiveTexture(GL_TEXTURE0); 
     gl.glBindTexture(GL_TEXTURE_2D, tex0.getName()); 

     //activate shader 
     shaderVisu.useProgram(gl, true); 

     // --- draw vbo 
     gl.glEnableClientState(GL_VERTEX_ARRAY); 
     gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
     //textcoords 
     gl.glBindBuffer(GL_ARRAY_BUFFER, vboTextCoord); 
     gl.glTexCoordPointer(2, GL_FLOAT, 0, 0); 
     //vertices 
     gl.glBindBuffer(GL_ARRAY_BUFFER, vboVertices); 
     gl.glVertexPointer(3, GL_FLOAT, 0, 0); 

     //draw buffer on screens 
     gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, canvasVertices.length/3); 

     gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
     gl.glDisableClientState(GL_VERTEX_ARRAY); 

     gl.glBindBuffer(GL_ARRAY_BUFFER, 0); 
     //desactivate shader 
     shaderVisu.useProgram(gl, false); 

    } 

    private void initFBO() 
    { 
     try { 

     gl.glEnable(GL_TEXTURE_2D); 

     fbo = new FBObject[2]; 

     //first fbo 
     fbo[currentSourceBuffer] = new FBObject(); // Create FrameBuffer 
     fbo[currentSourceBuffer].init(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); 
     fbo[currentSourceBuffer].reset(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); // int width, height - size of FBO, can be resized with the same call 
     fbo[currentSourceBuffer].bind(gl); 

     int tex = genTexture(gl); 
     gl.glBindTexture(GL_TEXTURE_2D, tex); 
     gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_FLOAT, null); 
     fbo[currentSourceBuffer].attachTexture2D(gl, 0, GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 
     //gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); 
     int DrawBuffers[] = {GL_COLOR_ATTACHMENT0}; 
     gl.glDrawBuffers(1, DrawBuffers, 0); // "1" is the size of DrawBuffers 
     fbo[currentSourceBuffer].unbind(gl); 

     //second fbo 
     fbo[currentDestBuffer] = new FBObject(); // Create FrameBuffer 
     fbo[currentDestBuffer].init(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); 
     fbo[currentDestBuffer].reset(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); // int width, height - size of FBO, can be resized with the same call 
     fbo[currentDestBuffer].bind(gl); 

     tex = genTexture(gl); 
     gl.glBindTexture(GL_TEXTURE_2D, tex); 
     gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_FLOAT, null); 
     fbo[currentDestBuffer].attachTexture2D(gl, 0, GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 
     //ogl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); 
     gl.glDrawBuffers(1, DrawBuffers, 1); // "1" is the size of DrawBuffers 
     fbo[currentDestBuffer].unbind(gl); 

     } catch (Exception e) { 
      System.out.println("Problem with fbo init " + e); 
      e.printStackTrace(); 
     } 

    } 

    private Texture initializeTexture() { 

     Texture t = null; 

     try { 
      t = TextureIO.newTexture(new File("e:/shaders/wiki.jpg"), false); 

      t.setTexParameteri(gl, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
      t.setTexParameteri(gl, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
      t.setTexParameteri(gl, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
      t.setTexParameteri(gl, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

     } catch (Exception e) { 
      System.out.println("Unable to read texture file: " + e); 
      e.printStackTrace(); 
     } 

     return t; 
    } 

    private ShaderProgram loadShader(GL2 gl, String vertexShader, String fragmentShader) 
    { 
      ShaderCode vertShader = ShaderCode.create(gl, GL2.GL_VERTEX_SHADER, 1, getClass(), new String[]{"e:/shaders/"+vertexShader},false); 
      vertShader.compile(gl); 

      ShaderCode fragShader = ShaderCode.create(gl, GL2.GL_FRAGMENT_SHADER, 1, getClass(), new String[]{"e:/shaders/"+fragmentShader},false); 
      fragShader.compile(gl); 

      ShaderProgram newShader = new ShaderProgram(); 
      newShader.init(gl); 
      newShader.add(vertShader); 
      newShader.add(fragShader); 

      newShader.link(gl, System.out); 

      vertShader.destroy(gl); 
      fragShader.destroy(gl); 

      return newShader; 
    } 

    public static void setShaderUniform1i(GL2 inGL,int inProgramID,String inName,int inValue) { 
     int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName); 
     if (tUniformLocation != -1) { 
      inGL.glUniform1i(tUniformLocation, inValue); 
     } else { 
      System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName); 
     } 
    } 

    public static void setShaderUniformFloat(GL2 inGL,int inProgramID,String inName,float inValue) { 
     int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName); 
     if (tUniformLocation != -1) { 
      inGL.glUniform1f(tUniformLocation, inValue); 
     } else { 
      System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName); 
     } 
    } 
    public static void setShaderUniformFloat2(GL2 inGL,int inProgramID,String inName,float inValue1 ,float inValue2) { 
     int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName); 
     if (tUniformLocation != -1) { 
      inGL.glUniform2f(tUniformLocation, inValue1, inValue2); 
     } else { 
      System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName); 
     } 
    } 

    private void viewOrtho(GL2 gl) // Set Up An Ortho View 
    { 
     gl.glMatrixMode(GL_PROJECTION); // Select Projection 
     gl.glPushMatrix();  // Push The Matrix 
     gl.glLoadIdentity();  // Reset The Matrix 
     gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 
     gl.glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix 
     gl.glPushMatrix();  // Push The Matrix 
     gl.glLoadIdentity();  // Reset The Matrix 
    } 

    private int genTexture(GL2 gl) { 
     final int[] tmp = new int[1]; 
     gl.glGenTextures(1, tmp, 0); 
     return tmp[0]; 
    } 

    /** 
    * Called back before the OpenGL context is destroyed. Release resource such as buffers. 
    */ 
    @Override 
    public void dispose(GLAutoDrawable drawable) { } 
} 

und die entsprechenden GLSL Shader:

#version 120 

uniform sampler2D textureData; 
uniform sampler2D textureImage; 


uniform vec2 resolution; 

uniform float diffuseU; 
uniform float diffuseV; 
uniform float feed; 
uniform float kill; 
uniform float Tech = 1.0; 
uniform float currentFrame = 0.0; 

void main() { 
    //coords 
    vec2 position = (gl_FragCoord.xy/resolution.xy); 
    vec2 pixel = 1./resolution; 

    //get data from texture 
    vec4 imgSource = texture2D(textureImage, gl_TexCoord[0].st); 
    vec2 oldUV = texture2D(textureData, gl_TexCoord[0].st).rg; 

    if(currentFrame<10){ 
     if (distance(position,vec2(0.5,0.5 - currentFrame * 0.01f)) < 0.2f) 
      oldUV = vec2(0.0,0.2); 
     else if (distance(position,vec2(0.5,0.5 - currentFrame * 0.01f)) < 0.3f) 
      oldUV = vec2(0.5,0.1); 
     else 
      oldUV = vec2(0.1,0.0); 

     gl_FragColor = vec4(oldUV.rg, 0.0, 1.0); 
     return; 
    } 

    //get neightboors 
    vec2 dataUp = texture2D(textureData, position + pixel * vec2(0., 1.)).rg; 
    vec2 dataDown = texture2D(textureData, position + pixel * vec2(0., -1.)).rg; 
    vec2 dataLeft = texture2D(textureData, position + pixel * vec2(-1., 0.)).rg; 
    vec2 dataRight = texture2D(textureData, position + pixel * vec2(1., 0.)).rg; 
    //adapt parameters 
    vec2 imgParam = imgSource.rg; 
    float dU = diffuseU ;//+ 0.01 * (imgParam - 0.5); 
    float dV = diffuseV ;//+ 0.01 * (imgParam - 0.5); 
    float F = feed ;//+ 0.01 * (imgParam - 0.5); 
    float K = kill ;//+ 0.01 * (imgParam - 0.5); 
    //compute new values 
    vec2 laplace = (dataUp+dataDown+dataLeft+dataRight) - 4.0 * oldUV; 
    float uvv = oldUV.r * oldUV.g * oldUV.g; 
    // calculate delta quantities 
    float du = dU * laplace.r - uvv + F*(1.0 - oldUV.r); 
    float dv = dV * laplace.g + uvv - (F+K)*oldUV.g; 
    vec2 newUV = oldUV + vec2(du, dv)* Tech; 

    gl_FragColor = vec4(newUV.rg, 0.0, 1.0); 
} 

Antwort

0

paar Überlegungen:

  • vermeiden veraltet OpenGL (und GLU), verwenden GL4 (oder GL3)

  • es sei denn, Sie benötigen awt/swt/swing, bevorzugen Newt, mehr here

  • bevorzugen Animator statt FPSAnimator, mehr here

  • direkte Puffer anstelle von Arrays bevorzugen, sonst da jogl sie darunter zu schaffen hat, und Sie können nicht Spur halten (= ausplanen wenn Sie fertig sind) dieser nativen Zuteilungen

  • GL4 ermöglicht es Ihnen, auch alle jene einheitliche Overhead (und auch mögliche Fehler) vermeiden Sie mit (vor allem während der Laufzeit) zu tun haben, dank expliziten Stellen

  • pr Eher direkte Pufferverwaltung anstelle von FBObject, wenn Sie nicht wirklich wissen, was FBObject tut. Sobald Sie es funktioniert haben, können Sie mit dieser Klasse weitermachen. Dies kann (einer der) Grund sein, dass Ihr Code nicht funktioniert, weil etwas nicht so eingerichtet wird, wie Sie es brauchen. Darüber hinaus sind die Zeilen von Codes benötigt, um FBObject zu ersetzen sind im Wesentlichen die gleichen

  • (wenn Sie nicht ausdrücklich aus irgendeinem Grund verwenden können) bevorzugen einige wörtliche Weise, um die Textur einheitliche Position zu definieren, ist es in der Regel eine andere heikle Teil verursacht Bugs, so etwas wie this

  • bevorzugen einen Sampler für die Texturen auch, Flexibilität mehr man gibt

  • nicht 1 Woche beim nächsten Mal warten, lassen Sie uns früher kennen! :) Frustration kann eine unangenehme Sache sein, die dich leicht fallen lässt. Zusammen können wir Ihnen helfen, es funktioniert;)

+0

Wow! Vielen Dank für all diese Überlegungen. Besonders der letzte;) Ich werde dem folgen, um zu versuchen, es funktioniert – Konzto

Verwandte Themen