LWJGL中OpenGL 2D纹理渲染至4顶点的问题排查
LWJGL纹理渲染错误排查与修复
当前使用LWJGL开发项目,为包含位置、颜色、UV信息的8个顶点立方体渲染纹理时,单个2D面的纹理朝向始终不正确,怀疑问题出在顶点或元素顺序上,相关情况如下:
需要渲染的16x16纹理(已缩放至256x256,红色调试线分隔构成GL_TRIANGLE_STRIP的两个三角形):
当前渲染效果:
负责渲染的核心代码
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); }
顶点着色器代码
#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; }
问题排查与修复方案
1. 顶点步长计算错误
原代码计算vertexSizeBytes时,仅包含了位置(3个float)和颜色(4个float)的字节数,漏掉了UV坐标(2个float),导致UV属性读取偏移错误。修正为:
int vertexSizeBytes = (posSize + colorSize + uvSize) * floatSizeBytes;
2. 绘制模式与元素数组不匹配
使用GL_TRIANGLE_STRIP绘制时,元素数组不需要6个索引(对应2个独立三角形),4个索引即可绘制完整四边形。两种修正方式:
- 调整元素数组为
GL_TRIANGLE_STRIP适配格式:int[] elementArray = { 0, 1, 2, 3 }; - 保持元素数组不变,将绘制模式改为
GL_TRIANGLES:glDrawElements(GL_TRIANGLES, elementArray.length, GL_UNSIGNED_INT, 0);
3. UV坐标与顶点位置对应关系错误
OpenGL纹理原点在左下角,原UV坐标与顶点位置的对应关系颠倒,导致纹理朝向错误。调整后的顶点UV部分:
float[] vertices = { //Position Color Texture // 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, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // 左上 → 纹理左上 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f // 右上 → 纹理右上 };
4. 纹理加载顺序错误
glGenerateMipmap需在glTexImage2D之后调用,否则mipmap生成无效。修正后的纹理加载部分:
if (image != null) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width.get(0), height.get(0), 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); // 移至glTexImage2D之后 stbi_image_free(image); }
同时,强制加载RGBA格式避免通道不匹配:
ByteBuffer image = stbi_load(path, width, height, channels, 4);
5. 冗余代码与属性启用遗漏
- 去掉多余的
glEnable(GL_TEXTURE1),未使用纹理单元1无需启用; - 绘制前需启用UV的顶点属性数组,补充:
glEnableVertexAttribArray(2);
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

