API

Vertex Normals

Vertex Normals

Each triangular facet of a mesh comprises three vertices. Besides a position, each vertex has another important Vector3 called a normal. These vertex normals are used by the shader code to calculate how the mesh is lit. Unlike a mathematical normal, they do not need to be set at right angles, and for curved shapes such as a sphere they may not be. In the case of a sphere, they are set as the mathematical normals of the sphere surface rather than of the flat facets of the mesh that create the sphere.

At first, the vertex normals are calculated as the mathematical normals for the facet. It then depends on whether you want to view the facets as flat surfaces or as part of a curve. For flat surfaces, the vertex normals remain as the mathematical normals. To enhance the curve when viewed under light, where triangular facets share vertices with the same positions, each shared vertex normal is recalculated to be the average of the mathematical normals of the shared facets.

These effects are explored below.

In the following two playgrounds see how the changing directions within the normals array affect how it is lit:

Vertex Normals Varying In Unison Showing Normals Varying

Normals and Minimum Vertices

Wireframe

The box above has 8 vertices. If we want to keep the indices to the minimum they will be 0, 1, 2, 3, 4, 5, 6, 7.

Facets 0, 3, 7 and 3, 7, 6 and 0, 3, 2 all have vertex 3 in common and vertex 3 can only have one entry in the normals array associated with it.

How does Babylon.js calculate the normal for vertex 3?

The diagram below shows that the average of the three mathematical normals at each vertex is used:

Normals

Besides minimising the number of vertices needed there are other advantages as will be seen when creating a sphere.

Keeping the indices to a minimum the normals at each corner are an average of the mathematical normals of the three faces that meet at that corner. So 8 corners and 8 unique vertex normals.

Table of Unique Indices, Positions and Normals for Box with Minimum Vertices

indexpositionnormal
0
( -1 , 1 , -1 )
( -0.5773502691896258 , 0.5773502691896258 , -0.5773502691896258 )
1
( 1 , 1 , -1 )
( 0.8164965809277261 , 0.4082482904638631 , -0.4082482904638631 )
2
( 1 , -1 , -1 )
( 0.4082482904638631 , -0.4082482904638631 , -0.8164965809277261 )
3
( -1 , -1 , -1 )
( -0.4082482904638631 , -0.8164965809277261 , -0.4082482904638631 )
4
( -1 , 1 , 1 )
( -0.4082482904638631 , 0.4082482904638631 , 0.8164965809277261 )
5
( 1 , 1 , 1 )
( 0.4082482904638631 , 0.8164965809277261 , 0.4082482904638631 )
6
( 1 , -1 , 1 )
( 0.5773502691896258 , -0.5773502691896258 , 0.5773502691896258 )
7
( -1 , -1 , 1 )
( -0.8164965809277261 , -0.4082482904638631 , 0.4082482904638631 )

Normals and Flat Shaded Meshes.

There are times, such as needing each face of a box to be covered in a different material, when it is better to have the box constructed from separate faces, each of which is constructed from two facets, with no two faces sharing vertex indices. They will, of course, share vertex positions.

Seperate Faces

In Babylon.js this can be achieved using the convertToFlatShadedMesh function. The results are shown below:

Flat Shaded Normals

For a flat-shaded mesh, each of the triangular facets making up a face of the box has mathematical normals as its vertex normals. For simplicity of illustration, we will consider only the six faces making up the box rather than the full range of triangular facets used in the mesh construction. Each face has 4 corners, and each corner has a unique normal at right angles to the face. There are 6 faces on a box, and so 24 unique corner normals.

Table of Faces, Corners, Positions and Normals for Flat Shaded Box

Facecornerpositionnormal
Front
0
( -1 , 1 , -1 )
( 0 , 0 , -1 )
Front
1
( 1 , -1 , -1 )
( 0 , 0 , -1 )
Front
2
( 1 , 1 , -1 )
( 0 , 0 , -1 )
Front
3
( -1 , 1 , -1 )
( 0 , 0 , -1 )
Back
4
( -1 , 1 , 1 )
( 0 , 0 , 1 )
Back
5
( 1 , -1 , 1 )
( 0 , 0 , 1 )
Back
6
( -1 , -1 , 1 )
( 0 , 0 , 1 )
Back
7
( -1 , 1 , 1 )
( 0 , 0 , 1 )
Right
8
( 1 , 1 , -1 )
( 1 , -0 , 0 )
Right
9
( 1 , -1 , 1 )
( 1 , -0 , 0 )
Right
10
( 1 , 1 , 1 )
( 1 , -0 , 0 )
Right
11
( 1 , 1 , -1 )
( 1 , 0 , 0 )
Left
12
( -1 , 1 , -1 )
( -1 , 0 , 0 )
Left
13
( -1 , -1 , 1 )
( -1 , 0 , 0 )
Left
14
( -1 , -1 , -1 )
( -1 , 0 , 0 )
Left
15
( -1 , 1 , -1 )
( -1 , -0 , -0 )
Top
16
( -1 , 1 , -1 )
( 0 , 1 , 0 )
Top
17
( 1 , 1 , 1 )
( 0 , 1 , 0 )
Top
18
( -1 , 1 , 1 )
( 0 , 1 , 0 )
Top
19
( 1 , 1 , -1 )
( 0 , 1 , -0 )
Base
20
( -1 , -1 , -1 )
( 0 , -1 , -0 )
Base
21
( 1 , -1 , 1 )
( 0 , -1 , -0 )
Base
22
( 1 , -1 , -1 )
( 0 , -1 , -0 )
Base
23
( -1 , -1 , 1 )
( 0 , -1 , 0 )

Playground Showing Box Normals

Box Normals

Advantage of Shared Normals

Sharing normals means that the shader produces a rounder looking sphere since the vertex normals are the mathematical normals of the sphere surface.

Applying the function converToFlatShadedMesh shows the individual faces making up the sphere. For a flat shaded sphere the normals of each facet are the mathematical normals of the facet.

Comparing Shading of Spheres

Further reading

Create Custom Meshes
Learn how to create custom meshes in Babylon.js.
Create Custom Meshes
Updating Vertices
Learn how to update vertices of a mesh in Babylon.js.
Updating Vertices