6

I have vertex and triangle data which contains a color for each triangle (face), not for each vertex. i.e. A single vertex is shared by multiple faces, each face potentially a different color.

How should I approach this problem in GLSL to obtain a solid color assignment for each face being rendered? Calculating and assigning a "vertex color" buffer by averaging the colors of a vertex's neighboring polys is easy enough, but this of course produces a blurry result where the colors are interpolated in the fragment shader.

What I really need shouldn't be interpolated color values at all, I'll have about 40k triangles shaded with approx 15 possible solid colors once this is working as intended.

Manius
  • 3,594
  • 3
  • 34
  • 44

3 Answers3

8

While you maybe could do this in high end GLSL, the right way to do solid shading is to make unique vertices for every triangle. This is a trivial loop. For every vertex, count how many triangles share it. That's how often you have to replicate it. Make sure your loop to do this is O(n). Then just set each vertex color or normal to that of the triangle. Again one straight loop. Do not bother to optimize for shared colors, it is not worth it.

Edit much later, because this is a popular answer:

To do flat per face shading you can interpolate the vertex position in world or view space. Then in the fragment shader compute ddx(dFdx) and ddy(dFdy) of this variable. Take the cross product of those two vectors and normalize it - you got a flat normal! No mesh changes or per vertex data needed at all.

starmole
  • 4,974
  • 1
  • 28
  • 48
  • Was concerned about performance, but I suppose if it's all in one geometry it might not be an issue. Will have to see how it goes. Another complication I didn't mention is that I'd like to be able to switch from this 'mode' to a fully multitextured, blended mode. But I could also just toggle the mesh visible. – Manius Jun 30 '11 at 11:56
  • This was a while ago, but this is all I ended up needing. Just duplicate all vertices, no triangle shares the same vertex index. – Manius May 21 '17 at 18:12
4

OpenGL does not have "per-face" attributes. See:

How can I specify per-face colors when using indexed vertex arrays in OpenGL 3.x?

Here are a few possible options I see:

  1. Ditch the index arrays and use separate vertices for each face like starmole suggested
  2. Create an index array for each color used. Use materials instead of vertex colors and change the material after drawing the triangles from the index array for each color.
  3. If the geometry allows it, you can make sure the last vertex specified by the index array has the correct vertex color for the face, and then use GL_FLAT shading, or have the fragment shader only use at the last vertex color.
Community
  • 1
  • 1
dschaeffer
  • 618
  • 6
  • 15
  • 2
    Would you be able to elaborate on #3 at all? Particularly the ability to "use the last vertex color" in the fragment shader - how do we access a fragment's vertices from the frag shader? – Manius Jul 13 '11 at 00:15
4

In addition to the other answers, you could maybe employ the gl_PrimitiveID variable, that's an input to the fragment shader (don't know since which version) and is incremented implicitly for each triangle. You could then use this to lookup the color (either from a 40k buffer texture of colors or color indices into a 15 color color map, or just some direct computation from the primitive id). But don't ask me about the performance of this approach.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
  • If I tried this, do you know if that ID variable applies per-mesh, or if the ID will increment for every triangle rendered? I'd be concerned about whether the IDs are consistent, and whether other meshes would throw the count off. – Manius Jul 16 '11 at 00:20
  • @Crusader The ID is set to zero for every `glDraw...` command (and in every instance of a `glDrawMulti...` command, I think) and incremented everytime a primitive (triangle) is drawn, so yes the IDs are consistent and only depend on the current `glDraw...` command. – Christian Rau Jul 16 '11 at 12:49