forked from: perspective projection bgstaal
Taken from:
http://bgstaal.net/blog/?p=57
/**
* Copyright jules ( http://wonderfl.net/user/jules )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/jzRG
*/
// 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;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.utils.*;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.*;
import org.libspark.betweenas3.tweens.ITween;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.utils.Mouse3D;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.render.QuadrantRenderEngine;
import org.papervision3d.view.BasicView;
import com.bit101.components.*;
[SWF(width="640", height="480", backgroundColor="0xbbFDE2")]
public class SpinningCube extends Sprite
{
private const COLOR:Number = 0x000000;
private const COLOR2:Number = 0xFF0000;
private const COLOR3:Number = 0x00FF00;
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 _centrePointX:Number;
private var _centrePointY:Number;
private var _rotationX:Number = 0;
private var _rotationY:Number = 0;
private var _rotationZ:Number = 0;
private var myLoader:Loader;
private const IMAGE_URL:String = "http://farm4.static.flickr.com/3190/2662752839_249c6642b1.jpg";
public function SpinningCube()
{
init();
}
private function init ():void
{
setProperties();
createProjection();
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
myLoader= new Loader();
myLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressStatus);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderReady);
var fileRequest:URLRequest = new URLRequest("http://maptopixel.com/projects/images/1326473779375__yaw_168.0_pitch_47.0_roll_-92.0_small.jpg");
myLoader.load(fileRequest);
myLoader.alpha = 0.5;
}
public function onProgressStatus(e:ProgressEvent) {
// this is where progress will be monitored
//trace(e.bytesLoaded, e.bytesTotal);
}
public function onLoaderReady(e:Event) {
// the image is now loaded, so let's add it to the display tree!
addChild(myLoader);
myLoader.x = 0;
myLoader.y = 0;
}
/**
* Set the inital properties for our perspective projection scene
*/
private function setProperties ():void
{
// set the size properties of the cube
_cubeWidth = 100;
_cubeHeight = 100;
_cubeDepth = 100;
// Set the position of the cube to the center of the stage
//_cubeX = (stage.stageWidth - _cubeWidth)/2;
//_cubeY = (stage.stageHeight - _cubeHeight)/2;
_cubeX = stage.stageWidth /2;
_cubeY = stage.stageHeight /2;
_centrePointX = stage.stageWidth /2;
_centrePointY = stage.stageHeight/2;
// _cubeX = 0;
//_cubeY = 0;
// Set the projection center (vanishing point) to the center of the stage
_projectionCenter = new Point(stage.stageWidth/2, stage.stageHeight/2);
//_projectionCenter = new Point(200, 200);
// 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(_cubeX, _cubeY, _cubeDepth);
// 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();
drawLines2();
_rotationX =47; //Should take pitch value I think
_rotationY =12; //Should be taken from the previous points somehoew, or yaw
_rotationZ = 0;
}
/**
* Creates the 3d points based on the properties we set earlier
*/
private function create3dPoints ():void
{
_3dPoints = new Vector.<Point3d>();
/*
_3dPoints.push(new Point3d(30,10, 180));
_3dPoints.push(new Point3d(20,10, 28));
_3dPoints.push(new Point3d(126,10, 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(_centrePointX, _centrePointY , _cubeDepth));//centre of frustr
_3dPoints.push(new Point3d(_centrePointX-350, _centrePointY, _cubeDepth));
_3dPoints.push(new Point3d(_centrePointX+350, _centrePointY, _cubeDepth));
//_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));
_3dPoints.push(new Point3d(_centrePointX, _centrePointY , _cubeDepth-250));
_3dPoints.push(new Point3d(_centrePointX, _centrePointY+250 , _cubeDepth));
_3dPoints.push(new Point3d(_centrePointX, _centrePointY-250, _cubeDepth));
// 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(_centrePointX, _centrePointY , _cubeDepth+250));
//_3dPoints.push(new Point3d(_centrePointX, _centrePointY , _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()
}
graphics.beginFill(COLOR3);
graphics.drawCircle(_projectionCenter.x,_projectionCenter.y, 2);
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);
}
private function drawLines2 ():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.lineStyle(1, COLOR2);
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[2].x, _2dPoints[2].y);
graphics.lineStyle(1, COLOR3);
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[3].x, _2dPoints[3].y);
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[4].x, _2dPoints[4].y);
graphics.lineStyle(1, COLOR2);
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[5].x, _2dPoints[5].y);
graphics.lineStyle(1, COLOR3);
graphics.moveTo(_2dPoints[0].x, _2dPoints[0].y);
graphics.lineTo(_2dPoints[6].x, _2dPoints[6].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;
}
}