Wednesday, October 20, 2021

Vertex normals the easy way

Everywhere you look, people suggest that in order to compute vertex normals for smooth shading, you should first compute face normals and average those. If you're doing this on the fly on the GPU, that's an extra pass and just incredibly silly. Here's an easier way: find the ring (order in some consistent winding order) of vertices around every vertex (or just the vertices connected by edges, unless it's valence 2 in which case keep the face verts too; saves half the work on quad meshes), store these lists in a flat array (eg. buffer texture, whatever) with offset+size in the actual render-vertex. Then loop these, subtracting the vertice's position and taking cross-products between any two sequential pairs, accumulate the result and normalize. For closed meshes, that's it. For borders and corners, if two sequential vertices are not connected by a face, add the center vertex as a "dummy edge" so the cross-product will come out zero and you save a branch. If you don't do mess with the lengths of the cross-products when accumulating, the weighting rule ends up roughly sin(angle)*area, which is typically more or less what you'd want anyway. There you go. No need to have face normals at all.