fc2ブログ

透視射影変換行列

2008-02-28 | 20:22



カメラから視錐台の近平面までの距離をn(ear)、遠平面までの距離をf(ar)、近平面の上辺をt(op)、下辺をb(ottom)、左辺をl(eft)、右辺をr(ight)とした時、 透視射影変換行列は

で表される。

3次元での座標にこの行列を適用すれば2次元上の座標に変換できる。
(この説明は、カメラがワールド座標のz軸上のマイナス方向にあり、原点の方向を向いていることを前提としている。カメラの位置や向きが変化する場合については次回)
package {
    import flash.display.*;
    import flash.events.*;

    import org.papervision3d.core.*;
    import org.papervision3d.core.geom.*;
    import org.papervision3d.core.math.*;
    [SWF(width="400", height="400", frameRate="10", backgroundColor="#ffffff")]
        public class Projection 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 ff:int = 0;

            private var m:Matrix3D = new Matrix3D();

            public function Projection():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{

                // rotation axis
                var ra:Number3D = new Number3D(1,2,3);
                ra.normalize();
                // rotation matrix
                var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(ra.x,ra.y,ra.z,(ff++)/180*Math.PI);

                var points2D:Array = [];
                for each(var pp:Number3D in initialPoints){
                    var p:Number3D = pp.clone();
                    // rotation
                    Matrix3D.multiplyVector(rotationMatrix,p);
                    // convert to 2D point
                    Matrix3D.multiplyVector(m,p);
                    p.x += 200; p.y = 200 - p.y;
                    points2D.push(p);
                }

                graphics.clear();
                graphics.lineStyle(3,0xff,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.lineStyle(3,0xff0000,0.8);
                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);
                
                graphics.lineStyle(3,0xff00,0.8);
                for (i = 0 ; i < 4; i++){
                    graphics.moveTo(points2D[i].x, points2D[i].y);
                    graphics.lineTo(points2D[i+4].x, points2D[i+4].y);
                }
            }
        }
}
スポンサーサイト



Comment

Post a comment

Secret