Reputation: 7
I have been using LWJGL 3 and a tutorial at LearnOpenGL.com in order to create a game engine. However, after following the tutorial, I have discovered that the use of glVertexAttribPointer
is not working. It works when uploading vertex positions and indices, but when I try to upload color and texture coordinates, nothing's happening, and I'm just getting a white box. I have attached the source code of the render engine, main class, and shaders:
public class Mesh {
public float[] vertices;
public float[] colors;
public float[] textureCoords;
public int[] indices;
public Mesh(float[] vertices, float[] colors, float[] textureCoords, int[] indices) {
this.vertices = vertices;
this.colors = colors;
this.textureCoords = textureCoords;
this.indices = indices;
}
}
public class MasterRenderer {
private int vbo;
private int vao;
private int ebo;
private Mesh mesh;
private ShaderProgram program;
public void Init(Mesh mesh) {
this.mesh = mesh;
program = new ShaderProgram();
vao = GL30.glGenVertexArrays();
vbo = GL20.glGenBuffers();
ebo = GL20.glGenBuffers();
}
public void Render(Color clearColor) {
// Clear Screen
GL11.glClearColor(clearColor.getRed(), clearColor.getGreen(), clearColor.getBlue(), clearColor.getAlpha());
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
// Bind vao
GL30.glBindVertexArray(vao);
// Bind Buffers
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.vertices, GL20.GL_STATIC_DRAW);
GL20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL20.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.indices, GL20.GL_STATIC_DRAW);
// Enable vertex attribPointers
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL20.glEnableVertexAttribArray(0);
// Handle Textures
Texture texture = Utils.LoadTexture("resources//textures//test.png");
// Uniforms
// Use Program
program.UseProgram();
// Draw the shape
GL20.glActiveTexture(GL20.GL_TEXTURE0);
GL20.glBindTexture(GL20.GL_TEXTURE_2D, texture.getId());
GL30.glBindVertexArray(vao);
GL20.glDrawElements(GL20.GL_TRIANGLES, 6, GL20.GL_UNSIGNED_INT, 0);
}
}
public class ShaderProgram {
public int programID;
public int vertexShaderID;
public int fragmentShaderID;
public ShaderProgram() {
programID = GL20.glCreateProgram();
try {
CompileVertexShader(Utils.LoadResource("resources/shaders/default/defaultShader.vs"));
CompileFragmentShader(Utils.LoadResource("resources/shaders/default/defaultShader.fs"));
GL20.glAttachShader(programID, vertexShaderID);
GL20.glAttachShader(programID, fragmentShaderID);
if(GL20.glGetShaderi(vertexShaderID, GL20.GL_COMPILE_STATUS) == 0) {
Logger.LogErrorClose("Error compiling vertex shader code: " + GL20.glGetShaderInfoLog(vertexShaderID, 1024));
}
if(GL20.glGetShaderi(fragmentShaderID, GL20.GL_COMPILE_STATUS) == 0) {
Logger.LogErrorClose("Error compiling fragment shader code: " + GL20.glGetShaderInfoLog(fragmentShaderID, 1024));
}
GL20.glLinkProgram(programID);
} catch (Exception e) {
e.printStackTrace();
}
}
public void UseProgram() {
GL20.glUseProgram(programID);
GL20.glDeleteShader(vertexShaderID);
GL20.glDeleteShader(fragmentShaderID);
}
public void CompileVertexShader(String shaderCode) {
vertexShaderID = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
GL20.glShaderSource(vertexShaderID, shaderCode);
GL20.glCompileShader(vertexShaderID);
}
public void CompileFragmentShader(String shaderCode) {
fragmentShaderID = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
GL20.glShaderSource(fragmentShaderID, shaderCode);
GL20.glCompileShader(fragmentShaderID);
}
}
public class Texture {
private int id;
public Texture(int id){
this.id = id;
}
public int getId(){
return id;
}
}
public class FoodFight {
public static void main(String[] args) {
Logger.LogMessage("Running on LWJGL Version: " + Version.getVersion());
Window w = new Window();
long window = w.CreateWindow(640, 360, "Food Fight");
MasterRenderer renderer = new MasterRenderer();
float[] vertices = {
0.5f, 0.5f, 0f,
0.5f, -0.5f, 0f,
-0.5f, -0.5f, 0f,
-0.5f, 0.5f, 0f
};
float[] colors = {
1f, 0f, 0f,
0f, 1f, 0f,
0f, 0f, 1f,
1f, 1f, 0f
};
float[] textureCoords = {
1f, 1f,
1f, 0f,
0f, 0f,
0f, 1f
};
int[] indices = {
0, 1, 3,
1, 2, 3
};
Mesh m = new Mesh(vertices, colors, textureCoords, indices);
renderer.Init(m);
while(!w.ShouldClose(window)) {
Input.ProcessInput(window);
renderer.Render(Color.black);
w.HandleWindow(window);
}
w.DestroyWindow(window);
}
}
Fragment:
#version 330 core
in vec3 color;
in vec2 texCoords;
out vec4 fragColor;
uniform sampler2D inputTexture;
void main() {
fragColor = texture(inputTexture, texCoords) * vec4(color, 1.0);
}
Vertex:
#version 330 core
in vec3 aPos;
in vec3 aColor;
in vec2 aTexCoord;
out vec3 color;
out vec2 texCoord;
void main() {
gl_Position = vec4(aPos, 1.0);
color = aColor;
texCoord = aTexCoord;
}
Upvotes: 1
Views: 975
Reputation: 211278
Since you have separate arrays for the vertex coordinates, colors and texture coordinates, you have specify separat buffers for the attributes:
vbo_ver = GL20.glGenBuffers();
vbo_col = GL20.glGenBuffers();
vbo_tex = GL20.glGenBuffers();
Creates and initializes the buffer object's data store
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_ver);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.vertices, GL20.GL_STATIC_DRAW);
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_col);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.colors, GL20.GL_STATIC_DRAW);
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_tex);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.textureCoords, GL20.GL_STATIC_DRAW);
Specify the attribute indices, in the vertex shader by layout qualifiers:
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;
glVertexAttribPointer
associates the buffer which is currently bound to the ARRAY_BUFFER
target, to the specified attribute (index), in the state vector of the currently bound Vertex Array Object. (See Vertex Specification).
Hence, the proper buffer and the VAO has to be bound before glVertexAttribPointer
.
(The ELEMENT_ARRAY_BUFFER
) is stated in the VAO, thus the VAO has to be bound before specifying the index buffer):
GL30.glBindVertexArray(vao);
GL20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, ebo);
GL20.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, mesh.indices, GL20.GL_STATIC_DRAW);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_ver);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_col);
GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0);
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo_tex);
GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, 0, 0);
Alternatively you can put the vertices and attributes to 1 array:
float[] attributes = {
// x y z r g b u v
0.5f, 0.5f, 0f, 1f, 0f, 0f, 1f, 1f,
0.5f, -0.5f, 0f, 0f, 1f, 0f, 1f, 0f,
-0.5f, -0.5f, 0f, 0f, 0f, 1f, 0f, 0f,
-0.5f, 0.5f, 0f, 1f, 1f, 0f 0f, 1f
};
vbo = GL20.glGenBuffers();
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo);
GL20.glBufferData(GL20.GL_ARRAY_BUFFER, mesh.attributes, GL20.GL_STATIC_DRAW);
The stride and the offset have to be specified in bates:
GL20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vbo);
int stride = 8 * 4; // the tuple size is 8 (x y z r g b u v), sizeof float is 4
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, stride, 0);
GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, stride, 3*4);
GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, stride, 6*4);
Upvotes: 1