我尝试使用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/