我尝试使用JOGL和GLSL在GPU上实现反应扩散模型。

我使用带有2个FramebufferObject的乒乓技术(我也尝试过使用一个FBO和2个Colors附件,但均未成功)。
Shader似乎是正确的,因为我已经统一尝试过(有一些改编)并且可以工作。
经过一个星期的尝试,我完全不知道如何使此代码有效。我真的不是JOGL的专家,所以也许我想念一些明显的东西。

结果是图像随着时间的推移变成白色:没有反应扩散行为,我不明白为什么!

在此先感谢您的帮助。这是我的代码:

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


以及相应的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);
}

最佳答案

几个注意事项:


避免使用不推荐使用的OpenGL(和GLU),请使用GL4(或GL3)
除非您需要awt / swt / swing,否则最好使用newt,更多here
更喜欢Animator而不是FPSAnimator,更多here
首选直接缓冲区而不是数组,因为否则jogl必须在下面创建它们,并且您无法跟踪(=完成后取消分配)这些本机分配
有了GL4,由于位置明确,您还可以避免必须处理的所有那些统一开销(以及潜在的错误)(尤其是在运行时)
除非您真的知道FBObject在做什么,否则暂时最好使用直接缓冲区管理而不是FBObject。一旦开始运行,就可以继续使用该类。这可能是(其中之一)导致您的代码无法正常工作的原因,因为某些设置没有按照您的需要进行设置。而且,替换FBObject所需的代码行基本相同
(如果由于某种原因而无法使用显式位置)则倾向于使用某种文字方式来定义纹理统一的位置,这通常是导致错误的另一个棘手的部分,例如this
更喜欢纹理采样器,为您提供更大的灵活性
下次不要等待一个星期,让我们早点知道! :)挫败感很容易使您失望。我们可以一起帮助您使它正常工作;)

关于java - GP/GPU:JOGL的乒乓技术,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36686895/

10-11 20:16