(Obligatory this is not a homework assignment for a class). I am currently working with LWJGL and the obstacle I face right now on my project is rendering textures to a cube, e.x a set of 8 vertices with position, color, and UV information. Here, I start off with a single 2D face however it's not exactly correctly rendered. I believe I am close but after playing around with it a bunch I'm not sure how to manipulate the information in a way that resembles a full, correctly oriented texture. Allow me to show you what I have so far:
This is the 16x16 texture (scaled to 256x256 so its visible in this post) I am trying to render, red lines for debugging purposes. The diagonal separates the 2 triangles that make up the GL_TRIANGLE_STRIP my code is trying to draw:
This is how my code displays it right now:
You can see that it almost looks right, but not quite. This leads me to believe it may be an issue with ordering of vertices or elements.
Here is my code that is responsible for displaying that texture:
private void renderMenu() {
// Define the vertices and colors of the cube
float[] vertices = {
//Position Color Texture
// Front face
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1, 1,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0, 0,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 1, 0,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0, 1};
int[] elementArray = {
2, 1, 0,
0, 1, 3
};
//Loading texture image
String path = "src/main/resources/textures/test_texture16.png";
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer height = BufferUtils.createIntBuffer(1);
IntBuffer channels = BufferUtils.createIntBuffer(1);
ByteBuffer image = stbi_load(path, width, height, channels, 0);
//Binding texture ID
int texId = glGenTextures();
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenerateMipmap(GL_TEXTURE_2D);
if (image != null) {
//Loads image to GPU
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width.get(0), height.get(0),
0, GL_RGBA, GL_UNSIGNED_BYTE, image);
//Frees memory containing image
stbi_image_free(image);
} else {
logger.warning("Texture could not be loaded from " + path);
}
/*==================================
Buffer binding and loading
====================================*/
// Create VAO
int vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
// Create a float buffer of vertices
FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(vertices.length);
vertexBuffer.put(vertices).flip();
// Create VBO upload the vertex buffer
int vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);
// Create the indices and upload
IntBuffer elementBuffer = BufferUtils.createIntBuffer(elementArray.length);
elementBuffer.put(elementArray).flip();
// Create EBO upload the element buffer
int eboID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementBuffer, GL_STATIC_DRAW);
// Bind the VAO that we're using
glBindVertexArray(vaoID);
/*=====================================
Vertex attribute definitions for shader
======================================*/
int posSize = 3;
int colorSize = 4;
int uvSize = 2;
int floatSizeBytes = 4;
int vertexSizeBytes = (posSize + colorSize) * floatSizeBytes;
//Position
glVertexAttribPointer(0, posSize, GL_FLOAT, false, vertexSizeBytes, 0);
glEnableVertexAttribArray(0);
//Color
glVertexAttribPointer(1, colorSize, GL_FLOAT, false, vertexSizeBytes, posSize * Float.BYTES);
glEnableVertexAttribArray(1);
//Texture
glVertexAttribPointer(2, uvSize, GL_FLOAT, false, vertexSizeBytes, (posSize + colorSize) * Float.BYTES);
glEnableVertexAttribArray(2);
/*==================================
View Matrix setup
====================================*/
// Set up the model-view matrix for rotation
modelViewMatrix = new Matrix4f();
modelViewMatrix.translate(new Vector3f(0.0f, 0.0f, -2.0f));
modelViewMatrix.rotate(angle, new Vector3f(0.0f, 1.0f, 0.0f));
// Set up the model-view-projection matrix
Matrix4f modelViewProjectionMatrix = new Matrix4f(projectionMatrix).mul(modelViewMatrix);
// Pass the model-view-projection matrix to the shader as a uniform
int mvpMatrixLocation = glGetUniformLocation(shaderProgram.getProgramId(), "modelViewProjectionMatrix");
glUniformMatrix4fv(mvpMatrixLocation, false, modelViewProjectionMatrix.get(new float[16]));
// Enable the vertex attribute pointers
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
/*==================================
Drawing
====================================*/
glDrawElements(GL_TRIANGLE_STRIP, elementArray.length, GL_UNSIGNED_INT, 0);
//Unbind everything
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
Vertex Shader:
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 aColor;
layout (location = 2) in vec2 aTexCoords;
uniform mat4 modelViewProjectionMatrix;
out vec4 fColor;
out vec2 fTexCoords;
void main() {
gl_Position = modelViewProjectionMatrix * vec4(position, 1.0);
fColor = aColor;
fTexCoords = aTexCoords;
}
The problem ended up being my stride. I was excluding my texture coordinates.
This: int vertexSizeBytes = (posSize + colorSize) * floatSizeBytes;
Should have been this:
int vertexSizeBytes = (posSize + colorSize + uvSize) * floatSizeBytes;