Face normal vs vertex normal

I agree about the example being a useful addition to the next edition. I don’t know if we will have the opportunity and / or the time and space to be able to do it, but if so we’ll certainly consider it.

I’m hoping that you know how to use git. I attach a project with three commits showing three different renders of a cube. First one is all red, second and third are separate color per face. You can checkout each commit and run the project to see how each is done.

Initial explanation:

A vertex is not a position. It may have a position attribute, but it is not itself a position.

A cube has 8 corners. A corner is a point in space. Each corner has three touching sides, so a cube actually has 8 corners (points in space), and 24 vertices.

Using indexing, you need only list the 8 points in space, and have 24 indices.

However, if you want to give a vertex a set of attributes, such as position, normal, color, then you’ll need to split out the vertices into 24 vertices.

Another consideration is that each vertex will have its own normal, but it might share a color with other vertices.

I’ve been talking about materials and submeshes to do this. Group the indices into groups of the same color. That’s a submesh.

The code:

Most of the action takes place in Primitive’s buildCube(). Renderer’s draw(in:) does the draw calls according to how the data is set up in Primitive. And the shader functions also match.

Commit #1 is a cube with 8 vertices and 24 indices. It does an indexed draw and the cube is all red. (The back indices are actually wrong, but that didn’t show up until #2 :stuck_out_tongue_winking_eye: ) Vertex just has a position.

Commit #2 is a cube with 24 vertices and no indices. It doesn’t do an indexed draw and has no indexBuffer, just a Vertex buffer. The vertices are created in buildCube(). This goes through the indices and separates out the indices into a color for each face. Vertex has a position and a color. The vertex shader passes through the color to the fragment shader, which uses the stage_in attribute to receive it.

Commit #3 is a cube with 8 vertices and 24 indices. The indices are grouped into 6 submeshes. Each submesh has its own color. This is most like the way the book does it. For example the train has a submesh for the wheels, the chimney, the body, the chassis etc. Each submesh has its own color. Instead of being attached to a vertex, this color goes directly to the fragment shader. This has the advantage that as well as color, you can easily add a new attribute such as shiny to a submesh. The disadvantage is that there are draw calls for each submesh. If you look at the GPU debugger for this one, there are six draw calls (one set for solid and one set for wireframe). Obviously overkill for a cube, but of course it depends on your models.

MeshGeneration.zip (130.3 KB)

If you wanted more complex materials, such as color and shininess, in Commit #2 you could assign a face number to the vertex instead of adding the color directly. That face number could index into an array of materials which you send to the fragment shader as in Commit #3.

1 Like