Related
I am new to OpenGL and I just begin to try LWJGL, everything worked fine until I added the PVM matrices, I don't know why nothing shows up when I added them.
The matrices related code is commented.
Here is the code :
public class Window {
private int vaoid;
private int vbover;
private int vboind;
private int vid;
private int fid;
private int pid;
//private int pml;projection matrix location
//private int vml;view matrix location
//private int mml;model matrix location
//private Matrix4f projectionMatrix;
//private Matrix4f viewMatrix;
//private Matrix4f modelMatrix;
//private FloatBuffer projbuffer = BufferUtils.createFloatBuffer(16);
public void start() {
try {
Display.setDisplayMode(new DisplayMode(800,600));
Display.setTitle("OpenGL Try");
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
init();
while (!Display.isCloseRequested()) {
update();
Display.sync(60);
Display.update();
}
cleanUp();
Display.destroy();
}
public static void main(String[] argv) {
Window displayExample = new Window();
displayExample.start();
}
public void init() {
//projectionMatrix = createProjectionMatrix();
float[] vertices = {
-0.5f, 0.5f, 0f, // Left top ID: 0
-0.5f, -0.5f, 0f, // Left bottom ID: 1
0.5f, -0.5f, 0f, // Right bottom ID: 2
0.5f, 0.5f, 0f // Right left ID: 3
};
FloatBuffer verticesbuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesbuffer.put(vertices);
verticesbuffer.flip();
byte[] indices = {
// Left bottom triangle
0, 1, 2,
// Right top triangle
2, 3, 0
};
ByteBuffer indicesbuffer = BufferUtils.createByteBuffer(indices.length);
indicesbuffer.put(indices);
indicesbuffer.flip();
vaoid = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoid);
vbover = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbover);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER,verticesbuffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0,3,GL11.GL_FLOAT,false,0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,0);
GL30.glBindVertexArray(0);
vboind = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER,vboind);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER,indicesbuffer,GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER,0);
vid = loadShader("./res/shader.ver",GL20.GL_VERTEX_SHADER);
fid = loadShader("./res/shader.frag",GL20.GL_FRAGMENT_SHADER);
pid = GL20.glCreateProgram();
GL20.glAttachShader(pid,vid);
GL20.glAttachShader(pid, fid);
GL20.glBindAttribLocation(pid, 0, "in_position");
GL20.glLinkProgram(pid);
GL20.glValidateProgram(pid);
//pml = GL20.glGetUniformLocation(pid, "projMatrix");
//vml = GL20.glGetUniformLocation(pid, "viewMatrix");
//mml = GL20.glGetUniformLocation(pid, "modelMatrix");
GL20.glUseProgram(pid);
//projectionMatrix.store(projbuffer);
//projbuffer.flip();
//GL20.glUniformMatrix4(pml, false, projbuffer);
GL20.glUseProgram(0);
}
public void update() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT|GL11.GL_DEPTH_BUFFER_BIT);
GL20.glUseProgram(pid);
//viewMatrix = createTransformationMatrix(new Vector3f(0,0,0),new Vector3f(0,0,0),1f);
//viewMatrix.store(projbuffer);projbuffer.flip();
//GL20.glUniformMatrix4(vml, false, projbuffer);
//modelMatrix = createTransformationMatrix(new Vector3f(0,0,0),new Vector3f(0,0,0),1f);
//modelMatrix.store(projbuffer);projbuffer.flip();
//GL20.glUniformMatrix4(mml, false, projbuffer);
GL30.glBindVertexArray(vaoid);
GL20.glEnableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER,vboind);
GL11.glDrawElements(GL11.GL_TRIANGLES,6,GL11.GL_UNSIGNED_BYTE,0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER,0);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
GL20.glUseProgram(0);
}
public void cleanUp() {
GL20.glUseProgram(0);
GL20.glDetachShader(pid, vid);
GL20.glDetachShader(pid, fid);
GL20.glDeleteShader(vid);
GL20.glDeleteShader(fid);
GL20.glDeleteProgram(pid);
GL20.glDisableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glDeleteBuffers(vbover);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL15.glDeleteBuffers(vboind);
GL30.glBindVertexArray(0);
GL30.glDeleteVertexArrays(vaoid);
}
public int loadShader(String filePath,int type) {
StringBuilder sb = new StringBuilder();
int shaderId = 0;
try {
BufferedReader br = new BufferedReader(new FileReader(filePath));
String line="";
while((line = br.readLine())!=null) {
sb.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
shaderId = GL20.glCreateShader(type);
GL20.glShaderSource(shaderId, sb);
GL20.glCompileShader(shaderId);
return shaderId;
}
/* public Matrix4f createTransformationMatrix(Vector3f pos,Vector3f
rot,float scale) {
Matrix4f mat = new Matrix4f();
Matrix4f.scale(new Vector3f(scale,scale,scale),mat,mat);
Matrix4f.translate(pos,mat,mat);
Matrix4f.rotate((float) Math.toRadians(rot.x),new
Vector3f(1,0,0),mat,mat);
Matrix4f.rotate((float) Math.toRadians(rot.y),new
Vector3f(0,1,0),mat,mat);
Matrix4f.rotate((float) Math.toRadians(rot.z),new
Vector3f(0,0,1),mat,mat);
return mat;
}*/
/*public Matrix4f createProjectionMatrix() {
Matrix4f pm = new Matrix4f();
float fieldOfView = 60f;
float aspectRatio = (float)Display.getWidth()/(float)Display.getHeight();
float znear = 0.1f;
float zfar = 100f;
float frustumLength = zfar-znear;
float ysize = (float) (1/Math.tan(Math.toRadians(fieldOfView/2f)));
float xsize = ysize/aspectRatio;
pm.m00 = xsize;
pm.m11 = ysize;
pm.m22 = -((znear+zfar)/frustumLength);
pm.m23 = -1;
pm.m32 = -((2*znear*zfar)/frustumLength);
pm.m33 = 0;
return pm;
} */
}
And the vertex shader :
#version 150 core
in vec3 in_position;
uniform mat4 projMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
out vec4 pass_color;
void main(void){
gl_Position = projMatrix * viewMarix * modelMatrix *
vec4(in_position,1.0);
pass_color = vec4(1,0,1,1);
}
And the fragment shader :
#version 150 core
in vec4 pass_color;
out vec4 out_color;
void main(void){
out_color = pass_color;
}
Any help is appreciated ,that block me to continue learning the new opengl stuff, thank you.
I've noticed 3 problems.
You should use an IntBuffer instead of a ByteBuffer for the indices, because you store integers in this buffer. If you change the buffer type you need to also change GL_UNSIGNED_BYTE in glDrawElements to GL_UNSIGNED_INT.
Don't bind GL_ELEMENT_ARRAY_BUFFER to 0 after binding the indices buffer.
You don't need to bind and unbind GL_ELEMENT_ARRAY_BUFFER when calling glDarwElements
I hope this helps.
I've tried to implement an reaction-diffusion model on GPU with JOGL and GLSL.
I use a ping pong technique with 2 FramebufferObject ( I've tried too with one FBO and 2 Colors attachements without success).
Shader seems correct since I've tried it in unity (with some adaptations) and it works.
After one week of trying many things, i'm completely out of idea to make this code works. I'm really not specialist of JOGL, so maybe i miss something evident.
The result is an image which becomes white with time : no reaction-diffusion behaviors and I don't understand why !
Thanks in advance for helps. Here is my 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) { }
}
And the corresponding 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);
}
Few considerations:
avoid deprecated OpenGL (and GLU), use GL4 (or GL3)
unless you need awt/swt/swing, prefer newt, more here
prefer Animator instead of FPSAnimator, more here
prefer direct buffers instead of arrays, since otherwise jogl has to create them underneath and you can't keep trace (= deallocate when done) of those native allocations
GL4 will allow you also to avoid all those uniform overhead (and also potential bugs) you have to deal with (especially during runtime), thanks to explicit locations
prefer direct buffer management instead of FBObject for the moment unless you really know what FBObject is doing. Once you get it working, you can move on using that class. This may be (one of the) cause your code is not working, because something is not getting setup up as you need. Moreover, the lines of codes needed to replace FBObject are essentially the same
(if you can't use explicit location for any reason) prefer some literal way to define the texture uniform location, it is usually another tricky part causing bugs, something like this
prefer also a sampler for the textures, gives you more flexibility
don't wait one week next time, let us know earlier! :) Frustation can be a nasty thing that put you down easily. Together we can help you getting it working ;)
so I've been following a fair amount of tutorials on the internet and I tried to create my own graphics engine with OpenGL. The problem is that I can't make the texture work. I can render a square on the screen and change the color but I can't show a texture.
This is the Main Method:
public class Main implements Runnable{
public int HEIGHT = 400;
public int WIDTH = 400;
private boolean running;
private Thread thread;
private long window;
Level level;
public Main(){
}
public void start(){
running = true;
thread = new Thread(this, "Game");
thread.start();
}
public void stop(){
try {
thread.join();
running = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void init(){
if(glfwInit() != GL_TRUE){
System.err.println("Couldn't load the window");
return;
}
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Game!!", NULL, NULL);
if(window == NULL){
System.err.println("Couldn't create the window");
return;
}
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(vidmode) - WIDTH) / 2, (GLFWvidmode.height(vidmode) - HEIGHT) / 2);
glfwMakeContextCurrent(window);
glfwShowWindow(window);
GLContext.createFromCurrent();
Input input = new Input();
glfwSetKeyCallback(window, input);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
System.out.println("OpenGL: " + glGetString(GL_VERSION));
Shader.loadAll();
Matrix4f pr_matrix = Matrix4f.orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
Shader.BG.setUniformMat4f("pr_matrix", pr_matrix);
Shader.BG.setUniform1i("tex", 1);
level = new Level();
}
public void run() {
init();
long lastTime = System.nanoTime();
double delta = 0.0;
double ns = 1000000000.0 / 60.0;
long timer = System.currentTimeMillis();
int updates = 0;
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1.0) {
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(updates + " ups, " + frames + " fps");
updates = 0;
frames = 0;
}
if (glfwWindowShouldClose(window) == GL_TRUE)
running = false;
}
}
private void update(){
glfwPollEvents();
if(Input.isKeyDown(GLFW_KEY_ESCAPE)){
running = false;
}
}
private void render(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int error = glGetError();
if (error != GL_NO_ERROR)
System.out.println(error);
glfwSwapBuffers(window);
level.render();
}
public static void main(String arg[]){
new Main().start();
}
}
This is the Level Method:
public class Level {
private VertexArray background;
private Texture bgTexture;
public Level() {
float[] vertices = new float[] {
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f
};
byte[] indices = new byte[] { 0, 1, 3, 3, 1, 2 };
float[] tcs = new float[] {
0f, 0f,
0, 1.0f,
1.0f, 1.0f,
1.0f, 0
};
background = new VertexArray(vertices, indices, tcs);
bgTexture = new Texture("res/bird.png");
}
public void render() {
Shader.BG.enable();
bgTexture.bind();
background.bind();
background.draw();
bgTexture.unbind();
Shader.BG.disable();
}
Here the Texture Class:
public class Texture {
private int width, height;
private int texture;
public Texture(String path) {
texture = load(path);
}
private int load(String path) {
int[] pixels = null;
try {
BufferedImage image = ImageIO.read(new FileInputStream(path));
width = image.getWidth();
height = image.getHeight();
pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
int[] data = new int[width * height];
for (int i = 0; i < width * height; i++) {
int a = (pixels[i] & 0xff000000) >> 24;
int r = (pixels[i] & 0xff0000) >> 16;
int g = (pixels[i] & 0xff00) >> 8;
int b = (pixels[i] & 0xff);
data[i] = a << 24 | b << 16 | g << 8 | r;
}
int result = glGenTextures();
glBindTexture(GL_TEXTURE_2D, result);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, BufferUtils.createIntBuffer(data));
glBindTexture(GL_TEXTURE_2D, 0);
return result;
}
public void bind() {
glBindTexture(GL_TEXTURE_2D, texture);
}
public void unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
}
Here the Vertex Class:
public class VertexArray {
private int vao, vbo, ibo, tbo;
private int count;
public VertexArray(int count) {
this.count = count;
vao = glGenVertexArrays();
}
public VertexArray(float[] vertices, byte[] indices, float[] textureCoordinates) {
count = indices.length;
vao = glGenVertexArrays();
glBindVertexArray(vao);
vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(vertices), GL_STATIC_DRAW);
glVertexAttribPointer(Shader.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(Shader.VERTEX_ATTRIB);
tbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(textureCoordinates), GL_STATIC_DRAW);
glVertexAttribPointer(Shader.TCOORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(Shader.TCOORD_ATTRIB);
ibo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createByteBuffer(indices), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void bind() {
glBindVertexArray(vao);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
if (ibo > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
}
public void unbind() {
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
if (ibo > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void draw() {
if (ibo > 0)
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0);
else
glDrawArrays(GL_TRIANGLES, 0, count);
}
public void render() {
bind();
draw();
}
}
And here the Shaders:
Vertex:
#version 400 core
in vec4 position;
layout (location = 1) in vec2 tc;
uniform mat4 pr_matrix;
out vec2 tc_vr;
void main(void)
{
gl_Position = pr_matrix * position;
tc_vr = tc;
}
Fragment:
#version 400 core
out vec4 color;
in vec2 tc_vr;
uniform sampler2D tex;
void main(void)
{
color = texture(tex, tc_vr);
}
Thanks a lot for the help!
Had this working on OpenGL ES 1.0 & 2.0.
Goal: Make a box, then display it
Won't work with LWJGL on Win 7. Loads a green box (as it should), and then starts to display a bunch of really thick white lines that won't stay as a box. There is a lot of flickering. Here is a picture.
Here is the code for windows.
Main.java
package play.box;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
public class Main {
public static final boolean VSYNC = true;
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static final boolean FULLSCREEN = false;
protected boolean running = false;
public static void main(String[] args) {
try {
start();
} catch (LWJGLException e) {
e.printStackTrace();
}
}
public static void start() throws LWJGLException {
Display.setTitle("Display example");
Display.setResizable(false);
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.setVSyncEnabled(VSYNC);
Display.setFullscreen(FULLSCREEN);
Display.create();
// Setup OpenGL
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(-3, 3, -2, 2, -1, 1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
new Renderer().run();
}
}
Renderer.java
package play.box;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
public class Renderer implements Runnable {
public Renderer() {
}
#Override
public void run() {
while(!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
GL11.glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
// Rendering //
/*GL11.glBegin(GL11.GL_TRIANGLES);
GL11.glColor3f(1.0f, 0.0f, 0.0f);
GL11.glVertex2f(0.0f, 1.0f);
GL11.glColor3f(1.0f, 0.0f, 0.0f);
GL11.glVertex2f(1.0f, 1.0f);
GL11.glColor3f(1.0f, 0.0f, 0.0f);
GL11.glVertex2f(1.0f, -1.0f);
GL11.glEnd();*/
Box box = new Box();
box.draw();
// End of Rendering //
Display.update();
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
Box.java
package play.box;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.opengl.GL11;
public class Box {
private float verticies[] = {
-1.0f, 1.0f, // Left Top (0)
-1.0f, -1.0f, // Left Bottom (1)
1.0f, -1.0f, // Right Bottom (2)
1.0f, 1.0f // Right Top (4)
};
private short indicies[] = {
0, 1, 2,
2, 3, 0
};
private FloatBuffer vertBuff;
private ShortBuffer indexBuff;
public Box() {
this.setupBuffers();
}
private void setupBuffers() {
ByteBuffer bBuff = ByteBuffer.allocateDirect(this.verticies.length * 4);
bBuff.order(ByteOrder.nativeOrder());
this.vertBuff = bBuff.asFloatBuffer();
this.vertBuff.put(this.verticies);
this.vertBuff.position(0);
ByteBuffer pbBuff = ByteBuffer.allocateDirect(this.indicies.length * 2);
pbBuff.order(ByteOrder.nativeOrder());
this.indexBuff = pbBuff.asShortBuffer();
this.indexBuff.put(this.indicies);
this.indexBuff.position(0);
}
public void draw() {
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glVertexPointer(2, GL11.GL_FLOAT, this.vertBuff);
GL11.glDrawElements(GL11.GL_TRIANGLES, this.indexBuff);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
}
}
Updated Code:
package play.box;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Box {
private float verticies[] = {
-1.0f, 1.0f, // Left Top (0)
-1.0f, -1.0f, // Left Bottom (1)
1.0f, -1.0f, // Right Bottom (2)
1.0f, 1.0f // Right Top (4)
};
private short indicies[] = {
0, 1, 2,
2, 3, 0
};
private FloatBuffer vertBuff;
private ShortBuffer indexBuff;
private int vbo_handle;
private int ibo_handle;
private int vao_handle;
private String vShaderStr =
"attribute vec4 vPosition; \n"
+ "void main() { \n"
+ " gl_Position = vPosition;\n"
+ "} \n";
private String fShaderStr =
"precision mediump float; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
+ "} \n";
private int vertexShader;
private int fragmentShader;
private int programObject;
public Box() {
}
public void create() {
ByteBuffer bBuff = ByteBuffer.allocateDirect(this.verticies.length * 4);
bBuff.order(ByteOrder.nativeOrder());
this.vertBuff = bBuff.asFloatBuffer();
this.vertBuff.put(this.verticies);
//this.vertBuff.flip();
this.vertBuff.position(0);
ByteBuffer pbBuff = ByteBuffer.allocateDirect(this.indicies.length * 2);
pbBuff.order(ByteOrder.nativeOrder());
this.indexBuff = pbBuff.asShortBuffer();
this.indexBuff.put(this.indicies);
//this.indexBuff.flip();
this.indexBuff.position(0);
// Create VBO
this.vbo_handle = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vbo_handle);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, this.vertBuff, GL15.GL_DYNAMIC_DRAW);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
// Create IBO
this.ibo_handle = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.ibo_handle);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, this.indexBuff, GL15.GL_DYNAMIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
// Create VAO
this.vao_handle = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao_handle);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo_handle);
GL20.glEnableVertexAttribArray(0);
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ibo_handle);
GL30.glBindVertexArray(0);
// Setup Shaders
this.vertexShader = this.loadShader(GL20.GL_VERTEX_SHADER, this.vShaderStr);
this.fragmentShader = this.loadShader(GL20.GL_FRAGMENT_SHADER, this.fShaderStr);
// Setup Program
int program = GL20.glCreateProgram();
if(program == 0) {
return;
}
GL20.glAttachShader(program, this.vertexShader);
GL20.glAttachShader(program, this.fragmentShader);
GL20.glBindAttribLocation(program, 0, "vPosition");
GL20.glLinkProgram(program);
if(GL20.glGetProgrami(program, GL20.GL_LINK_STATUS) == 0) {
System.out.println("Error Creating Program: " + GL20.glGetProgramInfoLog(program, Integer.MAX_VALUE));
GL20.glDeleteProgram(program);
return;
}
this.programObject = program;
}
public void draw() {
this.create();
GL20.glUseProgram(this.programObject);
GL30.glBindVertexArray(vao_handle);
GL11.glDrawElements(GL11.GL_TRIANGLES, 2, GL11.GL_FLOAT, 0);
GL30.glBindVertexArray(0);
this.dispose();
}
public void draw(boolean useVAO) {
if(useVAO) {
this.draw();
} else {
this.create();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.vbo_handle);
GL11.glVertexPointer(2, GL11.GL_FLOAT, 0, 0L);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.ibo_handle);
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glDrawElements(GL11.GL_TRIANGLES, this.indicies.length, GL11.GL_UNSIGNED_SHORT, 0L);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
this.dispose();
}
}
public void dispose() {
GL30.glDeleteVertexArrays(vao_handle);
GL30.glDeleteVertexArrays(vbo_handle);
GL30.glDeleteVertexArrays(ibo_handle);
this.vao_handle = -1;
this.vbo_handle = -1;
this.ibo_handle = -1;
}
private int loadShader(int type, String shaderSrc) {
int shader;
shader = GL20.glCreateShader(type);
if(shader == 0) {
return 0;
}
GL20.glShaderSource(shader, shaderSrc);
GL20.glCompileShader(shader);
if(GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS) == 0) {
System.out.println("Error Loading Shader: " + GL20.glGetShaderInfoLog(shader, Integer.MAX_VALUE));
GL20.glDeleteShader(shader);
return 0;
}
return shader;
}
}
Instead of just showing you what you asked for in the comments, I will demonstrate how you create, render and dispose a VAO using a VBO and IBO.
VAO <=> Vertex Array Object
VBO <=> Vertex Buffer Object
IBO <=> Index Buffer Object
Creating VAO, VBO & IBO
The vao_handle, vbo_handle and ibo_handle is 3 integers containing the id/handle, these 3 variables are used in the whole following code.
vbo_data <=> FloatBuffer containing the vertices
ibo_data <=> IntBuffer containing the indices
The two above variables are used in the following code.
// Creating the VBO
vbo_handle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_handle);
glBufferData(GL_ARRAY_BUFFER, vbo_data, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Creating the IBO
ibo_handle = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_handle );
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo_data, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Creating the VAO
vao_handle = glGenVertexArrays();
glBindVertexArray(vao_handle);
glBindBuffer(GL_ARRAY_BUFFER, vbo_handle);
glEnableVertexAttribArray(INDEX); // Place your own INDEX value in the parenthesis
glVertexAttribPointer(INDEX, SIZE, TYPE, NORMALIZED, STRIDE, OFFSET); // Replace all the VARIABLES with the values which fit to your VAO, VBO and IBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_handle);
glBindVertexArray(0);
/*
* Remember that the INDEX given in the
* glEnableVertexAttribArray() and in
* glVertexAttribPointer() is the same
* INDEX used in Shaders (GLSL)
*
* If the INDEX is 0 then in GLSL it
* should look like this
* GLSL: layout(location = 0) in vec3 position;
*
* ^ we can ignore this if you aren't
* using Shaders, though keep it in mind
* since we might need it in the future
*/
Rendering VAO
glBindVertexArray(vao_handle);
glDrawElements(MODE, SIZE, TYPE, OFFSET); // Again replace the variables, so it fits to your VAO, VBO and IBO
glBindVertexArray(0);
Dispose VAO, VBO & IBO
This is how you delete the different buffers, which is a good thing to do, when you close the program or if at some point you don't need them anymore.
glDeleteVertexArrays(vao_handle); // Deletes the VAO
glDeleteBuffers(vbo_handle); // Deletes the VBO
glDeleteBuffers(ibo_handle); // Deletes the IBO
vao_handle = -1;
vbo_handle = -1;
ibo_handle = -1;
I am trying to write a basic Quad-renderer, using VBO, VAO, IBO and shaders.
I am trying to use mainly only one VBO, VAO, IBO and rebuffer the data when an element is added/removed.
Mostly everything worked fine, until I decided to implement textures, instead of color gradings.
It just doesn't draw anyhting, no matter what I try, because I want to avoid using deprecated functions like ClientStates and maybe use the textures inside the shaders.
Next to the problem, that nothing is being drawn, I have the problem that the Textures are saved inside the BRectangle class, and now I don't know, how to access them while using DrawElements.
And can I reuse my IBO, so I don't have to add the additional indices?
My current approach:
The Renderer, you can add a Rectangle atm and it will buffer the needed data.
public class ShaderRenderer {
public static final int POSITION_INDEX = 0; // index of vertex attribute "in_Position"
public static final int TEXTURE_INDEX = 1; // index of vertex attribute "in_Texture"
public static final int FLOAT_NUM_BYTES; // sizeof(float) in bytes
public static final int INT_NUM_BYTES; // sizeof(int) in bytes
public static final int VEC4_BYTES; // sizeof(vec4) in bytes
static {
FLOAT_NUM_BYTES = Float.SIZE / Byte.SIZE;
INT_NUM_BYTES = Integer.SIZE / Byte.SIZE;
VEC4_BYTES = 4 * FLOAT_NUM_BYTES;
}
private VAO vao = new VAO();
private VBO vbo = new VBO();
private IBO ibo = new IBO();
private int elements = 0;
public ShaderRenderer() {
try {
ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", POSITION_INDEX, TEXTURE_INDEX);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void add( BRectangle rect ) {
// Bind the VAO
// This OpenGL-object groups the "in_Position" and "in_Color"
// vertex attributes.
vao.bind();
// Bind the VBO and add the FloatBuffer from the Rect
vbo.bind();
vbo.addBuffer(rect.vertexData);
ibo.bind();
ibo.addIndices(generateIndices());
ibo.buffer();
//==============================================================
// Now we tell OpenGL that we will use POSITION_INDEX and COLOR_INDEX
// to communicate respectively the vertex positions and vertex colors
// to our shaders.
{
// First we enable the indices. This will affect the vertex
// array object from above.
glEnableVertexAttribArray(POSITION_INDEX);
Util.checkGLError();
// Then we tell OpenGL how it should read the GL_ARRAY_BUFFER
// (to which we have bound our vertex data, see above).
// The position data starts at the beginning of the vertex data
glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false,
2 * VEC4_BYTES, 0);
Util.checkGLError();
// The color data starts after the first 4 floats of position data
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false,
0, VEC4_BYTES);
Util.checkGLError();
}
vbo.bufferData();
// Just to be VERY clean, we will unbind the vertex attribute object
// and only bind it when we render. This way we cannot accidentally modify
// it anymore.
vao.unbind();
// Only after the vertex array is disabled, we unbind the buffers
// to the GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER targets, because
// otherwise the vertex array object would become invalid again.
vbo.unbind();
ibo.unbind();
}
void DestroyVBO() {
glDisableVertexAttribArray(POSITION_INDEX);
Util.checkGLError();
glDisableVertexAttribArray(TEXTURE_INDEX);
Util.checkGLError();
glBindBuffer(GL_ARRAY_BUFFER, 0);
Util.checkGLError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Util.checkGLError();
glDeleteBuffers(ibo.id);
Util.checkGLError();
glDeleteBuffers(vbo.id);
Util.checkGLError();
glBindVertexArray(0);
Util.checkGLError();
glDeleteVertexArrays(vao.id);
Util.checkGLError();
}
private int[] generateIndices() {
int c = elements * 3;
int v[] = { c, c+1, c+2,
c, c+3, c+2};
elements++;
return v;
}
public void render () {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Util.checkGLError();
vao.bind();
glDrawElements(
GL_TRIANGLES,
ibo.size,
GL_UNSIGNED_INT,
0);
Util.checkGLError();
vao.unbind();
}
}
My basic Rectangle class
public class BRectangle {
final int amountOfVertices = 8;
final int vertexSize = 3;
final int textureSize = 2;
public FloatBuffer vertexData;
Texture texture;
public BRectangle(float x, float y ) {
float[] VerticesArray = new float[]{
-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.1f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-0.1f, 0.4f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.4f, 0.0f, 1.0f, 0.0f, 1.0f
};
vertexData = BufferUtils.createFloatBuffer(24);
vertexData.put(VerticesArray);
try {
texture = Textures.loadTexture("data/floor.jpg");
} catch (IOException e) {
e.printStackTrace();
}
glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
}
}
The test with main[]
public class ShaderTest {
ShaderRenderer sr;
FpsCounter c;
public ShaderTest() {
}
public void create() throws LWJGLException, Exception {
new SimpleDisplay(800, 600, "test", false, false);
glOrtho(0, 800, 0, 600, 1, -1);
//Keyboard
Keyboard.create();
c = new FpsCounter();
Textures.setUpTextureLoader();
//Mouse
Mouse.setGrabbed(false);
Mouse.create();
sr = new ShaderRenderer();
//OpenGL
initGL();
}
public void destroy() {
Mouse.destroy();
Keyboard.destroy();
Display.destroy();
}
public void initGL() throws IOException {
ShaderUtilities.compileShader("shaders/screen.vert", "shaders/screen.frag", ShaderRenderer.POSITION_INDEX, ShaderRenderer.TEXTURE_INDEX);
sr.add(new BRectangle(0f, 0f));
}
public void processKeyboard() {
}
public void processMouse() {
}
public void render() throws LWJGLException {
sr.render();
}
public void run() throws LWJGLException {
while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
if (Display.isVisible()) {
processKeyboard();
processMouse();
update();
render();
} else {
if (Display.isDirty()) {
render();
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
Display.update();
//Display.sync(60);
}
}
public void update() {
c.updateFPS();
}
public static void main(String[] args) {
ShaderTest main = null;
try {
main = new ShaderTest();
main.create();
main.run();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (main != null) {
main.destroy();
}
}
}
}
and the openglinit
public static void initGLSlim() {
glClearColor(0, 0, 0, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL11.GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
vertex shader
#version 140
in vec4 in_Position;
in vec2 in_Texture;
out vec2 out_Texture;
void main(void)
{
gl_Position = vec4(in_Position.x *0.75 ,in_Position.y, in_Position.z, in_Position.w);
out_Texture = in_Texture;
}
fragment shader
#version 140
in vec2 out_Texture;
uniform sampler2D mytexture;
out vec4 fragColor;
void main(void)
{
fragColor = texture2D(mytexture, out_Texture);
}
Your stride parameters are not correct.
Here's what you have:
glVertexAttribPointer(POSITION_INDEX, 4, GL_FLOAT, false, 2 * VEC4_BYTES, 0);
glVertexAttribPointer(TEXTURE_INDEX, 2, GL_FLOAT, false, 0, VEC4_BYTES);
You're telling the position index that it has 8 float stride, which is not correct. As far as I can tell you're uploading 4 vertices, with 6 floats per vertex (4x position + 2x texture). That means your POSITION stride should be 6 * FLOAT_NUM_BYTES.
Your texture stride should be the same, as it's packed into the same array. Here you're telling it that the texcoords are tightly packed, but in reality theres only one pair of texcoords per 6 floats. So again you need 6 * FLOAT_NUM_BYTES here.
And can I reuse my IBO, so I don't have to add the additional indices?
Yes, you can use an IBO to draw as many objects as you want, provided that they all want the same indices.
Other less serious comments:
You don't need to clearColor to zero in initialization, it's zero by
default.
You don't need to disable depth_test/lighting in
initialization, they are off by default.
Don't call glEnable(GL_TEXTURE_2D) when you're using shaders. This
switch only enables texturing for the fixed pipeline, and it has no effect on shader programs. This will generate an error if you ever move to a core profile, so just get rid of it.