PrspctvPrjctn
PerspectiveProjectionと
同じ計算をするクラスを作るとしたら
こんなかんじかな。
値がぴったり一致しないのは、
ビルトインクラス側では三角関数をMathではなく、
別なものから求めているからなんじゃないかな、、、。
/**
* Copyright umhr ( http://wonderfl.net/user/umhr )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/iPa6
*/
/*
PerspectiveProjectionと
同じ計算をするクラスを作るとしたら
こんなかんじかな。
値がぴったり一致しないのは、
ビルトインクラス側では三角関数をMathではなく、
別なものから求めているからなんじゃないかな、、、。
*/
package
{
import flash.display.Sprite;
import flash.geom.PerspectiveProjection;
import flash.geom.Point;
import flash.text.TextField;
public class Main extends Sprite
{
public function Main()
{
var pp1:PerspectiveProjection = new PerspectiveProjection();
var pp2:PrspctvPrjctn = new PrspctvPrjctn();
var pp1txt:String = "ビルトインクラスの\nPerspectiveProjection\n\nデフォルト値\n";
var pp2txt:String = "カスタムクラスの\nPrspctvPrjctn\n\nデフォルト値\n";
pp1txt += "fieldOfView : "+pp1.fieldOfView+"\n";
pp1txt += "focalLength : "+pp1.focalLength+"\n";
pp1txt += "projectionCenter : "+pp1.projectionCenter+"\n";
pp2txt += "fieldOfView : "+pp2.fieldOfView+"\n";
pp2txt += "focalLength : "+pp2.focalLength+"\n";
pp2txt += "projectionCenter : "+pp2.projectionCenter+"\n";
var random:Number = Math.random();
pp1.fieldOfView = pp2.fieldOfView = 180*random;
pp1txt += "\nfieldOfViewに値を入れてみる\n";
pp1txt += "fieldOfView = "+180*random+"\n";
pp2txt += "\nfieldOfViewに値を入れてみる\n";
pp2txt += "fieldOfView = "+180*random+"\n";
pp1txt += "focalLength : "+pp1.focalLength+"\n";
pp1txt += "projectionCenter : "+pp1.projectionCenter+"\n";
pp2txt += "focalLength : "+pp2.focalLength+"\n";
pp2txt += "projectionCenter : "+pp2.projectionCenter+"\n";
random = Math.random();
pp1.focalLength = pp2.focalLength = 2000*random;
pp1txt += "\nfocalLengthに値を入れてみる\n";
pp1txt += "focalLength = "+2000*random+"\n";
pp2txt += "\nfocalLengthに値を入れてみる\n";
pp2txt += "focalLength = "+2000*random+"\n";
pp1txt += "fieldOfView : "+pp1.fieldOfView+"\n";
pp1txt += "projectionCenter : "+pp1.projectionCenter+"\n";
pp2txt += "fieldOfView : "+pp2.fieldOfView+"\n";
pp2txt += "projectionCenter : "+pp2.projectionCenter+"\n";
random = Math.random();
var randomy:Number = Math.random();
pp1.projectionCenter = pp2.projectionCenter = new Point(random*1000,randomy*1000);
pp1txt += "\nprojectionCenterに値を入れてみる\n";
pp1txt += "projectionCenter = new Point("+random*1000+","+randomy*1000+")\n";
pp2txt += "\nprojectionCenterに値を入れてみる\n";
pp2txt += "projectionCenter = new Point("+random*1000+","+randomy*1000+")\n";
pp1txt += "fieldOfView : "+pp1.fieldOfView+"\n";
pp1txt += "focalLength : "+pp1.focalLength+"\n";
pp2txt += "fieldOfView : "+pp2.fieldOfView+"\n";
pp2txt += "focalLength : "+pp2.focalLength+"\n";
pp1txt += "toMatrix3D().rawData : "+pp1.toMatrix3D().rawData+"\n";
pp2txt += "toMatrix3D().rawData : "+pp2.toMatrix3D().rawData+"\n";
var tf1:TextField = new TextField();
tf1.width = 465/2;
tf1.height = 465;
tf1.text = pp1txt;
tf1.wordWrap = true;
this.addChild(tf1);
var tf2:TextField = new TextField();
tf2.width = 232;
tf2.height = 465;
tf2.text = pp2txt;
tf2.wordWrap = true;
tf2.x =233;
this.addChild(tf2);
}
}
}
import flash.geom.Point;
class PrspctvPrjctn{
private var _fieldOfView:Number = 55;
private var _focalLength:Number = 250/Math.tan(_fieldOfView*0.008726646259971648);
private var _projectionCenter:Point = new Point(250,250);
public function PrspctvPrjctn(){
}
public function get fieldOfView():Number{return _fieldOfView};
public function set fieldOfView(value:Number):void{
if(value<0 || 180<value){
return;
}
_fieldOfView = value;
_focalLength = 250/Math.tan(value*0.008726646259971648);
//0.008726646259971648 = Math.PI/360
}
public function get focalLength():Number{return _focalLength};
public function set focalLength(value:Number):void{
if(value<0){
return;
}
_focalLength = value;
_fieldOfView = Math.atan2(250,value)*114.59155902616465;
//114.59155902616465 = 360/Math.PI
}
public function get projectionCenter():Point{return _projectionCenter};
public function set projectionCenter(value:Point):void{
_projectionCenter = value.clone();
}
public function toMatrix3D():Mtrx3D{
return new Mtrx3D([_focalLength,0,0,0,0,_focalLength,0,0,0,0,1,1,0,0,0,0]);
}
}
//Matrix3D的なもの
class Mtrx3D {
private var _rawData:Array = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
//コンストラクタ
public function Mtrx3D(v:Array = null) {
if (v) {
_rawData = v.concat();
}
}
//プロパティ
public function get determinant():Number{
//余因子(cofactor)を作る
var d:Number = _rawData[0]*sarrus([_rawData[5],_rawData[9],_rawData[13],_rawData[6],_rawData[10],_rawData[14],_rawData[7],_rawData[11],_rawData[15]]);
//dはdeterminantから
d -= _rawData[1]*sarrus([_rawData[4],_rawData[8],_rawData[12],_rawData[6],_rawData[10],_rawData[14],_rawData[7],_rawData[11],_rawData[15]]);
d += _rawData[2]*sarrus([_rawData[4],_rawData[8],_rawData[12],_rawData[5],_rawData[9],_rawData[13],_rawData[7],_rawData[11],_rawData[15]]);
d -= _rawData[3]*sarrus([_rawData[4],_rawData[8],_rawData[12],_rawData[5],_rawData[9],_rawData[13],_rawData[6],_rawData[10],_rawData[14]]);
d -= ((_rawData[4]-_rawData[8])*_rawData[1]+(_rawData[9]-_rawData[5])*_rawData[0])*_rawData[11]*_rawData[14];
return -d;
function sarrus(c:Array):Number{
//cはcofactorから
//サルス(Sarrus)の公式(関-サルスの公式)
return c[0]*c[4]*c[8]+c[3]*c[7]*c[2]+c[6]*c[1]*c[5]
-c[6]*c[4]*c[2]-c[3]*c[1]*c[8]-c[0]*c[7]*c[5];
}
}
public function get position():Vctr3D{
return new Vctr3D(_rawData[12],_rawData[13],_rawData[14]);
}
public function set position(v:Vctr3D):void{
_rawData[12] = v.x;
_rawData[13] = v.y;
_rawData[14] = v.z;
}
public function get rawData():Array { return _rawData };
public function set rawData(value:Array):void {
_rawData = value.concat();
}
//メソッド
public function append(lhs:Mtrx3D):void {
_rawData = matrix44Calculat(_rawData,lhs.rawData);
}
public function appendRotation(degrees:Number,axis:Vctr3D,pivotPoint:Vctr3D=null):void {
if(!pivotPoint){
pivotPoint = new Vctr3D(0, 0, 0);
}
var tempAxis:Vctr3D = axis.clone();
//AXIS_ANGLE to QUATERNION
var degreesPIper360:Number = degrees / 360 * Math.PI;
var w:Number = Math.cos(degreesPIper360);
var x:Number = Math.sin(degreesPIper360) * tempAxis.x;
var y:Number = Math.sin(degreesPIper360) * tempAxis.y;
var z:Number = Math.sin(degreesPIper360) * tempAxis.z;
//rawData from QUATERNION
var p:Array = rawDataFromQuaternion(x, y, z, w);
//Matrix * entity
_rawData = matrix44Calculat(_rawData, p);
appendTranslation(pivotPoint.x,pivotPoint.y,pivotPoint.z);
}
public function appendScale(xScale:Number,yScale:Number,zScale:Number):void {
_rawData[0]*=xScale;
_rawData[1]*=yScale;
_rawData[2]*=zScale;
_rawData[4]*=xScale;
_rawData[5]*=yScale;
_rawData[6]*=zScale;
_rawData[8]*=xScale;
_rawData[9]*=yScale;
_rawData[10]*=zScale;
_rawData[12]*=xScale;
_rawData[13]*=yScale;
_rawData[14]*=zScale;
}
public function appendTranslation(x:Number, y:Number, z:Number):void{
_rawData[12] += x;
_rawData[13] += y;
_rawData[14] += z;
}
public function clone():Mtrx3D {
return new Mtrx3D(_rawData);
}
public function decompose(orientationStyle:String = "eulerAngles"):Array{
var e:Array = _rawData.concat();
//prependScale的処理
var vec:Array = matrix3dToEulerAnglePrepend(e);
if(orientationStyle != "eulerAngles"){
vec = matrix3dToQuaternion(e,vec[2],orientationStyle);
}
return vec;
}
private function matrix3dToQuaternion(e:Array,scale:Vctr3D,orientationStyle:String):Array{
if(scale.x > 0){
e[0]/=scale.x;
e[4]/=scale.x;
e[8]/=scale.x;
}
if(scale.y > 0){
e[1]/=scale.y;
e[5]/=scale.y;
e[9]/=scale.y;
}
if(scale.z > 0){
e[2]/=scale.z;
e[6]/=scale.z;
e[10]/=scale.z;
}
var w:Number;
var x:Number;
var y:Number;
var z:Number;
var _ar:Array = new Array(e[0]+e[5]+e[10],e[0]-e[5]-e[10],e[5]-e[0]-e[10],e[10]-e[0]-e[5]);
var biggestIndex:int = _ar.sort(Array.NUMERIC|Array.RETURNINDEXEDARRAY|Array.DESCENDING)[0];
var biggestVal:Number = Math.sqrt(_ar[biggestIndex]+1)*0.5;
var mult:Number = 0.25/biggestVal;
switch (biggestIndex) {
case 0:
w = biggestVal;
x = (e[6]-e[9])*mult;
y = (e[8]-e[2])*mult;
z = (e[1]-e[4])*mult;
break;
case 1:
x = biggestVal;
w = (e[6]-e[9])*mult;
y = (e[4]+e[1])*mult;
z = (e[2]+e[8])*mult;
break;
case 2:
y = biggestVal;
w = (e[8]-e[2])*mult;
x = (e[4]+e[1])*mult;
z = (e[9]+e[6])*mult;
break;
case 3:
z = biggestVal;
w = (e[1]-e[4])*mult;
x = (e[2]+e[8])*mult;
y = (e[9]+e[6])*mult;
break;
}
if(orientationStyle == "axisAngle"){
if(Math.sin(Math.acos(w)) != 0){
x = x/Math.sin(Math.acos(w));
y = y/Math.sin(Math.acos(w));
z = z/Math.sin(Math.acos(w));
w = 2*Math.acos(w);
}else{
x = y = z= w = 0;
}
}
return [new Vctr3D(e[12],e[13],e[14]),new Vctr3D(x,y,z,w),scale];
}
private function matrix3dToEulerAnglePrepend(e:Array):Array{
var _z:Number = Math.atan2(e[1],e[0]);
var sz:Number = Math.sin(_z);
var cz:Number = Math.cos(_z);
var _y:Number;
if(Math.abs(cz) > 0.7){
_y = Math.atan2(-e[2],e[0]/cz);
}else{
_y = Math.atan2(-e[2],e[1]/sz);
}
var sy:Number = Math.sin(_y);
var cy:Number = Math.cos(_y);
var _x:Number;
if(Math.abs(cz) > 0.7){
_x = Math.atan2((sy*sz-e[9]*cy/e[10]),cz);
}else{
_x = Math.atan2((e[8]*cy/e[10]-sy*cz)/sz,1);
}
//_x = Math.atan2((sy*sz-e[9]*cy/e[10])/cz,1);
//_x = Math.atan2((e[8]*cy/e[10]-sy*cz)/sz,1);
var sx:Number = Math.sin(_x);
var cx:Number = Math.cos(_x);
var scale_x:Number = -e[2]/sy;
var scale_y:Number = e[6]/(sx*cy);
var scale_z:Number = e[10]/(cx*cy);
return [new Vctr3D(e[12], e[13], e[14]), new Vctr3D(_x, _y, _z), new Vctr3D(scale_x, scale_y, scale_z)];
}
public function deltaTransformVector(v:Vctr3D):Vctr3D {
var e:Array = _rawData;
return new Vctr3D((e[0]*v.x+e[4]*v.y+e[8]*v.z),(e[1]*v.x+e[5]*v.y+e[9]*v.z),(e[2]*v.x+e[6]*v.y+e[10]*v.z),(e[3]*v.x+e[7]*v.y+e[11]*v.z));
}
public function identity():void {
_rawData=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];
}
public function interpolate(thisMat:Mtrx3D,toMat:Mtrx3D,percent:Number):Mtrx3D{
var v0:Vctr3D = thisMat.decompose("quaternion")[1];
var v1:Vctr3D = toMat.decompose("quaternion")[1];
var cosOmega:Number = v0.w*v1.w + v0.x*v1.x + v0.y*v1.y + v0.z*v1.z;
if(cosOmega < 0){
v1.x = -v1.x;
v1.y = -v1.y;
v1.z = -v1.z;
v1.w = -v1.w;
cosOmega = -cosOmega;
}
var k0:Number;
var k1:Number;
if(cosOmega > 0.9999){
k0 = 1 - percent;
k1 = percent;
}else{
var sinOmega:Number = Math.sqrt(1 - cosOmega*cosOmega);
var omega:Number = Math.atan2(sinOmega,cosOmega);
var oneOverSinOmega:Number = 1/sinOmega;
k0 = Math.sin((1-percent)*omega)*oneOverSinOmega;
k1 = Math.sin(percent*omega)*oneOverSinOmega;
}
var scale_x:Number = thisMat.decompose("quaternion")[2].x*(1-percent) + toMat.decompose("quaternion")[2].x*percent;
var scale_y:Number = thisMat.decompose("quaternion")[2].y*(1-percent) + toMat.decompose("quaternion")[2].y*percent;
var scale_z:Number = thisMat.decompose("quaternion")[2].z*(1-percent) + toMat.decompose("quaternion")[2].z*percent;
var tx:Number = thisMat.decompose("quaternion")[0].x*(1-percent) + toMat.decompose("quaternion")[0].x*percent;
var ty:Number = thisMat.decompose("quaternion")[0].y*(1-percent) + toMat.decompose("quaternion")[0].y*percent;
var tz:Number = thisMat.decompose("quaternion")[0].z*(1-percent) + toMat.decompose("quaternion")[0].z*percent;
var x:Number = v0.x*k0+v1.x*k1;
var y:Number = v0.y*k0+v1.y*k1;
var z:Number = v0.z*k0+v1.z*k1;
var w:Number = v0.w * k0 + v1.w * k1;
var _q:Array = rawDataFromQuaternion(x, y, z, w);
_q[12] = tx;
_q[13] = ty;
_q[14] = tz;
//var v:Vctr3D = new Vctr3D(v0.x*k0+v1.x*k1,v0.y*k0+v1.y*k1,v0.z*k0+v1.z*k1,v0.w*k0+v1.w*k1);
//var txyz:Vector3D = new Vector3D(tx,ty,tz);
//var m:Matrix3D=new Matrix3D();
//m.recompose(Vector.<Vector3D>([txyz,v,new Vector3D(scale_x,scale_y,scale_z)]),"quaternion");
//trace(m.rawData);
return new Mtrx3D(_q);
}
public function interpolateTo():* {
//未実装
}
public function invert():Boolean {
var e:Array = _rawData;
var a:Array=new Array(16);
//aはadjugateから
a[0]=sarrus([e[5],e[9],e[13],e[6],e[10],e[14],e[7],e[11],e[15]]);
a[1]=- sarrus([e[4],e[8],e[12],e[6],e[10],e[14],e[7],e[11],e[15]]);
a[2]=sarrus([e[4],e[8],e[12],e[5],e[9],e[13],e[7],e[11],e[15]]);
a[3]=- sarrus([e[4],e[8],e[12],e[5],e[9],e[13],e[6],e[10],e[14]]);
a[4]=- sarrus([e[1],e[9],e[13],e[2],e[10],e[14],e[3],e[11],e[15]]);
a[5]=sarrus([e[0],e[8],e[12],e[2],e[10],e[14],e[3],e[11],e[15]]);
a[6]=- sarrus([e[0],e[8],e[12],e[1],e[9],e[13],e[3],e[11],e[15]]);
a[7]=sarrus([e[0],e[8],e[12],e[1],e[9],e[13],e[2],e[10],e[14]]);
a[8]=sarrus([e[1],e[5],e[13],e[2],e[6],e[14],e[3],e[7],e[15]]);
a[9]=- sarrus([e[0],e[4],e[12],e[2],e[6],e[14],e[3],e[7],e[15]]);
a[10]=sarrus([e[0],e[4],e[12],e[1],e[5],e[13],e[3],e[7],e[15]]);
a[11]=- sarrus([e[0],e[4],e[12],e[1],e[5],e[13],e[2],e[6],e[14]]);
a[12]=- sarrus([e[1],e[5],e[9],e[2],e[6],e[10],e[3],e[7],e[11]]);
a[13]=sarrus([e[0],e[4],e[8],e[2],e[6],e[10],e[3],e[7],e[11]]);
a[14]=- sarrus([e[0],e[4],e[8],e[1],e[5],e[9],e[3],e[7],e[11]]);
a[15]=sarrus([e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]]);
var d:Number=e[0]*a[0]+e[1]*a[1]+e[2]*a[2]+e[3]*a[3];
//dはdeterminantから
if (d!=0) {
_rawData = [
a[0]/d,a[4]/d,a[8]/d,a[12]/d,
a[1]/d,a[5]/d,a[9]/d,a[13]/d,
a[2]/d,a[6]/d,a[10]/d,a[14]/d,
a[3]/d,a[7]/d,a[11]/d,a[15]/d];
}
return d != 0;
function sarrus(c:Array):Number {
//cはcofactorから
return c[0]*(c[4]*c[8]-c[5]*c[7])+
c[1]*(c[5]*c[6]-c[3]*c[8])+
c[2]*(c[3]*c[7]-c[4]*c[6]);
}
}
public function pointAt():* {
//未実装
}
public function prepend(rhs:Mtrx3D):void {
_rawData = matrix44Calculat(rhs.rawData,_rawData);
}
public function prependRotation(degrees:Number,axis:Vctr3D,pivotPoint:Vctr3D=null):void {
if(!pivotPoint){
pivotPoint = new Vctr3D(0, 0, 0);
}
var tempAxis:Vctr3D = axis.clone();
tempAxis.normalize();
//AXIS_ANGLE to QUATERNION
var degreesPIper360:Number = degrees / 360 * Math.PI;
var w:Number = Math.cos(degreesPIper360);
var x:Number = Math.sin(degreesPIper360) * tempAxis.x;
var y:Number = Math.sin(degreesPIper360) * tempAxis.y;
var z:Number = Math.sin(degreesPIper360) * tempAxis.z;
//rawData from QUATERNION
var p:Array = rawDataFromQuaternion(x, y, z, w);
//Matrix * entity
_rawData = matrix44Calculat(p, _rawData);
appendTranslation(pivotPoint.x,pivotPoint.y,pivotPoint.z);
}
public function prependScale(xScale:Number,yScale:Number,zScale:Number):void {
_rawData[0]*=xScale;
_rawData[1]*=xScale;
_rawData[2]*=xScale;
_rawData[3]*=xScale;
_rawData[4]*=yScale;
_rawData[5]*=yScale;
_rawData[6]*=yScale;
_rawData[7]*=yScale;
_rawData[8]*=zScale;
_rawData[9]*=zScale;
_rawData[10]*=zScale;
_rawData[11]*=zScale;
}
public function prependTranslation(x:Number, y:Number, z:Number):void{
_rawData[12] += _rawData[0]*x+_rawData[4]*y+_rawData[8]*z;
_rawData[13] += _rawData[1]*x+_rawData[5]*y+_rawData[9]*z;
_rawData[14] += _rawData[2]*x+_rawData[6]*y+_rawData[10]*z;
_rawData[15] += _rawData[3]*x+_rawData[7]*y+_rawData[11]*z;
}
public function recompose(components:Array, orientationStyle:String = "eulerAngles"):Boolean {
var scale:Array=new Array(16);
//prependScale的な乗算
scale[0] = scale[1] = scale[2] = components[2].x;
scale[4] = scale[5] = scale[6] = components[2].y;
scale[8] = scale[9] = scale[10] = components[2].z;
var v:Array=new Array(16);
if (orientationStyle=="eulerAngles") {
//eulerAngles to Matrix3D
var cx:Number=Math.cos(components[1].x);
var cy:Number=Math.cos(components[1].y);
var cz:Number=Math.cos(components[1].z);
var sx:Number=Math.sin(components[1].x);
var sy:Number=Math.sin(components[1].y);
var sz:Number=Math.sin(components[1].z);
v[0]=cy*cz*scale[0];
v[1]=cy*sz*scale[1];
v[2]=- sy*scale[2];
v[3]=0;
v[4] = (sx*sy*cz-cx*sz)*scale[4];
v[5] = (sx*sy*sz+cx*cz)*scale[5];
v[6]=sx*cy*scale[6];
v[7]=0;
v[8] = (cx*sy*cz+sx*sz)*scale[8];
v[9] = (cx*sy*sz-sx*cz)*scale[9];
v[10]=cx*cy*scale[10];
v[11]=0;
v[12]=components[0].x;
v[13]=components[0].y;
v[14]=components[0].z;
v[15]=1;
} else {
//"quaternion" to Matrix3D
var x:Number=components[1].x;
var y:Number=components[1].y;
var z:Number=components[1].z;
var w:Number=components[1].w;
if (orientationStyle=="axisAngle") {
//"axisAngle" to Matrix3D
x*=Math.sin(w/2);
y*=Math.sin(w/2);
z*=Math.sin(w/2);
w=Math.cos(w/2);
}
v[0] = (1-2*y*y-2*z*z)*scale[0];
v[1] = (2*x*y+2*w*z)*scale[1];
v[2] = (2*x*z-2*w*y)*scale[2];
v[3]=0;
v[4] = (2*x*y-2*w*z)*scale[4];
v[5] = (1-2*x*x-2*z*z)*scale[5];
v[6] = (2*y*z+2*w*x)*scale[6];
v[7]=0;
v[8] = (2*x*z+2*w*y)*scale[8];
v[9] = (2*y*z-2*w*x)*scale[9];
v[10] = (1-2*x*x-2*y*y)*scale[10];
v[11]=0;
v[12]=components[0].x;
v[13]=components[0].y;
v[14]=components[0].z;
v[15]=1;
}
//v[0],v[4],v[8]が三つとも0だと
//ArgumentError: Error #2188: 行マトリックスが無効です。マトリックスは反転可能である必要があります。
//というエラーでMatrix3Dを作れないので、設定可能な最小値を入れている。
//0.000000000000000000000000000000000000000000001;
//これは1e-45と書ける。
//ただしx,y,z三つとも1e-45には設定できないので、1e-15にしてる。
if(components[2].x == 0){v[0] = 1e-15};
if(components[2].y == 0){v[5] = 1e-15};
if(components[2].z == 0){v[10] = 1e-15};
_rawData = v;
//helpには拡大 / 縮小エレメントのいずれかが 0 の場合は、false を返します。
//とあるがtrueしか返さないっぽい、、
return !(components[2].x == 0 || components[2].y == 0 || components[2].y == 0)
}
public function transformVector(v:Vctr3D):Vctr3D{
var tempV:Vctr3D = new Vctr3D();
tempV.x = _rawData[0]*v.x+_rawData[4]*v.y+_rawData[8]*v.z+_rawData[12];
tempV.y = _rawData[1]*v.x+_rawData[5]*v.y+_rawData[9]*v.z+_rawData[13];
tempV.z = _rawData[2]*v.x+_rawData[6]*v.y+_rawData[10]*v.z+_rawData[14];
tempV.w = _rawData[3]*v.x+_rawData[7]*v.y+_rawData[11]*v.z+_rawData[15];
return tempV;
}
public function transformVectors(vin:Array, vout:Array):void {
var e:Array = _rawData;
var n:int=vin.length;
var temp:Array = new Array(n);
for (var i:int=0; i<n; i+=3) {
temp[i] = e[0]*vin[i]+e[4]*vin[i+1]+e[8]*vin[i+2]+e[12];
temp[i+1] = e[1]*vin[i]+e[5]*vin[i+1]+e[9]*vin[i+2]+e[13];
temp[i+2] = e[2]*vin[i]+e[6]*vin[i+1]+e[10]*vin[i+2]+e[14];
}
for (var j:int=0; j<n; j++) {
vout[j] = temp[j];
}
}
public function transpose():void {
_rawData = [
_rawData[0],_rawData[4],_rawData[8],_rawData[12],
_rawData[1],_rawData[5],_rawData[9],_rawData[13],
_rawData[2],_rawData[6],_rawData[10],_rawData[14],
_rawData[3],_rawData[7],_rawData[11],_rawData[15]
]
}
//private function
private function matrix44Calculat(e:Array,p:Array):Array {
var pe:Array = new Array();
pe[0] = p[0]*e[0]+p[4]*e[1]+p[8]*e[2]+p[12]*e[3];
pe[1] = p[1]*e[0]+p[5]*e[1]+p[9]*e[2]+p[13]*e[3];
pe[2] = p[2]*e[0]+p[6]*e[1]+p[10]*e[2]+p[14]*e[3];
pe[3] = p[3]*e[0]+p[7]*e[1]+p[11]*e[2]+p[15]*e[3];
pe[4] = p[0]*e[4]+p[4]*e[5]+p[8]*e[6]+p[12]*e[7];
pe[5] = p[1]*e[4]+p[5]*e[5]+p[9]*e[6]+p[13]*e[7];
pe[6] = p[2]*e[4]+p[6]*e[5]+p[10]*e[6]+p[14]*e[7];
pe[7] = p[3]*e[4]+p[7]*e[5]+p[11]*e[6]+p[15]*e[7];
pe[8] = p[0]*e[8]+p[4]*e[9]+p[8]*e[10]+p[12]*e[11];
pe[9] = p[1]*e[8]+p[5]*e[9]+p[9]*e[10]+p[13]*e[11];
pe[10] = p[2]*e[8]+p[6]*e[9]+p[10]*e[10]+p[14]*e[11];
pe[11] = p[3]*e[8]+p[7]*e[9]+p[11]*e[10]+p[15]*e[11];
pe[12] = p[0]*e[12]+p[4]*e[13]+p[8]*e[14]+p[12]*e[15];
pe[13] = p[1]*e[12]+p[5]*e[13]+p[9]*e[14]+p[13]*e[15];
pe[14] = p[2]*e[12]+p[6]*e[13]+p[10]*e[14]+p[14]*e[15];
pe[15] = p[3]*e[12]+p[7]*e[13]+p[11]*e[14]+p[15]*e[15];
return pe;
}
private function rawDataFromQuaternion(x:Number,y:Number,z:Number,w:Number):Array {
var p:Array = new Array(16);
p[0] = (w*w+x*x-y*y-z*z);
p[1] = 2*(y*x+w*z);
p[2] = 2*(z*x-w*y);
p[3] = 0;
p[4] = 2*(y*x-w*z);
p[5] = (w*w-x*x+y*y-z*z);
p[6] = 2*(w*x+z*y);
p[7] = 0;
p[8] = 2*(z*x+w*y);
p[9] = 2*(z*y-w*x);
p[10] = (w*w-x*x-y*y+z*z);
p[11] = 0;
p[12] = 0;
p[13] = 0;
p[14] = 0;
p[15] = 1;
return p;
}
}
class Vctr3D{
public var w:Number;
public var x:Number;
public var y:Number;
public var z:Number;
public static const X_AXIS:Vctr3D=new Vctr3D(1,0,0);
public static const Y_AXIS:Vctr3D=new Vctr3D(0,1,0);
public static const Z_AXIS:Vctr3D=new Vctr3D(0,0,1);
function Vctr3D(x:Number=0.,y:Number=0.,z:Number=0.,w:Number=0.) {
this.w=w;
this.x=x;
this.y=y;
this.z=z;
}
public function get length():Number {
return Math.sqrt(x*x+y*y+z*z);
}
public function get lengthSquared():Number {
return x*x+y*y+z*z;
}
public function add(a:Vctr3D):Vctr3D {
return new Vctr3D(a.x+x,a.y+y,a.z+z);
}
public static function angleBetween(a:Vctr3D,b:Vctr3D):Number {
return Math.acos(a.x*b.x+a.y*b.y+a.z*b.z/Math.sqrt(a.x*a.x+a.y*a.y+a.z*a.z)*Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z));
}
public function clone():Vctr3D {
return new Vctr3D(x,y,z,w);
}
public function crossProduct(a:Vctr3D):Vctr3D {
return new Vctr3D(y*a.z-z*a.y,z*a.x-x*a.z,x*a.y-y*a.x,1);
}
public function decrementBy(a:Vctr3D):void {
x-=a.x;
y-=a.y;
z-=a.z;
}
public static function distance(pt1:Vctr3D,pt2:Vctr3D):Number {
return Math.sqrt(pt1.x-pt2.x*pt1.x-pt2.x+pt1.y-pt2.y*pt1.y-pt2.y+pt1.z-pt2.z*pt1.z-pt2.z);
}
public function dotProduct(a:Vctr3D):Number {
return x*a.x+y*a.y+z*a.z;
}
public function equals(toCompare:Vctr3D,allFour:Boolean=false):Boolean {
return x==toCompare.x&&y==toCompare.y&&z==toCompare.z&&! allFour||w==toCompare.w;
}
public function incrementBy(a:Vctr3D):void {
x+=a.x;
y+=a.y;
z+=a.z;
}
public function nearEquals(toCompare:Vctr3D,tolerance:Number,allFour:Boolean=false):Boolean {
return Math.abs(x-toCompare.x)<tolerance&&Math.abs(y-toCompare.y)<tolerance&&Math.abs(z-toCompare.z)<tolerance&&! allFour||Math.abs(w-toCompare.w)<tolerance;
}
public function negate():void {
x=- x;
y=- y;
z=- z;
}
public function normalize():Number {
var _len:Number=Math.sqrt(x*x+y*y+z*z);
x/=_len;
y/=_len;
z/=_len;
return _len;
}
public function project():void {
x/=w;
y/=w;
z/=w;
}
public function scaleBy(s:Number):void {
x*=s;
y*=s;
z*=s;
}
public function subtract(a:Vctr3D):Vctr3D {
return new Vctr3D(x-a.x,y-a.y,z-a.z);
}
public function toString():String {
return "Vctr3D("+x+", "+y+", "+z+")";
}
// おまけ
public function isHiddenCrossProduct(a:Vctr3D):Boolean {
return x*a.y-y*a.x>0;
}
}