Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How do I properly render a quad in OpenGL using a GL_TRIANGLE_STRIP primitive?
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. For now, I am starting off simple 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 code 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:
But this is how my code displays it right now:
But after a lot of tweaking and guessing as to what could be the issue, I am just not sure. As far as I can tell at least, the code looks right:
private void renderMenu() {
// Define the vertices and colors of the cube
//TODO: Figure out how tf to render a cube with GL_TRIANGLE_STRIP preferably
float[] vertices = {
//Position (X, Y, Z) Color (R, G, B, A) Texture (U, V)
// Front face
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
};
// Declares the Elements Array, where the indices to be drawn are stored
int[] elementArray = {
// Front face
0, 1, 2, 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();
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(180, 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;
}
Drawing a picture helped me to visualize it, but it did not spark any "ah ha" moments like I had hoped:
1 answer
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
cuzzo | (no comment) | Oct 1, 2023 at 14:30 |
It looks like your vertexSizeBytes
stride variable doesn't include uvSize
.
To figure things like this out, use this kind of logic:
The shape of the image isn't a square, so something is wrong with the position coordinates. Possible problems: bad offset, bad stride, bad size, bad order of values (e.g. transposed matrix of values). The offset and size look fine, but the stride doesn't.
If that hadn't found the issue, I would have modified entries in vertices
one at a time to see the effect on the output.
0 comment threads