I am trying to learn how to use LWJGL3 and I just got to a state where I want to render something (a test quad for now). I have a class that represents a mesh where I set up the VAO with vertex, colour and indices buffers and another object later takes the mesh instance, retrieves its VAO ID and attempts to render it.
The problem I have is that no matter what I try, nothing renders in the window. I can change the background colour through the glClearColor() method but the quad never shows up.
The VAO set up:
vertexCount = indices.length;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//Vertices
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(positions.length);
verticesBuffer.put(positions).flip();
vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4, 0);
//Colours
FloatBuffer colorsBuffer = BufferUtils.createFloatBuffer(colors.length);
colorsBuffer.put(colors).flip();
colVboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, colVboID);
glBufferData(GL_ARRAY_BUFFER, colorsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 3 * 4, 0);
//Indices
IntBuffer indicesBuffer = BufferUtils.createIntBuffer(indices.length);
indicesBuffer.put(indices).flip();
idxVboID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxVboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
//Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
The rendering code:
//Bind the shader
shaderProgram.bind();
//Bind the VAO
glBindVertexArray(mesh.getVaoID());
//Draw
glDrawElements(GL_TRIANGLES, mesh.getVertexCount(), GL_UNSIGNED_INT, 0);
//Restore
glBindVertexArray(0);
shaderProgram.unbind();
Vertex shader:
#version 330
layout (location=0) in vec3 pos;
layout (location=1) in vec3 inColor;
out vec3 exColor;
void main()
{
gl_Position = vec4(pos, 1.0);
exColor = inColor;
}
Fragment shader:
#version 330
in vec3 exColor;
out vec4 fragColor;
void main()
{
fragColor = vec4(exColor, 1.0);
}
What am I doing wrong?
The problem was not in the parts of code shown, but in the main loop that I copied from a book without thoroughly thinking through what it did. I ended up with a glClear call right before glfwSwapBuffers call, which cleared the buffer right before showing it.
Lesson of the day: don't just copy from a book, think thoroughly about what you're doing
(Thank you to the people of LWJGL formus for helping me discover this mistake)
Related
I am trying to render a model by importing the .obj File. Im successfully importing and preparing the data to be rendered in FloatBuffers/IntegerBuffers but cant manage to render it. Can someone help me?
This is the class that renders and initializes the VBOs
private int vertexBufferID;
private int indexBufferID;
private int numberIndices;
public void init() {
try{
InputStream objInputStream = new FileInputStream("./res/obj/Terrain.obj");
Obj obj = ObjReader.read(objInputStream);
obj = ObjUtils.convertToRenderable(obj);
IntBuffer indices = ObjData.getFaceVertexIndices(obj, 3);
FloatBuffer vertices = ObjData.getVertices(obj);
// FloatBuffer texCoords = ObjData.getTexCoords(obj, 2);
// FloatBuffer normals = ObjData.getNormals(obj);
vertexBufferID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBufferID);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
indexBufferID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
}catch(IOException e)
{
e.printStackTrace();
}
}
public void render() {
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBufferID);
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
GL11.glDrawElements(GL11.GL_TRIANGLES, numberIndices, GL11.GL_UNSIGNED_INT, 0);
}
I get no error code the object is just not rendered. I am able to render the Object using Display Lists.
I've now solved the problem and am now able to import .obj-Files and render them using vbo/vao. Im using "Obj - a simple Wavefront OBJ file loader and writer" to prepare the data to be rendered.
The code to load up and prepare the .obj file
InputStream objInputStream = new FileInputStream(pathTObjFile);
Obj obj = ObjReader.read(objInputStream);
obj = ObjUtils.convertToRenderable(obj);
IntBuffer indices = ObjData.getFaceVertexIndices(obj, 3);
FloatBuffer vertices = ObjData.getVertices(obj);
Now the data is stored in 2 VBOs and the VBO for the vertices is stored in a VAO:
vaoId = GL30.glGenVertexArrays();
The Vertex Array Object ID (vaoID) is an Integer that is called if we are calling the VAO.
GL30.glBindVertexArray(vaoId);
To be able to do anything with the VAO we have to bind or "select" it.
vboId = GL15.glGenBuffers();
The VBOs also have an ID to be called with. We are creating the Vertex Buffer Object ID here (vboId)
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
Now we select the VBO and store the vertices in it.
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
First we put the VBO in the first attribute list of the VAO (a VAO has 16 lists), then we unbind the VAO and the VBO.
vboiId = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboiId);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
indicesCount = indices.capacity();
At the end of the Initialization we have create the vbo for the indices so the Vertices can be connected to each others to create faces in the right way. Therefor we bind the vboiId and store the index data inside. Then we unbind the VBO again and save the number of Indices stored in the VBO because we have to tell it OpenGL to be able to render it later.
Rendering the Object:
GL30.glBindVertexArray(vaoId);
GL20.glEnableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboiId);
To Render the Object we have to bind the VAO and the VBO inside. We also have to select the VBO for the Indices. That is done by the code snippet above.
GL11.glDrawElements(GL11.GL_TRIANGLES, indicesCount, GL11.GL_UNSIGNED_INT, 0);
Now we draw the Object and
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
Deselect the VBOs and VAOs again.
Here is the whole code combined
private int vboiId;
private int vaoId;
private int vboId;
private int indicesCount;
public void init() {
try{
InputStream objInputStream =
new FileInputStream("./res/obj/Terrain.obj");
Obj obj = ObjReader.read(objInputStream);
obj = ObjUtils.convertToRenderable(obj);
IntBuffer indices = ObjData.getFaceVertexIndices(obj, 3);
FloatBuffer vertices = ObjData.getVertices(obj);
FloatBuffer texCoords = ObjData.getTexCoords(obj, 2);
FloatBuffer normals = ObjData.getNormals(obj);
indicesCount = indices.capacity();
vaoId = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoId);
vboId = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
vboiId = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboiId);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
}catch(IOException e)
{
e.printStackTrace();
}
}
public void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL30.glBindVertexArray(vaoId);
GL20.glEnableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboiId);
GL11.glDrawElements(GL11.GL_TRIANGLES, indicesCount, GL11.GL_UNSIGNED_INT, 0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
For further and more detailed information i strongly recommend u to read The quad with Draw Array, The Quad with Draw Elements and if you want to go more in detail look up the OpenGL 3.2 and above tutorials on the Main Page of the LWJGL Wiki.
For information on how to use the Obj loader I used look up The sample projects using this loader
My code basically consists of a mixture of the code on this websites.
Edit: If you try to render multiple Objects you have to Clear the Color before rendering the first object (First line of the Render method)
I've recently started using OpenGL and LWJGL but ever since I tried to mess with/add vertex array objects, I've been getting the same error over and over:
GL_INVALID_OPERATION
I am having a hard time understanding why but I managed to pin down to problem to these methods:
glEnableClientState(GL_VERTEX_ARRAY);
vao = glGenVertexArrays();
glBindVertexArray(vao);
glEnableVertexAttribArray(vao);
glVertexAttribPointer(0, count, GL_FLOAT, false, Float.SIZE * 2, 0);
glBindVertexArray(0);
...so basically anything that has to do with vertex arrays throws this error. If anyone could point out what exactly I am doing wrong, that would be great. This is the rest of my code:
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
public class Model {
private int count;
private int ibo, vao;
public Model(float[] vertices, int[] indices) {
count = indices.length;
glEnableClientState(GL_VERTEX_ARRAY);
vao = glGenVertexArrays();
glBindVertexArray(vao);
glEnableVertexAttribArray(vao);
glVertexAttribPointer(0, count, GL_FLOAT, false, Float.SIZE * 2, 0);
glBindVertexArray(0);
FloatBuffer vBuffer = BufferUtils.createFloatBuffer(vertices.length);
vBuffer.put(vertices).flip();
int vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vBuffer, GL_STATIC_DRAW);
IntBuffer iBuffer = BufferUtils.createIntBuffer(indices.length);
iBuffer.put(indices).flip();
ibo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
public void draw() {
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0);
}
}
The parameter of glEnableVertexAttribArray is the attibute index. This means you have to change your code like this:
glBindVertexArray( vao );
glEnableVertexAttribArray( 0 ); // <--- attribute index instead of object name
Or you may use glEnableVertexArrayAttrib:
glEnableVertexArrayAttrib( vao, 0 );
OpenGL 4.6 core profile specification, 10.3. VERTEX ARRAYS, page 354:
An individual generic vertex attribute array in a vertex array object is enabled with the commands
void EnableVertexAttribArray( uint index );
void EnableVertexArrayAttrib( uint vaobj, uint index );
Note, glEnableClientState is part of the deprecated fixed function pipeline. If you want to use the fixed function pipeline and glEnableClientState, then you have to use glVertexPointer instead of glVertexAttribPointer.
I'm using LWJGL to draw "tiles", or textured 2D squares on the screen. However, the texture coordinate is always (0, 0) and therefore the textured square only uses the first pixel colour to fill it.
This is my vertex shader:
#version 330 core
in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;
out vec4 pass_Color;
out vec2 pass_TextureCoord;
void main(void) {
gl_Position = in_Position;
pass_Color = in_Color;
pass_TextureCoord = in_TextureCoord;
}
And this is my fragment shader:
#version 330 core
uniform sampler2D texture_diffuse;
in vec4 pass_Color;
in vec2 pass_TextureCoord;
out vec4 out_Color;
void main(void) {
out_Color = pass_Color;
// Override out_Color with our texture pixel
out_Color = texture(texture_diffuse, pass_TextureCoord);
}
And this is essentially the code I'm using to draw the square:
ARBShaderObjects.glUseProgramObjectARB(shaderProgram);
glBindTexture(GL_TEXTURE_2D, sprite.getId());
glBegin(GL11.GL_QUADS);
glVertex2d(screenMinX, screenMinY);
glTexCoord2d(0.0, 0.0);
glVertex2d(screenMaxX, screenMinY);
glTexCoord2d(1.0, 0.0);
glVertex2d(screenMaxX, screenMaxY);
glTexCoord2d(1.0, 1.0);
glVertex2d(screenMinX, screenMaxY);
glTexCoord2d(0.0, 1.0);
glEnd();
// release the shader
ARBShaderObjects.glUseProgramObjectARB(0);
I cannot fix it because I don't know how the above code works in the first place. I have not told the shaders what in_Position, in_Color or in_TextureCoord are but the first two seem to work just fine. It is in_TextureCoord, which is eventually passed to the fragment shader, that seems to have a constant value of (0, 0) - I have determined that by setting the output colour of the fragment shader to have one of the channels equal to the X-coordinate of the texture coordinate. It remained a solid colour throughout the square, indicating that there was no change in texture coordinate.
The square produced with the code above should be textured but instead is painted a solid colour - the first pixel of the texture given. How can I change the code to make the texture coordinate change accordingly? If I appear to have some misunderstanding to how this all fits together, please correct me.
This is the tutorial I used to try to accomplish the above.
p.s. I am aware that the Java snippet is using deprecated immediate-mode, but I don't know how to use glDrawArrays or any other commonly suggested method to accomplish the same. Could you help me to change this?
I am aware that the Java snippet is using deprecated immediate-mode, but I don't know how to use glDrawArrays or any other commonly suggested method to accomplish the same. Could you help me to change this?
Since you do not need the attribute in_Color anymore, you have to delete the attribute from the vertex shader (and of course also pass_Color from the vertex shader and the fragment shader).
Otherwise, you have to expand my solution logically by the color attribute.
Set up an array for the vertex positions an for the texture coordinates:
float[] posData = {
screenMinX, screenMinY, 0.0, 1.0,
screenMaxX, screenMinY, 0.0, 1.0,
screenMaxX, screenMaxY, 0.0, 1.0,
screenMinX, screenMaxY, 0.0, 1.0 };
float[] texData = { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 };
Generate a vertex array object:
int vaoObj = glGenVertexArrays();
glBindVertexArray(vaoObj);
Generate array buffers for the vertices and texture coordinates, enable the attribute indices and associate them buffers to the attribute indices:
FloatBuffer posBuffer = MemoryUtil.memAllocFloat(posData.length);
posBuffer.put(posData).flip();
FloatBuffer texBuffer = MemoryUtil.memAllocFloat(texData.length);
texBuffer.put(texData).flip();
int vboPosObj = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboPosObj);
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
// index 0 to associate with "in_Position"
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0); // 0 = attribute index of "in_Position"
int vboTexObj = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTexObj);
glBufferData(GL_ARRAY_BUFFER, texBuffer, GL_STATIC_DRAW);
// index 0 to associate with "in_TextureCoord"
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(1); // 1 = attribute index of "in_TextureCoord"
Release the vertex array object:
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
You have to specify the attribute indices of the attributes in_Position and in_TextureCoord.
Either you use explicit layout specifications in the vertex shader:
layout (location = 0) in vec4 in_Position;
layout (location = 1) in vec2 in_TextureCoord;
Or you specify the attribute indices in the shader program, right before you link the shader program (glLinkProgram).
glBindAttribLocation(shaderProgramID, 0, "in_Position");
glBindAttribLocation(shaderProgramID, 1, "in_TextureCoord");
If the object is to be drawn, it is sufficient to bind the Vertex Array Object:
glBindVertexArray(vaoObj);
glDrawArrays(GL_QUADS, 0, 4); // 4 = number of vertices
glBindVertexArray(0);
Note, if a buffer objects or a vertex array object is not further used, it has to be deleted, to prevent memory leaks. Buffer objects are deleted by glDeleteBuffers and vertex array objects are deleted by glDeleteVertexArrays.
Buffer objects are not "created under" vertex array objects, it is not sufficient to delete the vertex array object only (see OpenGL Vertex Array/Buffer Objects)
If you use need to use box to show some texture image that will be fit the full box area you can use two triangles for it and following parameters for -1,-1 to 1,1 area (that can be used with appropriate shaders to show).
Vertex (two triangles coordinates):
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f
Then use can use following texture coordinates for full size:
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
I am trying to use VAOs to render and am having trouble with incorrect rendering.
I do have a little experience in the subject but not a huge amount.
This is my binding Code:
//RawModel is just a type to store vao id and number of indices.
public RawModel loadToVao(float[] positions, int[] indices){
//create VAO and bind it
int vaoID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoID);
//create index buffer
int indexVBO = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexVBO);
IntBuffer indexBuffer = BufferUtils.createIntBuffer(indices.length);
indexBuffer.put(indices);
indexBuffer.flip();
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer , GL15.GL_STATIC_DRAW);
//create vertex buffer
int positionVBO = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, positionVBO);
FloatBuffer vertBuffer = BufferUtils.createFloatBuffer(positions.length);
vertBuffer.put(positions);
vertBuffer.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertBuffer , GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
return new RawModel(vaoID, indices.length);
}
This is my render code:
GL30.glBindVertexArray(obj.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_POINTS, 0, sphere.getRawModel().getSize());
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, sphere.getRawModel().getSize());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
I render both points and Triangles just to see what is going wrong. eventually will only be triangles.
This code always seems to give me a point at the objects centre which should not be there. It also has incorrect grouping of elements so triangles render completely wrong.
If anyone could help it would be great.
Thanks
I'm trying to learn GLSL and I'm wanting to send a float attribute to my vertex shader. For now, this float is to be used simply to set the brightness (I mulitply in_Color by in_Light and assign it to out_Color). The brightness always seems to equal 1.0 in the vertex shader regardless of what I try to pass (0.1 in the code below). I've tried googling and I've tried experimenting quite a bit but I just don't get what's wrong. Position, texture coordinates and color seem to work fine.
Here is how I'm binding the attribute locations, and a bit more of the code.
this.vsId = Shader.loadShader(pVertexFilePath, GL20.GL_VERTEX_SHADER);
this.fsId = Shader.loadShader(pFragmentFilePath, GL20.GL_FRAGMENT_SHADER);
this.pId = GL20.glCreateProgram();
GL20.glAttachShader(this.pId, this.vsId);
GL20.glAttachShader(this.pId, this.fsId);
GL20.glBindAttribLocation(this.pId, 0, "in_Position");
GL20.glBindAttribLocation(this.pId, 1, "in_TextureCoord");
GL20.glBindAttribLocation(this.pId, 2, "in_Color");
GL20.glBindAttribLocation(this.pId, 3, "in_Light");
GL20.glLinkProgram(this.pId);
this.normalMatrixId = GL20.glGetUniformLocation(this.pId, "normalMatrix");
this.projectionModelViewMatrixId = GL20.glGetUniformLocation(this.pId, "projModelViewMatrix");
This is how I'm setting the position of each attribute
FloatBuffer verticesFloatBuffer = BufferUtils.createFloatBuffer(verticesCount * 36);
for (VertexData vert : vertices) {verticesFloatBuffer.put(vert.getElements());}
vertices.clear();
verticesFloatBuffer.flip();
GL30.glBindVertexArray(vaoId);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesFloatBuffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 36, 0);
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, 36, 12);
GL20.glVertexAttribPointer(2, 3, GL11.GL_FLOAT, false, 36, 20);
GL20.glVertexAttribPointer(3, 1, GL11.GL_FLOAT, false, 36, 32);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
This is the getElements method used above (I have manually input color and brightness for testing purposes). Note that the last value which should be in_Light is 0.1f and always turns out to be 1.f in the vertex shader.
public float[] getElements() {
return new float[]{this.x, this.y, this.z, this.s, this.t, 1.f, 0.f, 1.f, 0.1f};
}
Vertex Shader:
#version 430 core
uniform mat4 projModelViewMatrix;
uniform mat3 normalMatrix;
in vec3 in_Position;
in vec2 in_TextureCoord;
in vec3 in_Color;
in float in_Light;
out vec4 pass_Color;
out vec2 pass_TextureCoord;
void main(void) {
gl_Position = projModelViewMatrix * vec4(in_Position, 1.0);
pass_TextureCoord = in_TextureCoord;
pass_Color = vec4(in_Color * in_Light, 1.0);
}
Fragment Shader (just in case someone wants to see it):
#version 430 core
uniform sampler2D texture_diffuse;
in vec4 pass_Color;
in vec2 pass_TextureCoord;
out vec4 out_Color;
void main(void) {
out_Color = texture2D(texture_diffuse, pass_TextureCoord) * pass_Color;
}
All other attributes that I pass to the vertex shader work fine.
EDIT:
Just as a note, I've tried changing the shader to specify locations, eg:
layout (location = 0) in vec3 in_Position;
I've also used glGetAttributeLocation which gives me the same attribute locations (0, 1, 2, 3), eg:
GL20.glGetAttribLocation(this.pId, "in_Position");
I've also added an if statement to the shader to check the value of in_Light and it always equals one.
EDIT2:
Now I've changed the color attribute to a vec4 and passed the light value in place of the alpha which works fine. Based on other trials, as well as this, it's almost as if I can't have more than 3 attributes for some reason.
GL20.glLinkProgram(this.pId);
GL20.glBindAttribLocation(this.pId, 0, "in_Position");
GL20.glBindAttribLocation(this.pId, 1, "in_TextureCoord");
GL20.glBindAttribLocation(this.pId, 2, "in_Color");
GL20.glBindAttribLocation(this.pId, 3, "in_Light");
The glBindAttribLocation call needs to come before you link the program. Attribute locations are fixed at link time, so if you didn't bind any, OpenGL will arbitrarily assign them locations.
Yup, simple noob mistake in addition to the one Nicol Bolas mentioned. (wonder how many more I have ;)
I needed to add glEnableVertexAttribArray before setting the position of each attribute with glVertexAttribPointer. Seems like the first three attributes are automatically enabled, though I imagine this could change on a per GPU basis?
FloatBuffer verticesFloatBuffer = BufferUtils.createFloatBuffer(verticesCount * 36);
for (VertexData vert : vertices) {verticesFloatBuffer.put(vert.getElements());}
vertices.clear();
verticesFloatBuffer.flip();
GL30.glBindVertexArray(vaoId);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesFloatBuffer, GL15.GL_STATIC_DRAW);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
GL20.glEnableVertexAttribArray(3);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 36, 0);
GL20.glVertexAttribPointer(1, 2, GL11.GL_FLOAT, false, 36, 12);
GL20.glVertexAttribPointer(2, 3, GL11.GL_FLOAT, false, 36, 20);
GL20.glVertexAttribPointer(3, 1, GL11.GL_FLOAT, false, 36, 32);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
Thanks to everyone that replied!