スポンサーサイト

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

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

[ActionScript 3.0] クォータニオンを使った球面線形補間

2007-08-15 | 20:45

移動元をP1、移動先をP2、 P1とP2の角をwとすると t(0~1)での位置は
p(t) = (sin(1-t)w / sinw)P1 + (sin(tw)/sinw)P2
で表される。

↓のウィンドウをクリックすると (50,0,50)から(0,20,0)にボールが移動する軌跡が表示されます。

SphericalLinearInterpolation.as
package{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.ui.*;
    import flash.utils.*;
    [SWF(width="400", height="300",backgroundColor="0xffffff")]

        public class SphericalLinearInterpolation extends Sprite{
            // camera position
            private var cameraX:Number = 100;
            private var cameraY:Number = 50;
            private var cameraZ:Number = -100;

            // view position
            private var viewX:Number = 0;
            private var viewY:Number = 0;
            private var viewZ:Number = 0;

            private var faceZ:Number = 100;

            private var balls:Array = new Array();
            private var v1:Vector3 = new Vector3(50,0,50);
            private var v2:Vector3 = new Vector3(0,30,0);

            private var cnt:int = 0;
            private var theta:Number = Math.PI/2;

            public function SphericalLinearInterpolation(){
                for(var i:int = 0 ; i < 10 ; i++){
                    var ball:Ball = new Ball(0xff0000);
                    ball.x = -100;
                    ball.y = -100;
                    addChild(ball);
                    balls.push(ball);
                }

                graphics.lineStyle(1,0,0.3);
                var from:Point;
                var to:Point;
                // X axis
                from = view2screen(world2view(0,0,0));
                to = view2screen(world2view(200,0,0));
                graphics.moveTo(from.x, from.y);
                graphics.lineTo(to.x, to.y);
                // Y axis
                from = view2screen(world2view(0,0,0));
                to = view2screen(world2view(0,200,0));
                graphics.moveTo(from.x, from.y);
                graphics.lineTo(to.x, to.y);
                // Z axis
                from = view2screen(world2view(0,0,0));
                to = view2screen(world2view(0,0,200));
                graphics.moveTo(from.x, from.y);
                graphics.lineTo(to.x, to.y);

                cnt = 10;

                stage.addEventListener(MouseEvent.CLICK, function():void{
                        for each(var ball:Ball in balls){
                        ball.x = -100;
                        ball.y = -100;
                        }
                        cnt = 0;
                        });


                var timer:Timer = new Timer(500);
                timer.addEventListener(TimerEvent.TIMER, loop);
                timer.start();
            }

            private function rotate(ball:Ball):void{
                if(cnt >= 10)
                    return;

                var t:Number = (cnt+1) * 0.1;

                var q1:Quaternion = new Quaternion(0, v1);
                var q2:Quaternion = new Quaternion(0, v2);
                var qt:Quaternion = 
                    q1.multiplScalar((Math.sin((1-t)*theta))/Math.sin(theta)).add(
                    q2.multiplScalar(Math.sin(theta*t)/Math.sin(theta)));

                ball.wx = qt.x
                ball.wy = qt.y
                ball.wz = qt.z
                var view:Point = view2screen(world2view(ball.wx, ball.wy, ball.wz));
                ball.x = view.x;
                ball.y = view.y;
            }

            private function loop(e:Event):void{
                if(cnt < 10)
                    rotate(balls[cnt]);
                cnt++;
            }

            private function world2view(x:Number, y:Number, z:Number):Point{
                var xx:Number = (faceZ - cameraZ) * (x - cameraX) / (z - cameraZ) 
                    - (faceZ - cameraZ) * (viewX - cameraX) / (viewZ - cameraZ);
                var yy:Number =  (faceZ - cameraZ) * (y - cameraY) / (z - cameraZ)
                    -(faceZ - cameraZ)* (viewY - cameraY) / (viewZ - cameraZ);
                return new Point(xx,yy);
            }

            private function view2screen(p:Point):Point{
                return new Point(p.x + 200, 200 - p.y);
            }
        }
}

スポンサーサイト

Comment

Post a comment

Secret

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