Two-sided Lighting

How to 3D

Chapter 6: Lighting

Two-sided Lighting

Many models we render are watertight, which means they completely enclose a volume and have no holes. Water can neither get in or out of the surface. They are also usually manifold, which means the triangles form a clean surface. No faces overlap, each edge connects exactly two faces, and the faces are oriented consistently so that their normals point outward. Our lighting system assumes watertight and manifold surfaces.

Sometimes we render models that don't meet all these criteria. For example: walls. We often model these as flat polygons. They aren't watertight because they don't enclose volumes. They aren't manifold because their boundary edges do not connect two faces. Normally we assume that the viewer sees only one side of a surface. If we've got surfaces that might be viewed from both sides, like walls, we have to fix a couple of things.

First, we must disable back-face culling—since we expect the viewer to see back-facing triangles. Click and drag on the triangle in this renderer so its back face is to the viewer. The triangle's normal points out from its front face.

The triangle disappears. Disable back-face culling to make the triangle reappear. However, there's an issue with the lighting. If the front-face is pointing at the light, the back-face is illuminated too. If the back-face is pointing at the light, it's pitch black. In sum, the back-face is illuminated in exactly the same way as the front-face, despite pointing in the opposite direction. Enable two-sided lighting to fix this.

The fix happens in the fragment shader. GLSL has a builtin boolean variable gl_FrontFacing that we can inspect. If it's false, we are viewing the backface of a triangle. The normal points outward from the front-face. We negate it to make it point outward from the back-face.

We might be tempted to fix this in the vertex shader, which runs less often than the fragment shader. Unfortunately, gl_FrontFacing isn't available in the vertex shader. There's a good reason for this: a single vertex may be part of many triangles. Some might be front-facing and some might be back-facing.

← SpotlightLighting Without Normals →