To calculate flat shading (an approximation that works well for small flat faces), you need:
- a vector pointing towards the light source from the center of the surface you want to shade,
- a vector representing the normal of the surface to be rendered.
The first one is easily calculated:
var faceCenter = [x1, y1, z1];
var light = [x2, y2, z2];
var lightDirection = [x2-x1, y2-y1, z2-z1];
The second is trickier, since you need to calculate this using the given rotations. This depends on the order of rotations around the X, Y and Z axes. Point is, this vector should be perpendicular to the surface you want to light.
When you have both vectors, ie. lightDirection
and surfaceNormal
, you can calculate the angle between the two using the cosine formula. Let a
be the length of lightDirection
, b
be surfaceNormal
and c
the length of the vector lightDirection - surfaceNormal
:
var cos = (a*a + b*b - c*c) / (2 * a * b);
A cosine value then gets you values between -1 and 1, so you can use the following formula to calculate light intensity:
var globalLight = 0.1;
var intensity = Math.max(globalLight, cos);
...where globalLight
is a global fill light to avoid having non-facing faces and backfaces display black.
Note, since you cannot control back-face lighting in 3D CSS, you will need extra elements for backfaces that you light by simply negating the surfaceNormal
vector.