Root cause: ALL 12 faces in cube.obj had reversed winding order.
This caused every face normal to point inward, breaking:
- Diffuse lighting (NdotL < 0 → no light on any face)
- Shadow bias (slope-dependent bias used wrong NdotL)
- Shadow self-shadowing (both sides rendered with CULL_NONE)
Fix: reversed all face indices to correct CCW winding:
- Back face: f 1 4 3, f 1 3 2 (was f 1 2 3, f 1 3 4)
- Front face: f 5 6 7, f 5 7 8 (was f 5 7 6, f 5 8 7)
- Left/Right/Bottom/Top: all reversed
Now MeshMath.ComputeFaceNormal produces correct outward normals.
Normal flip in shader (dot(N,V) < 0) is still kept as safety for
double-sided rendering, but cubes now have correct normals natively.