I'm trying to implement flat shading for non-planar polygons (using a single normal vector per polygon) based on buffer textures, but I can't seem to figure out how to set up things correctly. The approach is as follows —
I render n-gons using
GL_TRIANGLE_FAN
. Everything is stored index-based, so I useglDrawElements()
. To know where one n-gon ends and the next one starts, I use the primitive restart approach.In the fragment shader, one has access to
gl_PrimitiveID
. In the rendering process, each n-gon is split into(n-2)
triangles, each triangle has a uniquegl_PrimitiveID
.Each triangle can be linked back to its original n-gon as follows. Let's consider a mesh consisting of a pentagon, a triangle and a quad (in that order). The data stored in the first buffer texture is
0,0,0,1,2,2
. The pentagon (index0
) is rendered as three triangles, the triangle (index1
) is of course rendered as a single triangle, and the quad (index2
) is rendered as two triangles. Usinggl_PrimitiveID
, the n-gon index can be obtained.Finally, there is a second buffer texture which contains one normal vector per original n-gon. The indices in the other buffer texture (i.e.,
0
,1
and2
in the example) can be used to obtain the right normal vectors for each triangle.
Ok, to create the buffer textures, I use
GLuint faceIndexBuffer, faceIndexTexture, faceNormalBuffer, faceNormalTexture;
glGenBuffers(1, &faceIndexBuffer);
glBindBuffer(GL_TEXTURE_BUFFER, faceIndexBuffer);
glBufferData(GL_TEXTURE_BUFFER, sizeof(unsigned int)*FaceIDs.size(), FaceIDs.data(), GL_DYNAMIC_DRAW);
glGenTextures(1, &faceIndexTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, faceIndexTexture);
// Unsigned integers (uint)
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, faceIndexBuffer);
glGenBuffers(1, &faceNormalBuffer);
glBindBuffer(GL_TEXTURE_BUFFER, faceNormalBuffer);
glBufferData(GL_TEXTURE_BUFFER, sizeof(QVector3D)*FaceNorms.size(), FaceNorms.data(), GL_DYNAMIC_DRAW);
glGenTextures(1, &faceNormalTexture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_BUFFER, faceNormalTexture);
// RGB floats (vec3)
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, faceNormalBuffer);
where
QVector<unsigned int> FaceIDs;
QVector<QVector3D> FaceNorms;
Neither FaceIDs
nor FaceNorms
contains any data when the above code is run. To update the actual data, I use
glBindBuffer(GL_TEXTURE_BUFFER, faceIndexBuffer);
glBufferData(GL_TEXTURE_BUFFER, sizeof(unsigned int)*FaceIDs.size(), FaceIDs.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_TEXTURE_BUFFER, faceNormalBuffer);
glBufferData(GL_TEXTURE_BUFFER, sizeof(QVector3D)*FaceNorms.size(), FaceNorms.data(), GL_DYNAMIC_DRAW);
The other data (vertex information, i.e. coordinates and normals, and indices) are stored as VBOs and IBOs, wrapped in a VAO.
Relevant part of the fragment shader —
layout(binding = 0) uniform samplerBuffer primIdToFaceId;
layout(binding = 1) uniform samplerBuffer faceNormals;
int faceIndex = int(texelFetch(primIdToFaceId, gl_PrimitiveID).x);
vec3 norm = texelFetch(faceNormals, faceIndex).xyz;
Note that I use bindings in the shader, so I shouldn't have to use e.g.
uFaceIDs = glGetUniformLocation(ShaderProg->programId(), "primIdToFaceId");
glUniform1i(uFaceIDs, 0);
uFaceNorms = glGetUniformLocation(ShaderProg->programId(), "faceNormals");
glUniform1i(uFaceNorms, 1);
Unfortunately, something is apparently not set up in the correct way, because I don't obtain the right normals. This is the relevant logging information (Buffer 4 corresponds to the first TBO containing indices, Buffer 5 to the second one, containing normals) —
→ Log: QOpenGLDebugMessage("APISource", 131185, "Buffer detailed info: Buffer object 4 (bound to GL_TEXTURE_BUFFER, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.", "NotificationSeverity", "OtherType")
→ Log: QOpenGLDebugMessage("APISource", 131185, "Buffer detailed info: Buffer object 5 (bound to GL_TEXTURE_BUFFER, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations.", "NotificationSeverity", "OtherType")
when creating/updating data, and
→ Log: QOpenGLDebugMessage("APISource", 131185, "Buffer detailed info: Buffer object 4 (bound to NONE, usage hint is GL_DYNAMIC_DRAW) will use VIDEO memory as the source for buffer object operations.", "NotificationSeverity", "OtherType")
when rendering. This last line here indicates what might be wrong, the first TBO is not bound anymore? What am I overlooking?