unproject 2D point
turn mouse coordinates to 3D world coordinates -- the painful way
/**
* Copyright mutantleg ( http://wonderfl.net/user/mutantleg )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/7nUP
*/
package {
import flash.geom.Point;
import flash.text.TextField;
import flash.geom.Matrix3D;
import flash.display.BlendMode;
import flash.display.BitmapData;
import flash.events.KeyboardEvent;
import flash.events.Event;
//import flash.media.Camera;
//http://alternativaplatform.com/en/docs/7.7.0/index.html
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.EllipsoidCollider;
import alternativ7.engine3d.objects.Mesh;
import alternativ7.engine3d.primitives.Plane;
import alternativ7.engine3d.primitives.Box;
import alternativ7.engine3d.primitives.Sphere;
import alternativ7.engine3d.primitives.GeoSphere;
import alternativ7.engine3d.core.View;
import alternativ7.engine3d.materials.Material;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.materials.NormalMapMaterial;
import alternativ7.engine3d.materials.FlatShadingMaterial;
import alternativ7.engine3d.materials.VertexLightMaterial;
import alternativ7.engine3d.materials.AverageLightMaterial;
import alternativ7.engine3d.materials.SphericalEnvironmentMaterial;
import alternativ7.types.Texture;
import alternativ7.types.Point3D;
import alternativ7.engine3d.lights.AmbientLight;
import alternativ7.engine3d.lights.DirectionalLight;
import alternativ7.engine3d.lights.OmniLight;
import alternativ7.engine3d.lights.SpotLight;
import flash.display.Sprite;
public class FlashTest extends Sprite {
public var cam:Camera3D;
public var cont:Object3DContainer = new Object3DContainer();
public var gBox:Box;
public var targ:Sprite;
public var ori:cQuat;
public var mat:Matrix3D;
public var camx:Number = 0;
public var camy:Number = 0;
public var camz:Number = 0;
public var debText:TextField;
public var myFrust:cFrustum;
public var vecLine:Vector.<Mesh>;
public function FlashTest() {
// write as3 code here..
cam = new Camera3D();
cam.view = new View(400,400);
///cam.z = -1000;
//cam.fov = (90+30)*(3.1415*180.0);
myFrust = new cFrustum();
myFrust.setPersp( 70, 1,0.1, 3000);
ori = new cQuat();
mat = new Matrix3D();
camy = -900;
camz = -600;
ori.rotPitch(-0.4);
addChild(cam.view);
cont.addChild(cam);
var bm:BitmapData;
bm = new BitmapData(64,64,false,0);
bm.noise(123213,0,16,3,true);
var p:Plane;
p = new Plane(1000, 1000, 8, 8);
p.setMaterialToAllFaces( new TextureMaterial( bm ) );
p.rotationX = 1.57;
p.y = 200+10;
cont.addChild(p);
bm = new BitmapData(64,64,false,0);
bm.noise(123123);
var i:int;
var m:Mesh;
vecLine = new Vector.<Mesh>;
for (i = 0; i < 10; i++)
{
m = new Box(20,20,20,1,1,1);
m.setMaterialToAllFaces(new FillMaterial(0xFF0000,0.5));
vecLine.push(m);
cont.addChild(m);
}//nexti
var box:Box;
box = new Box(60,60,60,1,1,1);
//box.x = 400;
// box.setMaterialToAllFaces( new FillMaterial(0) );
box.setMaterialToAllFaces( new TextureMaterial( bm) );
//box.setMaterialToAllFaces( new VertexLightMaterial( bm ) );
//box.setMaterialToAllFaces( new FlatShadingMaterial( bm ) );
box.calculateVerticesNormals();
cont.addChild(box);
gBox = box;
targ = new Sprite();
targ.graphics.clear();
targ.graphics.lineStyle(2,0);
targ.graphics.drawCircle(0,0,8);
addChild(targ);
debText = new TextField();
debText.text = "debug";
debText.width = 400;
addChild(debText);
stage.addEventListener(Event.ENTER_FRAME, onEnter);
stage.addEventListener(KeyboardEvent.KEY_DOWN, kdown);
stage.addEventListener(KeyboardEvent.KEY_UP, kup);
}//ctor
public var proj:Matrix3D = new Matrix3D();
public var look:Matrix3D = new Matrix3D();
public var testOri:cQuat = new cQuat();
public function onEnter(e:Event):void
{
// var m:Vector.<Number>;
//ref
//http://www.dakmm.com/?p=272
if (cKeyMan.isKeyDown(39) ) { ori.rotYaw(0.1);}
if (cKeyMan.isKeyDown(37) ) { ori.rotYaw(-0.1);}
// if (cKeyMan.isKeyDown(38) ) { cam.y += 20;}
// if (cKeyMan.isKeyDown(40) ) { cam.y -= 20;}
targ.x = stage.mouseX;
targ.y = stage.mouseY;
/*
var dx:Number, dy:Number;
dx = ((stage.mouseX / 500)-0.5)*2;
dy = ((stage.mouseY / 500)-0.5)*2;
//dx = stage.mouseX/500;
//dy = stage.mouseY/500;
//dy *= -1;
// dx = 0;
// dy = 0;
debText.text = "dx " +dx + " dy " + dy;
m = proj.rawData;
setProjectionMatrix(m, 90,1,1,2000);
proj.rawData = m;
proj.invert();
m = look.rawData;
setLookAtMatrix(m, camx,camy,camz,ori.x,ori.y,ori.z, ori.w);
look.rawData = m;
look.invert();
var far:Number = 1;
m = proj.rawData;
mx = dx * m[0] + dy * m[4] + far *-1* m[8] + m[12];
my = dx * m[1] + dy * m[5] + far *-1* m[9] + m[13];
mz = dx * m[2] + dy * m[6] + far *-1* m[10] + m[14];
mw = dx * m[3] + dy * m[7] + far *-1* m[11] + m[15];
m = look.rawData;
kx = mx * m[0] + my * m[4] + mz * m[8] + m[12];
ky = mx * m[1] + my * m[5] + mz * m[9] + m[13];
kz = mx * m[2] + my * m[6] + mz * m[10] + m[14];
kw = mx * m[3] + my * m[7] + mz * m[11] + m[15];
kx *= kw;
ky *= kw;
kz *= kw;
debText.text = "kx " +kx + " ky " + ky + " kz " + kz;
gBox.x = kx;
gBox.y = ky;
gBox.z = kz;
far = 1000;
m = proj.rawData;
mx = dx*far *m[0] + dy*far * m[4] + far*1 * m[8] + m[12];
my = dx*far * m[1] + dy*far * m[5] + far*1 * m[9] + m[13];
mz = dx*far * m[2] + dy*far * m[6] + far*1 * m[10] + m[14];
mw = dx*far * m[3] + dy*far * m[7] + far*1 * m[11] + m[15];
m = look.rawData;
tx = mx * m[0] + my * m[4] + mz * m[8] + m[12];
ty = mx * m[1] + my * m[5] + mz * m[9] + m[13];
tz = mx * m[2] + my * m[6] + mz * m[10] + m[14];
tw = mx * m[3] + my * m[7] + mz * m[11] + m[15];
tx *= tw;
ty *= tw;
tz *= tw;
// gBox.rotationY += 0.1;
var tx:Number, ty:Number, tz:Number, tw:Number;
var mx:Number, my:Number, mz:Number, mw:Number;
var kx:Number, ky:Number, kz:Number, kw:Number;z
var t:Number;
mx = 0; my = -100; mz = 0;
kx = 0; ky = 500; kz = 0;
t = linePlaneTest(kx, ky,kz, tx,ty,tz, 0,200,0, 0,-1,0 );
gBox.x = kx + (tx - kx) * t;
gBox.y = ky + (ty - ky) * t;
gBox.z = kz + (tz - kz) * t;
*/
// camz = -1000;
var umx:Number;
var umy:Number;
var t:Number;
var kx:Number, ky:Number, kz:Number;
//alternativa camera fov is by default is 1.57 .. aka 90 ... which is actually 60 (what in the flying f
umx = ((stage.mouseX / 400)-0.5)*2;//*1.46;
umy = ((stage.mouseY / 400)-0.5)*2;//*1.46;
myFrust.setPoint(camx, camy, camz, ori, umx, umy);
// myFrust.setPoint(0, -200, 0, testOri, umx, umy);
t = linePlaneTest(myFrust.sax, myFrust.say, myFrust.saz,
myFrust.sbx, myFrust.sby, myFrust.sbz, 0,200,0, 0,-1,0 );
debText.text = "t " + t;
debText.appendText("\n mx " +stage.mouseX + " my " + stage.mouseY);
debText.appendText("\n umx " + umx + "\n umy " +umy);
kx = myFrust.sax + (myFrust.sbx - myFrust.sax) * t;
ky = myFrust.say + (myFrust.sby - myFrust.say) * t;
kz = myFrust.saz + (myFrust.sbz - myFrust.saz) * t;
var i:Number;
var m:Mesh;
for (i = 0; i < 10; i++)
{
m = vecLine[i];
m.x = myFrust.sax + (myFrust.sbx - myFrust.sax) * (i*0.1);
m.y = myFrust.say + (myFrust.sby - myFrust.say) * (i*0.1);
m.z = myFrust.saz + (myFrust.sbz - myFrust.saz) * (i*0.1);
}//nexti
gBox.x = kx;
gBox.y = ky;
gBox.z = kz;
// res = View.get3DCoords(p, 40, null);
/*
gBox.x = res.x;
gBox.y = res.y;
gBox.z = res.z;
*/
ori.setMatrix(mat);
mat.appendTranslation(camx,camy,camz);
cam.matrix = mat;
cam.render();
}//onenter
// public var res:Point3D;
// public var p:Point;
public function kdown(e:KeyboardEvent):void
{
cKeyMan.setKey(e.keyCode, true);
}//kdown
public function kup(e:KeyboardEvent):void
{
cKeyMan.setKey(e.keyCode, false);
}//kup
public function linePlaneTest(
ax:Number, ay:Number, az:Number,
bx:Number, by:Number, bz:Number,
px:Number, py:Number, pz:Number,
nx:Number, ny:Number, nz:Number):Number
{
var dx:Number, dy:Number, dz:Number;
var vx:Number, vy:Number, vz:Number;
var ndotv:Number;
vx = bx - ax;
vy = by - ay;
vz = bz - az;
dx = px - ax;
dy = py - ay;
dz = pz - az;
ndotv = (vx *nx) + (vy*ny)+(vz*nz);
if (ndotv == 0) {return -99999;} //parallel -- no inter
return ((nx*dx)+(ny*dy)+(nz*dz)) / ndotv;
}//lineplane
public function setProjectionMatrix(
vec:Vector.<Number>,
fovdeg:Number = 90.0,
aspect:Number=1.0, nearp:Number = 1.0, farp:Number=1000.0):void
{
var f:Number;
var i:int;
for (i = 0; i < 16; i++) { vec[i] = 0.0; }
f = 1.0 / Math.tan( (fovdeg * (3.1415 / 180.0)) * 0.5 );
if (nearp == 0) { nearp = 0.0001; }
if (farp == 0) { farp = 0.0001; }
vec[0] = f / aspect;
vec[5] = f;
vec[10] = (farp + nearp) / (nearp - farp);
vec[14] = (2.0 * farp * nearp) / (nearp - farp);
vec[11] = -1.0;
vec[15] = 0.0;
}//projmatrix
public function setLookAtMatrix(
vec:Vector.<Number>,
cx:Number, cy:Number, cz:Number,
qx:Number, qy:Number, qz:Number, qw:Number):void
{
var forwx:Number; var forwy:Number; var forwz:Number;
var sidex:Number; var sidey:Number; var sidez:Number;
var upx:Number; var upy:Number; var upz:Number;
var i:int;
for (i = 0; i < 16; i++) { vec[i] = 0.0; }
forwx = 2.0 * ( qx*qz + qy*qw );
forwy = 2.0 * ( qy*qz - qx*qw );
forwz = 1.0 - 2.0 * ( qx*qx + qy*qy );
upx = 2.0 * ( qx*qy - qz*qw );
upy = 1.0 - 2.0 * ( qx*qx + qz*qz );
upz = 2.0 * ( qy * qz + qx * qw );
sidex = 1.0 - 2.0 * ( qy*qy + qz*qz );
sidey = 2.0 * ( qx*qy + qz*qw );
sidez = 2.0 * ( qx * qz - qy * qw );
vec[0] = vec[5] = vec[10] = vec[15] = 1.0;
vec[0] = sidex; vec[4] = sidey; vec[8] = sidez;
vec[1] = upx; vec[5] = upy; vec[9] = upz;
vec[2] = -forwx; vec[6] = -forwy; vec[10] = -forwz;
vec[12] = (sidex *-cx) + (sidey * -cy) + (sidez * -cz);
vec[13] = (upx *-cx) + (upy * -cy) + (upz * -cz);
vec[14] = (-forwx *-cx) + (-forwy * -cy) + (-forwz * -cz);
}//setlookat
}//flashtest
}
import flash.geom.Matrix3D;//package
internal class cKeyMan
{
public function cKeyMan() {}//ctor (unused)
public static var vecKey:Vector.<Boolean> = new Vector.<Boolean>(512,true);
public static function setKey(k:int, b:Boolean):void
{
if (k < 0) return;
if (k >= 512) return;
vecKey[k] = b;
}//setkey
public static function isKeyDown(k:int):Boolean
{
if (k < 0) return false;
if (k >= 512) return false;
return vecKey[k];
}//iskey
}//keyman
internal class cQuat
{
public var x:Number = 0;
public var y:Number = 0;
public var z:Number = 0;
public var w:Number = 1;
public function cQuat()
{}//ctor
public function reset():void
{ x = 0; y = 0; z = 0; w = 1; }
public function copyQuat(q:cQuat):void
{ x = q.x; y = q.y; z = q.z; w = q.w; }
public function invert():void
{ x = -x; y = -y; z = -z; }
public function normalise():void
{
var mag:Number;
mag = x*x + y*y + z*z + w*w;
if (mag == 1.0) {return;}
if (mag == 0.0) {x=0;y=0;z=0;w=1; return;}
mag = 1.0 / Math.sqrt(mag);
x*= mag;
y*= mag;
z*= mag;
w*= mag;
}//normal
//multiply with other quaternion
public function mul(b:cQuat):void
{
var tx:Number;
var ty:Number;
var tz:Number;
var tw:Number;
tx = (w*b.x + x*b.w + y*b.z - z*b.y),
ty = (w*b.y + y*b.w + z*b.x - x*b.z),
tz = (w*b.z + z*b.w + x*b.y - y*b.x),
tw = (w*b.w - x*b.x - y*b.y - z*b.z);
x = tx;
y = ty;
z = tz;
w = tw;
}//mul
public function mulq(px:Number, py:Number, pz:Number, pw:Number):void
{
var tx:Number;
var ty:Number;
var tz:Number;
var tw:Number;
tx = (w*px + x*pw + y*pz - z*py),
ty = (w*py + y*pw + z*px - x*pz),
tz = (w*pz + z*pw + x*py - y*px),
tw = (w*pw - x*px - y*py - z*pz);
x = tx;
y = ty;
z = tz;
w = tw;
}//mulq
//rotate pitch by angle (in radian)
public function rotPitch(ang:Number):void
{
ang *= 0.5;
mulq(Math.sin(ang),0,0, Math.cos(ang));
normalise();
}//rotpitch
public function rotYaw(ang:Number):void
{
ang *= 0.5;
mulq(0,Math.sin(ang),0, Math.cos(ang));
normalise();
}//rotyaw
public function rotRoll(ang:Number):void
{
ang *= 0.5;
mulq(0,0,Math.sin(ang), Math.cos(ang));
normalise();
}//rotpitch
public static var tempVec:Vector.<Number> = new Vector.<Number>(16,true);
public function setMatrix(m:Matrix3D):void
{
var xx:Number = x * x;
var xy:Number = x * y;
var xz:Number = x * z;
var xw:Number = x * w;
var yy:Number = y * y;
var yz:Number = y * z;
var yw:Number = y * w;
var zz:Number = z * z;
var zw:Number = z * w;
tempVec[3] = tempVec[7] = tempVec[11] = tempVec[12] = tempVec[13] = tempVec[14] = 0.0;
tempVec[15] = 1.0;
tempVec[0] = 1.0 - 2.0 * ( yy + zz );
tempVec[4] = 2.0 * ( xy - zw );
tempVec[8] = 2.0 * ( xz + yw );
tempVec[1] = 2.0 * ( xy + zw ) ;
tempVec[5] = 1.0 - 2.0 * ( xx + zz ) ;
tempVec[9] = 2.0 * ( yz - xw ) ;
tempVec[2] = 2.0 * ( xz - yw );
tempVec[6] = 2.0 * ( yz + xw );
tempVec[10] = 1.0 - 2.0 * ( xx + yy );
m.rawData = tempVec;
}//setmatrix
public function getSideVx():Number
{ return 1.0 - 2.0 * ( y * y + z * z ); }
public function getSideVy():Number
{ return 2.0 * ( x * y + z * w ); }
public function getSideVz():Number
{ return 2.0 * ( x * z - y * w ); }
public function getUpVx():Number
{ return 2.0 * ( x*y - z*w ); }
public function getUpVy():Number
{ return 1.0 - 2.0 * ( x*x + z*z ); }
public function getUpVz():Number
{ return 2.0 * ( y*z + x*w ); }
public function getFrontVx():Number
{ return 2.0 * ( x*z + y*w ); }
public function getFrontVy():Number
{ return 2.0 * ( y*z - x*w ); }
public function getFrontVz():Number
{ return 1.0 - 2.0 * ( x*x + y*y ); }
}//cquat
internal class cFrustum
{
public function cFrustum()
{}//ctor
public var nearWidth:Number, nearHeight:Number;
public var farWidth:Number, farHeight:Number;
public var fov:Number;
public var aspect:Number;
public var nearDist:Number, farDist:Number;
public function setPersp(fov_:Number= 90, aspect_:Number=1.33, nearDist_:Number=1, farDist_:Number=300):void
{
fov = fov_;
aspect = aspect_;
nearDist = nearDist_;
farDist = farDist_;
var tang:Number;
fov_ *= 3.1415 / 180.0 //torad
tang = Math.tan(fov_ * 0.5);
nearHeight = nearDist * tang;
nearWidth = nearHeight * aspect;
farHeight = farDist * tang;
farWidth = farHeight * aspect;
}//setpersp
public var sax:Number = 0;
public var say:Number = 0;
public var saz:Number = 0;
public var sbx:Number = 0;
public var sby:Number = 0;
public var sbz:Number = 0;
//m -0.5 - 0.5
public function setPoint(cx:Number, cy:Number, cz:Number, cq:cQuat, umx:Number, umy:Number):void
{
var fx:Number, fy:Number, fz:Number;
var sx:Number, sy:Number, sz:Number;
var ux:Number, uy:Number, uz:Number;
var frontx:Number, fronty:Number, frontz:Number;
var nearx:Number, neary:Number, nearz:Number;
var farupx:Number, farupy:Number, farupz:Number;
var farsidex:Number, farsidey:Number, farsidez:Number;
var nearupx:Number, nearupy:Number, nearupz:Number;
var nearsidex:Number, nearsidey:Number, nearsidez:Number;
var nh:Number, nw:Number, fh:Number, fw:Number;
fx = cq.getFrontVx();
fy = cq.getFrontVy();
fz = cq.getFrontVz();
sx = cq.getSideVx();
sy = cq.getSideVy();
sz = cq.getSideVz();
ux = cq.getUpVx();
uy = cq.getUpVy();
uz = cq.getUpVz();
nh = nearHeight;
nw = nearWidth;
fh = farHeight;
fw = farWidth;
farupx = ux * fh;
farupy = uy * fh;
farupz = uz * fh;
farsidex = sx * fw;
farsidey = sy * fw;
farsidez = sz * fw;
nearupx = ux * nh;
nearupy = uy * nh;
nearupz = uz * nh;
nearsidex = sx * nw;
nearsidey = sy * nw;
nearsidez = sz * nw;
frontx = cx + fx * farDist;
fronty = cy + fy * farDist;
frontz = cz + fz * farDist;
sbx = frontx + (farupx * umy) + (farsidex * umx);
sby = fronty + (farupy * umy) + (farsidey * umx);
sbz = frontz + (farupz * umy) + (farsidez * umx);
nearx = cx + fx * nearDist;
neary = cy + fy * nearDist;
nearz = cz + fz * nearDist;
sax = nearx + (nearupx * umy) + (nearsidex * umx);
say = neary + (nearupy * umy) + (nearsidey * umx);
saz = nearz + (nearupz * umy) + (nearsidez * umx);
}//setpoint
}//cfrust