forked from: perspective projection bgstaal
forked from perspective projection bgstaal (diff: 17)
Taken from: http://bgstaal.net/blog/?p=57
ActionScript3 source code
/**
* Copyright jules ( http://wonderfl.net/user/jules )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/gUMP
*/
// forked from jules's perspective projection bgstaal
/*Taken from:
http://bgstaal.net/blog/?p=57
*/
package {
import flash.display.Sprite;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
[SWF(widht="600", height="330", backgroundColor="0xFFFDE2")]
public class SpinningCube extends Sprite
{
private const COLOR:Number = 0x000000;
private var _cubeWidth:Number;
private var _cubeHeight:Number;
private var _cubeDepth:Number;
private var _cubeX:Number;
private var _cubeY:Number;
private var _projectionCenter:Point;
private var _fieldOfView:Number;
private var _focalLength:Number;
private var _pivotPoint:Point3d;
private var _3dPoints:Vector.<Point3d>;
private var _2dPoints:Vector.<Point2d>;
private var _rotationX:Number = 0;
private var _rotationY:Number = 0;
private var _rotationZ:Number = 0;
public function SpinningCube()
{
init();
}
private function init ():void
{
setProperties();
createProjection();
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
/**
* Set the inital properties for our perspective projection scene
*/
private function setProperties ():void
{
// set the size properties of the cube
_cubeWidth = 400;
_cubeHeight = 200;
_cubeDepth = 600;
// Set the position of the cube to the center of the stage
//_cubeX = (stage.stageWidth - _cubeWidth)/2;
// _cubeY = (stage.stageHeight - _cubeHeight)/2;
_cubeX = 10;
_cubeY = 20;
// Set the projection center (vanishing point) to the center of the stage
_projectionCenter = new Point(stage.stageWidth/2, stage.stageHeight/2);
// Set the pivot point to be at the 3d center of the cube
//_pivotPoint = new Point3d(_cubeX + (_cubeWidth/2), _cubeY + (_cubeHeight/2), _cubeDepth/2);
_pivotPoint = new Point3d(20,300, 28);
// Set the the field of view to a numver between 1 & 179.
_fieldOfView = 55;
// Calculate the focal length based on the width of the stage and the field of view.
var a:Number = _fieldOfView/2;
var b:Number = 90 - a;
var bRad:Number = b/180*Math.PI;
var opposite:Number = stage.stageWidth/2;
_focalLength = opposite * Math.tan(bRad);
}
private function enterFrameHandler (e:Event):void
{
createProjection();
}
private function createProjection ():void
{
create3dPoints();
rotate3dPoints();
projectPoints();
drawPoints();
drawLines();
_rotationX += 4;
_rotationY += 4;
}
/**
* Creates the 3d points based on the properties we set earlier
*/
private function create3dPoints ():void
{
_3dPoints = new Vector.<Point3d>();
_3dPoints.push(new Point3d(30,300, 180));
_3dPoints.push(new Point3d(20,300, 28));
_3dPoints.push(new Point3d(126,300, 20));
//_3dPoints.push(new Point3d(126,300, 20));
/*
_3dPoints.push(new Point3d(100,300, 400));
_3dPoints.push(new Point3d(stage.stageWidth/2, stage.stageHeight/2,300));
_3dPoints.push(new Point3d(350,300, 400));
*/
/*
// add points to create a rectangle of the supplied width and height
// at the supplied x and y coordinates and a z value of 0
_3dPoints.push(new Point3d(_cubeX, _cubeY, 0));
_3dPoints.push(new Point3d(_cubeX + _cubeWidth, _cubeY, 0));
_3dPoints.push(new Point3d(_cubeX + _cubeWidth, _cubeY + _cubeHeight, 0));
_3dPoints.push(new Point3d(_cubeX, _cubeY + _cubeHeight, 0));
// then add the same points again with a z value of the supplied depth
_3dPoints.push(new Point3d(_cubeX, _cubeY, _cubeDepth));
_3dPoints.push(new Point3d(_cubeX + _cubeWidth, _cubeY, _cubeDepth));
_3dPoints.push(new Point3d(_cubeX + _cubeWidth, _cubeY + _cubeHeight, _cubeDepth));
_3dPoints.push(new Point3d(_cubeX, _cubeY + _cubeHeight, _cubeDepth));
*/
}
/**
* Loops through the 3d points and rotates each point around the pivot point
*/
private function rotate3dPoints():void
{
var rotationMatrix:Matrix3d = Matrix3d.createRotationMatrix(_rotationX, _rotationY, _rotationZ);
for (var i:int = 0; i < _3dPoints.length; i++)
{
var point3d:Point3d = _3dPoints[i];
point3d.applyMatrix(rotationMatrix, _pivotPoint);
}
}
/**
* Loops through and projects the 3d points to create a vector of 2d points.
*/
private function projectPoints ():void
{
_2dPoints = new Vector.<Point2d>();
for (var i:int = 0; i < _3dPoints.length; i++)
{
var point3d:Point3d = _3dPoints[i];
// calls the project function on each point3d wich reaturns a point2d
var point2d:Point2d = point3d.project(_focalLength, _projectionCenter);
_2dPoints.push(point2d)
}
}
/**
* Draws a circle on stage as a visual representation of each point
*/
private function drawPoints ():void
{
var radius:Number = 5;
graphics.clear();
for (var i:int = 0; i < _2dPoints.length; i++)
{
var point2d:Point2d = _2dPoints[i];
graphics.beginFill(COLOR);
graphics.drawCircle(point2d.x, point2d.y, radius*point2d.t);
graphics.endFill()
}
}
/**
* Draws a the lines that connects the eight corners of the cube
*/
private function drawLines ():void
{
graphics.lineStyle(1, COLOR);
// draw the first rectangle
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[1].x, _2dPoints[1].y);
graphics.lineTo(_2dPoints[2].x, _2dPoints[2].y);
graphics.lineTo(_2dPoints[3].x, _2dPoints[3].y);
graphics.lineTo(_2dPoints[0].x, _2dPoints[0].y);
// draw the second rectangle
graphics.moveTo(_2dPoints[4].x, _2dPoints[4].y);
graphics.lineTo(_2dPoints[5].x, _2dPoints[5].y);
graphics.lineTo(_2dPoints[6].x, _2dPoints[6].y);
graphics.lineTo(_2dPoints[7].x, _2dPoints[7].y);
graphics.lineTo(_2dPoints[4].x, _2dPoints[4].y);
// draw lines between the corners of the rectangles
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[4].x, _2dPoints[4].y);
graphics.moveTo(_2dPoints[1].x, _2dPoints[1].y);
graphics.lineTo(_2dPoints[5].x, _2dPoints[5].y);
graphics.moveTo(_2dPoints[2].x, _2dPoints[2].y);
graphics.lineTo(_2dPoints[6].x, _2dPoints[6].y);
graphics.moveTo(_2dPoints[3].x, _2dPoints[3].y);
graphics.lineTo(_2dPoints[7].x, _2dPoints[7].y);
}
}
}
import flash.geom.Point;
/**
* <b>Point3d ©2009, bgstaal.net</b>
* <hr/>
* The Point3d holds the properties to represent a single point i 3d space (x,y,z)
* and the methods to apply transformation matrices and return a 2d representation
* of the 3d point.
* @author Bjørn Gunnar Staal
* @version 1.0
*/
class Point3d
{
/**
* The x coordinate
*/
public var x:Number;
/**
* The y coordinate
*/
public var y:Number;
/**
* The z coordinate
*/
public var z:Number;
/**
* Creates a Point3d instance
* @param x The x coordinate
* @param y The y coordinate
* @param z The z coordinate
*/
public function Point3d(x:Number = 0, y:Number = 0, z:Number = 0)
{
this.x = x;
this.y = y;
this.z = z;
}
/**
* Performs a perspective projection on the instance and returns a 2d represenation of the 3d coordinates
* @param focalLength Distance from camera to the stage
* @param projectionCenter 2d coordinate representing the center of the viewing frustrum (vanishing point)
* @return A Point2d instance representing a projected version of <code>this<code>
*/
public function project (focalLength:Number, projectionCenter:Point = null):Point2d
{
var t:Number = focalLength / (focalLength+z);
if (!projectionCenter)
{
projectionCenter = new Point(0, 0);
}
var xOffset:Number = projectionCenter.x;
var yOffset:Number = projectionCenter.y;
var x:Number = this.x;
var y:Number = this.y;
var z:Number = this.z;
x -= xOffset;
y -= yOffset;
x = (x*t)+xOffset;
y = (y*t)+yOffset;
return new Point2d(x, y, t);
}
/**
* Applies the supplied transformation matrix to the point around the supplied pivot point
* @param m Matrix3d instance with the transformation values
* @param pivotPoint A Point in 3d witch the transformation should be applied around. The coordinates (0,0,0) is used if no value is supplied.
*/
public function applyMatrix (m:Matrix3d, pivotPoint:Point3d = null):void
{
if (!pivotPoint)
{
pivotPoint = new Point3d();
}
var p:Point3d = m.apply(this, pivotPoint);
this.x = p.x;
this.y = p.y;
this.z = p.z;
}
}
class Point2d
{
/**
* The points x coordinate
*/
public var x:Number;
/**
* The points y coordinate
*/
public var y:Number;
/**
* The value t represents the points scale
*/
public var t:Number;
/**
* Create a Point2d instance
* @param x The x coordinate
* @param y The y coordinate
* @param t The value t represents the points scale
*/
public function Point2d(x:Number, y:Number, t:Number)
{
this.x = x;
this.y = y;
this.t = t;
}
/**
* Returns the x, y & t values as a string
* @return A string representation of the public properties.
*/
public function toString ():String
{
return "x: " + x + ", y: " + y + ", t: " + t;
}
}
class Matrix3d
{
/**
* <p>
* X 0 0 0 <br/>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n11:Number;
/**
* <p>
* 0 X 0 0 <br/>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n12:Number;
/**
* <p>
* 0 0 X 0 <br/>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n13:Number;
/**
* <p>
* 0 0 0 X <br/>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n14:Number;
/**
* <p>
* 0 0 0 0 <br/>
* X 0 0 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n21:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 X 0 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n22:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 0 X 0 <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n23:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 0 0 X <br/>
* 0 0 0 0 <br/>
* </p>
*/
public var n24:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* X 0 0 0 <br/>
* </p>
*/
public var n31:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* 0 X 0 0 <br/>
* </p>
*/
public var n32:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* 0 0 X 0 <br/>
* </p>
*/
public var n33:Number;
/**
* <p>
* 0 0 0 0 <br/>
* 0 0 0 0 <br/>
* 0 0 0 X <br/>
* </p>
*/
public var n34:Number;
/**
* Create a new Matrix3d Object.
* By default a 4x3 identity matrix is created.
* @param n11 The value in the first collumn of the first row
* @param n12 The value in the second collumn of the first row
* @param n13 The value in the third collumn of the first row
* @param n14 The value in the fourth collumn of the first row
* @param n21 The value in the first collumn of the second row
* @param n22 The value in the second collumn of the second row
* @param n23 The value in the third collumn of the second row
* @param n24 The value in the fourth collumn of the second row
* @param n31 The value in the first collumn of the third row
* @param n32 The value in the second collumn of the third row
* @param n33 The value in the third collumn of the third row
* @param n34 The value in the fourth collumn of the third row
*/
public function Matrix3d(n11:Number = 1, n12:Number = 0, n13:Number = 0, n14:Number = 0,
n21:Number = 0, n22:Number = 1, n23:Number = 0, n24:Number = 0,
n31:Number = 0, n32:Number = 0, n33:Number = 1, n34:Number = 0)
{
this.n11 = n11;
this.n12 = n12;
this.n13 = n13;
this.n14 = n14;
this.n21 = n21;
this.n22 = n22;
this.n23 = n23;
this.n24 = n24;
this.n31 = n31;
this.n32 = n32;
this.n33 = n33;
this.n34 = n34;
}
/**
* Applies the transformation to a Point3d around a pivot point and returns a new point3d
* @param p The point witch the transformation should be applied to.
* @param pivotPoint The point in 3d witch the transformation should be applied around. The coordinates (0,0,0) is used if no value is supplied.
* @return A new Point3d representing the supplied Point3d instance with the transformations applied.
*/
public function apply (p:Point3d, pivotPoint:Point3d = null):Point3d
{
if (!pivotPoint)
{
pivotPoint = new Point3d();
}
p.x -= pivotPoint.x;
p.y -= pivotPoint.y;
p.z -= pivotPoint.z;
var x:Number = (p.x * n11) + (p.y * n12) + (p.z * n13) + n14 + pivotPoint.x;
var y:Number = (p.x * n21) + (p.y * n22) + (p.z * n23) + n14 + pivotPoint.y;
var z:Number = (p.x * n31) + (p.y * n32) + (p.z * n33) + n14 + pivotPoint.z;
return new Point3d(x, y, z);
}
/**
* Creates a transformation matrix with the supplied rotation around either axis
* @param xRotation The number of degrees of rotation that should be applied around the x axis. (roll)
* @param yRotation The number of degrees of rotation that should be applied around the y axis. (pitch)
* @param zRotation The number of degrees of rotation that should be applied around the z axis. (yaw)
* @return A Matrix3d instance with the supplied rotations applied.
*/
public static function createRotationMatrix (xRotation:Number, yRotation:Number, zRotation:Number):Matrix3d
{
var xMatrix:Matrix3d = createXRotationMatrix(xRotation);
var yMatrix:Matrix3d = createYRotationMatrix(yRotation);
var zMatrix:Matrix3d = createZRotationMatrix(zRotation);
var m:Matrix3d = multiplySeveral(xMatrix, yMatrix, zMatrix);
return m;
}
/**
* Creates a rotation matrix with the supplied rotation around the x axis. (roll)
* @param rotation The number of degrees of rotation that should be applied around the x axis
* @return A Matrix3d instance with the supplied x rotation applied.
*/
public static function createXRotationMatrix (rotation:Number):Matrix3d
{
var radians:Number = rotation/180*Math.PI;
var n:Array = [1, 0, 0, 0,
0, Math.cos(radians), Math.sin(radians), 0,
0, -Math.sin(radians), Math.cos(radians), 0];
return matrix3dFromArray(n);
}
/**
* Creates a rotation matrix with the supplied rotation around the y axis. (pitch)
* @param rotation The number of degrees of rotation that should be applied around the y axis
* @return A Matrix3d instance with the supplied y rotation applied.
*/
public static function createYRotationMatrix (rotation:Number):Matrix3d
{
var radians:Number = rotation/180*Math.PI;
var n:Array = [Math.cos(radians), 0, Math.sin(radians), 0,
0, 1, 0, 0,
-Math.sin(radians), 0, Math.cos(radians), 0];
return matrix3dFromArray(n);
}
/**
* Creates a rotation matrix with the supplied rotation around the z axis. (yaw)
* @param rotation The number of degrees of rotation that should be applied around the z axis
* @return A Matrix3d instance with the supplied z rotation applied.
*/
public static function createZRotationMatrix (rotation:Number):Matrix3d
{
var radians:Number = rotation/180*Math.PI;
var n:Array = [Math.cos(radians), Math.sin(radians), 0, 0,
-Math.sin(radians), Math.cos(radians), 0, 0,
0, 0, 1, 0];
return matrix3dFromArray(n);
}
/**
* Creates a Matrix3d filled with the values from the supplied array
* @param n A Array instance with 12 entries representing the numbers in the matrix starting with the top left collumn and ending with the bottom right.
* @return A Matrix3d instance filled with the supplied values
*/
public static function matrix3dFromArray (n:Array):Matrix3d
{
if (n.length == 12)
{
var m:Matrix3d = new Matrix3d(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[8], n[9], n[10], n[11]);
return m;
}
else
{
return null;
}
}
/**
* Multiplies two Matrix3d instances and returns the result
* @param a The first matrix
* @param b The seconds matrix
* @return A Matrix3d instance representing the result of the multiplication
*/
public static function multiply (a:Matrix3d, b:Matrix3d):Matrix3d
{
var c:Matrix3d = new Matrix3d();
c.n11 = a.n11 * b.n11 + a.n12 * b.n21 + a.n13 * b.n31;
c.n12 = a.n11 * b.n12 + a.n12 * b.n22 + a.n13 * b.n32;
c.n13 = a.n11 * b.n13 + a.n12 * b.n23 + a.n13 * b.n33;
c.n14 = a.n11 * b.n14 + a.n12 * b.n24 + a.n13 * b.n34 + a.n14;
c.n21 = a.n21 * b.n11 + a.n22 * b.n21 + a.n23 * b.n31;
c.n22 = a.n21 * b.n12 + a.n22 * b.n22 + a.n23 * b.n32;
c.n23 = a.n21 * b.n13 + a.n22 * b.n23 + a.n23 * b.n33;
c.n24 = a.n21 * b.n14 + a.n22 * b.n24 + a.n23 * b.n34 + a.n24;
c.n31 = a.n31 * b.n11 + a.n32 * b.n21 + a.n33 * b.n31;
c.n32 = a.n31 * b.n12 + a.n32 * b.n22 + a.n33 * b.n32;
c.n33 = a.n31 * b.n13 + a.n32 * b.n23 + a.n33 * b.n33;
c.n34 = a.n31 * b.n14 + a.n32 * b.n24 + a.n33 * b.n34 + a.n34;
return c;
}
/**
* Multiplies several Matrix3d instances and returns the result
* @param matrices The Matrix3d instances that should be multiplied.
* @return A Matrix3d instance representing the result of the multiplication
*/
public static function multiplySeveral (...matrices):Matrix3d
{
var newMatrix:Matrix3d = matrices[0];
for (var i:int = 1; i < matrices.length; i++)
{
var m:Matrix3d = matrices[i];
newMatrix = multiply(newMatrix, m);
}
return newMatrix;
}
}
