Math and (Quasi) Physics in Action Script 3

3D light - computing the angle between the plane surface and the light

Example of applying effect of light by computing the angle between the plane surface and the light.

To determine the angle of the plane, two vectors that represent the two sides of it are needed. The cross product, which is a vector perpendicular to the both of the vectors, can be calculated using the formula below.

Vector3D object provides convenient methods to do this process, crossProduct() and angleBetween(), which returns a cross product of two vectors and angle between two vectors, respectively.

cross product

A×B = [(a2 * b3 - a3 * b2) * (a3 * b1 - a1 * b3) * (a1 * b2 - a2 * b1)] 

for any two vectors A = [a1 a2 a3] and B[b1 b2 b3]

Main.as

´╗┐package {
  import flash.display.*;
  import flash.geom.*;
  import flash.events.*
  
  public class Main extends Sprite {
    private var canvas:Sprite;
    private var vecs:Vector.<Vector3D>;
    private var mtr3d:Matrix3D;
    private var lightVec:Vector3D = new Vector3D(0,0,-1);
    private var  color:uint = 0xfff000;
    
    public function Main() {
      vecs = new Vector.<Vector3D>();
      vecs.push(new Vector3D(-100,-100,0));
      vecs.push(new Vector3D(100,-100,0));
      vecs.push(new Vector3D(100,100,0));
      vecs.push(new Vector3D(-100,100,0));
      mtr3d = new Matrix3D();
      mtr3d.prependRotation(1,Vector3D.Y_AXIS);
      
      addChild(canvas = new Sprite());
      canvas.x = stage.stageWidth / 2;
      canvas.y = stage.stageHeight / 2;
      canvas.z = 1;
      addEventListener(Event.ENTER_FRAME, h_enterFrame);
    }
    
    public function h_enterFrame(evt:Event):void {
      var i:uint;
      lightVec = new Vector3D(canvas.mouseX, canvas.mouseY, -100);
      
      // rotate
      for (i = 0; i < vecs.length; i ++) {
        vecs[i] = mtr3d.transformVector(vecs[i])
      }
      
      // angle between the plane and the light
      var v1:Vector3D = vecs[0].subtract(vecs[1]);
      var v2 :Vector3D = vecs[0].subtract(vecs[3]);
      var cp:Vector3D = v1.crossProduct(v2);
      var angle:Number = Vector3D.angleBetween(cp, lightVec);
      if (angle > Math.PI / 2) { angle = Math.PI - angle };
      
      // brightness
      var brightness:Number = 1 - angle / Math.PI * 0.7;
      var r:uint = color >> 16 & 0xff;
      var g:uint = color >> 8 & 0xff;
      var b:uint = color  & 0xff;
      r *= brightness;
      g *= brightness;
      b *= brightness;
      var tColor:uint = r << 16 | g << 8 | b;
      
      // draw
      var p:Point;
      var gr:Graphics = canvas.graphics;
      gr.clear();
      gr.beginFill(tColor);
      for (i = 0; i < vecs.length; i ++) {
        p = getPoint2d(vecs[i]);
        if (i == 0) {
          gr.moveTo(p.x, p.y);
        } else {
          gr.lineTo(p.x, p.y);
        }
      }
    }
    
    public function getPoint2d(v:Vector3D):Point {
      var p:Point = canvas.local3DToGlobal(v);
      return canvas.globalToLocal(p);
    }
    
  }
}