スポンサーサイト

-------- | --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

射影変換行列 + ビュー変換

2008-02-28 | 22:29


前回、透視射影変換行列を示したが、あの説明はワールド座標のZ軸上にカメラがあり原点の方向をカメラが向いていることを前提としていた。 別な言い方をすると、カメラの向いている方向をZ軸と見立てた座標上の3次元の位置に対して透視射影変換行列を適用していた。

カメラの位置や向きが変わった場合、カメラの向いている方向をZ軸と見立てた座標(ビュー座標)に変換してから透視射影変換行列を適用すればよい。

対象物が固定でカメラの位置と向きが変わった場合、対象物の絶対的な位置は変わらないが軸が変わることにより座標が変わる。 (動かない建物を正面に見ている状態で視線を左に動かすと、その建物は相対的に視野の右に移動する)
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 Projection2 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 ff:int = 0;

            private var m:Matrix3D = new Matrix3D();

            public function Projection2():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;

                addEventListener(Event.ENTER_FRAME, onEnterFrame);
               
            }

            private function onEnterFrame(e:*):void{

                ff++;

                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{
                // camera rotation matrix
                var rm:Matrix3D = Matrix3D.rotationMatrix(0, 1, 0,(ff)/180*Math.PI);
                rm = Matrix3D.multiply(Matrix3D.rotationMatrix(1,0,0, 0.1), rm);

                // apply camera rotation
                Matrix3D.multiplyVector(rm,p);

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

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

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

スポンサーサイト

Comment

Post a comment

Secret

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。