Skip to content

Instantly share code, notes, and snippets.

@KrofDrakula
Created December 20, 2011 08:48
Show Gist options
  • Save KrofDrakula/1500838 to your computer and use it in GitHub Desktop.
Save KrofDrakula/1500838 to your computer and use it in GitHub Desktop.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment