# How to best deal with colors and normals

Hello,

I have multiple mesh files that use indexed elements into a vertex buffer for rendering. The problem that I have encountered with this, is that my normal vectors and color values are defined by per-primitive. Likewise for the normal vectors, I can’t easily just store a normal per “shared” vertex using this method. So, in light of this, I have been thinking of using a geometry shader to calculate the normal vectors, as well use a TBO to hold my per primitive colors for calculation of the lighting.

Is this the best method to approach this? Would it be better to use two TBO’s one for color and one for normals inside of the vertex shader and use gl_VertexID/3 as an index into these TBO’s? What is the most efficient way to access the TBO’s, textCoord or some other method.

Thanks,

James

The most efficient solution is to use [var]flat[/var]-qualified vertex shader outputs, so each triangle takes the colour and normal from one of the vertices (by default, the last vertex). That way, you only need (roughly) as many vertices as triangles (rather than 3 vertices per triangle). But constructing the topology is fairly complex if you want to minimise the number of vertices (finding an optimal solution is an exact cover problem, which is NP-complete).

Otherwise, unless memory is particularly tight, I’d just use vertex attributes (you don’t need 3 floats for the normal; for lighting, a 16-bit value is perfectly adequate).

Note that you can calculate the face normal in the fragment shader using N=cross(dFdx§,dFdy§), where p is the fragment position in any affine space (object space, world space or eye space, but not NDC). The normal will be in the same space.

Geometry shaders tend to be expensive because they eliminate vertex sharing. But that isn’t an issue if you aren’t sharing any vertices in the first place.

[QUOTE=GClements;1291985]The most efficient solution is to use [var]flat[/var]-qualified vertex shader outputs, so each triangle takes the colour and normal from one of the vertices (by default, the last vertex). That way, you only need (roughly) as many vertices as triangles (rather than 3 vertices per triangle). But constructing the topology is fairly complex if you want to minimise the number of vertices (finding an optimal solution is an exact cover problem, which is NP-complete).

Otherwise, unless memory is particularly tight, I’d just use vertex attributes (you don’t need 3 floats for the normal; for lighting, a 16-bit value is perfectly adequate).

Note that you can calculate the face normal in the fragment shader using N=cross(dFdx§,dFdy§), where p is the fragment position in any affine space (object space, world space or eye space, but not NDC). The normal will be in the same space.

Geometry shaders tend to be expensive because they eliminate vertex sharing. But that isn’t an issue if you aren’t sharing any vertices in the first place.[/QUOTE]

Is there a large performance penalty for using a TBO in the vertex shader and using the gl_VertexID/3 as a per triangle color/normal access modifier? Of course we can compute the normal in the fragment shader, it was my understanding that it is more expensive to do that because this is calculated on every pixel of a particular resolution. Our memory is tight and we are trying to find ways to lower the amount of memory usage, hence the use of element array for accessing the vertexs that can be shared amount different triangles in the mesh.

There’s a penalty, but whether it’s “large” is subjective. The main reason for preferring attributes over texture fetches is that attribute data can be efficiently streamed by the hardware, i.e. the attribute values are loaded into dedicated memory prior to the vertex shader being invoked, whereas texture fetches have to wait for the values to be read.

In that case, you might also want to store the vertex positions in a texture, with the indices being the only attributes. Using gl_VertexID/3 requires 3 distinct vertices per triangle.

Ultimately, there’s no one right way to do this. The trade-offs depend upon the amount of data and the hardware.