fc2ブログ

ビュー変換行列

2008-03-07 | 21:47

上下左右キーでカメラ一が移動します。
(カメラが移動しても視線は原点を向いているという設定です)

カメラの向いている方向をである視線ベクトルをE、カメラの上向きのベクトルをU、EUに直行するベクトル(EをZ軸、UをY軸とした時のX軸)をX、カメラの位置をPとすると、ビュー変換行列は
で表される。

(カメラ座標を基底に持つ回転行列は
なので、ワールド座標をカメラ座標に変換するためにはその逆行列である
を掛ける。(回転行列の逆行列はその転置行列))
package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

    import org.papervision3d.core.*;
    import org.papervision3d.core.geom.*;
    import org.papervision3d.core.math.*;
    [SWF(width="600", height="400", frameRate="10", backgroundColor="#ffffff")]
        public class ViewMatrix extends Sprite{
            private var LEN:int = 80;
            private var initialPoints:Array = 
                [new Number3D(LEN, +LEN, LEN),
                new Number3D(LEN, +LEN, -LEN),
                new Number3D(-LEN, +LEN, -LEN),
                new Number3D(-LEN, +LEN, LEN),
                new Number3D(LEN, -LEN, LEN),
                new Number3D(LEN, -LEN, -LEN),
                new Number3D(-LEN, -LEN, -LEN),
                new Number3D(-LEN, -LEN, LEN)
                    ];
            private var initialPoints2:Array = 
                [new Number3D(LEN + 200, +LEN, LEN),
                new Number3D(LEN + 200, +LEN, -LEN),
                new Number3D(-LEN + 200, +LEN, -LEN),
                new Number3D(-LEN + 200, +LEN, LEN),
                new Number3D(LEN + 200, -LEN, LEN),
                new Number3D(LEN + 200, -LEN, -LEN),
                new Number3D(-LEN + 200, -LEN, -LEN),
                new Number3D(-LEN + 200, -LEN, LEN)
                    ];

            // 射影変換行列
            private var m:Matrix3D = new Matrix3D();
            // ビュー変換行列
            private var vm:Matrix3D = new Matrix3D();

            private var cameraPos:Number3D = new Number3D();

            public function ViewMatrix():void
            {
                var r:Number = 500;
                var l:Number = -500;
                var t:Number = 500;
                var b:Number = -500;
                var n:Number = 500;
                var f:Number = 1000;
                m.n11 = 2*n/(r-l);
                m.n13 = (r+l)/(r-l);
                m.n22 = 2*n/(t-b);
                m.n23 = (t+b)/(t-b);
                m.n33 = -(f+n)/(f-n);
                m.n34 = -2*n*f/(f-n);
                m.n43 = -1;

                cameraPos.z = -50;

                drawCube(initialPoints);
                drawCube(initialPoints2);

                stage.addEventListener(KeyboardEvent.KEY_DOWN , keyDown);
            }

            private function keyDown(e:*):void{
                switch (e.keyCode){
                    case 37 :// ←
                        cameraPos.x--
                        break;
                    case 39 :// →
                        cameraPos.x++
                        break;
                    case 38 :// ↑
                        cameraPos.y++
                        break;
                    case 40 :// ↓
                        cameraPos.y--;
                        break;
                }
                // カメラ視点ベクトル
                var cev:Number3D = new Number3D(-cameraPos.x, -cameraPos.y, -cameraPos.z);
                cev.normalize();

                var cxv :Number3D = Number3D.cross( cev, new Number3D(0,1,0));
				cxv.normalize();
	
                var cuv :Number3D = Number3D.cross( cxv, cev);
				cuv.normalize();

                vm.n11 = cxv.x;
                vm.n12 = cxv.y;
                vm.n13 = cxv.z;
                vm.n14 = -Number3D.dot(cameraPos, cxv);
                vm.n21 = cuv.x;
                vm.n22 = cuv.y;
                vm.n23 = cuv.z;
                vm.n24 = -Number3D.dot(cameraPos, cuv);
                vm.n31 = cev.x;
                vm.n32 = cev.y;
                vm.n33 = cev.z;
                vm.n34 = -Number3D.dot(cameraPos, cev);

                graphics.clear();
                drawCube(initialPoints);
                drawCube(initialPoints2);
            }
            
            private function drawCube(points:Array):void{

                var points2D:Array = [];
                for each(var pp:Number3D in points){
                    var p:Number3D = pp.clone();

                    var point:Point = convertPoint(p);

                    points2D.push(p);
                }

                graphics.lineStyle(3,0,0.8);
                graphics.drawCircle(points2D[0].x, points2D[0].y, 5);
                graphics.moveTo(points2D[0].x, points2D[0].y);
                for (var i:int = 1 ; i < 4; i++){
                    graphics.lineTo(points2D[i].x, points2D[i].y);
                }
                graphics.lineTo(points2D[0].x, points2D[0].y);

                graphics.moveTo(points2D[4].x, points2D[4].y);
                for (i = 5 ; i < 8; i++){
                    graphics.lineTo(points2D[i].x, points2D[i].y);
                }
                graphics.lineTo(points2D[4].x, points2D[4].y);
                
                for (i = 0 ; i < 4; i++){
                    graphics.moveTo(points2D[i].x, points2D[i].y);
                    graphics.lineTo(points2D[i+4].x, points2D[i+4].y);
                }

                // draw x axis
                graphics.lineStyle(2,0xff0000,0.8);
                var p1:Point = convertPoint(new Number3D(-300, 0,0));
                var p2:Point = convertPoint(new Number3D(300, 0,0));
                graphics.moveTo(p1.x, p1.y);
                graphics.lineTo(p2.x, p2.y);

                graphics.lineStyle(2,0xff,0.8);
                p1= convertPoint(new Number3D(0, 300,0));
                p2= convertPoint(new Number3D(0, -300,0));
                graphics.moveTo(p1.x, p1.y);
                graphics.lineTo(p2.x, p2.y);


                graphics.lineStyle(2,0xff00,0.8);
                p1= convertPoint(new Number3D(0, 0, 300));
                p2= convertPoint(new Number3D(0, 0, -300));
                graphics.moveTo(p1.x, p1.y);
                graphics.lineTo(p2.x, p2.y);

            }

            private function convertPoint(p:Number3D):Point{
                // apply view matrix
                Matrix3D.multiplyVector(vm,p);

                // convert to 2D point
                Matrix3D.multiplyVector(m,p);

                p.x += 300; p.y = 200 - p.y;

                return new Point(p.x, p.y);
            }
        }
}

スポンサーサイト