スポンサーサイト

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

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

[PV3D] 3次元での姿勢の変換

2008-01-28 | 20:10


左のオブジェクトの姿勢を右の姿勢に移動する事を考える。
移動後のオブジェクトの法線ベクトル(図中の青い線)と、法線ベクトルを軸に回転する角度(この例では120°)は与えられているものとする。
まず最初に移動前の法線ベクトルを移動後の法線ベクトに合わせるための回転を行う。
そのために回転軸と回転角が必要になるが、回転角は二つのベクトルの内積から求める事ができ、回転軸は二つのベクトルの外積そのものである。
下の図が、その回転軸と回転角を使って回転した後の姿勢。


その後は、移動後の法線ベクトルを回転軸にして、与えられた角度だけ回転させればよい。
↓が以上の説明の処理を行っているプログラム。マウスクリックで姿勢(と位置)が変わります。

package {
    import flash.display.*;
    import flash.events.*;

    import org.papervision3d.core.*;
    import org.papervision3d.core.geom.*;
    import org.papervision3d.core.math.*;
    import org.papervision3d.scenes.* ;
    import org.papervision3d.objects.*;
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.cameras.*;
    import org.papervision3d.materials.*;
    import org.papervision3d.materials.shadematerials.* ;
    import org.papervision3d.materials.utils.*;
    import org.papervision3d.view.*;
    import org.papervision3d.render.*;
    import org.papervision3d.lights.*;
    import org.papervision3d.materials.special.LineMaterial ;

    [SWF(width="600", height="400", frameRate="10", backgroundColor="#ffffff")]
        public class PoseChange extends Sprite{
            private var renderer:BasicRenderEngine = new BasicRenderEngine();
            private var viewport:Viewport3D = new Viewport3D(600, 800, false, true);
            private var scene:Scene3D = new Scene3D();
            private var camera:FreeCamera3D = new FreeCamera3D();

            private var lines:Array = null;

            private var cube:Cube;
            private var flg:Boolean = false;

            public function PoseChange():void
            {
                stage.align = StageAlign.TOP_LEFT;
                stage.scaleMode = StageScaleMode.NO_SCALE;

                addChild(viewport);

                camera.y = 100;
                camera.z = -1100;
                camera.x = 200;
                camera.focus = 1100;
                camera.zoom = 1;
                camera.tilt(20);

                var greenwire:WireframeMaterial = new WireframeMaterial( 0xff00 );
                cube= new Cube(new MaterialsList({all:greenwire}), 100, 200, 300);
                scene.addChild(cube);

                showVector(cube);

                renderer.renderScene(scene, camera, viewport);

                stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
            }

            private function onClick(e:*):void{
                flg = !flg;

                var toV:Number3D;
                var pos:Number3D;
                var rad:Number;

                if(flg){
                    toV = new Number3D(1,1,1);
                    pos = new Number3D(200,100,100);
                    rad = Math.PI*2/3;
                }else{
                    toV = new Number3D(0,1,0);
                    pos = new Number3D(0,0,0);
                    rad = -Math.PI*2/3;
                }
                
                pose(cube,  toV , rad, pos);

                renderer.renderScene(scene, camera, viewport);
                showVector(cube);
            }

            private function pose(o3d:DisplayObject3D, toV:Number3D, rad:Number, pos:Number3D):void{
                var fromV:Number3D = new Number3D(o3d.transform.n12, o3d.transform.n22, o3d.transform.n32);
                fromV.normalize();
                toV.normalize();

                // 二つのベクトルから法線ベクトルをあわせるための回転軸(二つのベクトルの外積)を求める
                var rv:Number3D = Number3D.cross(toV, fromV);
                rv.normalize();

                // 法線ベクトルをあわせるための回転角(内積のarccos)を求める
                var rr:Number = Math.acos(Number3D.dot(fromV, toV));

                // 法線ベクトルをあわせるための回転軸と回転角から回転行列作成
                var mat:Matrix3D = Matrix3D.rotationMatrix(rv.x, rv.y, rv.z, rr);

                // 作成した回転行列をオブジェクトに適用
                o3d.transform = Matrix3D.multiply(mat, o3d.transform);

                // オブジェクトの座標系のY軸中心にrad回転する
                o3d.transform = Matrix3D.multiply(o3d.transform, Matrix3D.rotationY(rad));

                o3d.x = pos.x;
                o3d.y = pos.y;
                o3d.z = pos.z;

            }

            private function showVector(cube:Cube):void{
                if(lines != null){
                    for each(var l:Lines3D in lines){
                        scene.removeChild(l);
                    }
                }
                lines = [];

                var m:Matrix3D = cube.transform;
                var xl:Lines3D = new Lines3D(new LineMaterial());
                scene.addChild(xl);
                xl.addNewLine(2, cube.x,cube.y,cube.z,
                        cube.x + m.n11*100, cube.y + m.n21*100 , cube.z + m.n31*100);
                lines.push(xl);

                var yl:Lines3D =  new Lines3D(new LineMaterial(0xff));
                scene.addChild(yl);
                yl.addNewLine(2, cube.x,cube.y,cube.z,
                        cube.x + m.n12*100, cube.y + m.n22*100 , cube.z + m.n32*100);
                lines.push(yl);

                var zl:Lines3D = new Lines3D(new LineMaterial(0xff00));
                scene.addChild (zl);
                zl.addNewLine(2, cube.x,cube.y,cube.z,
                        cube.x + m.n13*100, cube.y + m.n23*100 , cube.z + m.n33*100);
                lines.push(zl);

                renderer.renderScene(scene, camera, viewport);
            }
        }
}

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