fc2ブログ

軽量3D

2008-02-29 | 20:29

マウスドラッグで視点変更できます。

graphicsに描画する時の座標およびスプライトの座標にビュー変換と射影変換を適用して3Dに見えるようにしています。

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

    import org.papervision3d.core.math.*;

    [SWF(width="400", height="400",backgroundColor="0xffffff")]

        public class Light3D extends Sprite{
            private var m:Matrix3D = new Matrix3D();
            private var rm:Matrix3D = new Matrix3D();

            private var lastPoint:Point;
            private var mouseDown:Boolean = false;

            private var objects:Array = [];

            public function Light3D(){

                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;

                var triangle:Triangle = new Triangle();
                addChild(triangle);
                triangle.redraw(m, rm);
                triangle.zz = 0;
                objects.push(triangle);

                var star:Star = new Star();
                addChild(star);
                star.redraw(m, rm);
                star.zz = 50;
                objects.push(star);

                var rectangle:Rectangle = new Rectangle();
                addChild(rectangle);
                rectangle.redraw(m, rm);
                rectangle.zz = 100;
                objects.push(rectangle);

                stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:*):void{
                        mouseDown = true;
                        lastPoint = new Point(stage.mouseX, stage.mouseY);
                        });
                stage.addEventListener(MouseEvent.MOUSE_UP, function(e:*):void{
                        mouseDown = false;
                        lastPoint = new Point(stage.mouseX, stage.mouseY);
                        });
                stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            }

            private function onMouseMove(e:*):void{
                if(!mouseDown)
                    return;

                var xx:Number = stage.mouseX - lastPoint.x;
                var yy:Number = -stage.mouseY + lastPoint.y;
                if(yy == 00) return;

                var rotAxis:Number3D = new Number3D();

                rotAxis.z = 0;
                rotAxis.x = yy;
                rotAxis.y = -xx;

                // calculate the amount of rotation 
                var rotAngle:Number = Math.sqrt(xx*xx + yy*yy)/200*Math.PI;
                if(rotAngle == 0) return;

                rotAxis.normalize();
                rm = Matrix3D.multiply(Matrix3D.rotationMatrix(rotAxis.x, rotAxis.y, 0, rotAngle), rm); 

                lastPoint = new Point(stage.mouseX, stage.mouseY);

                for each(var o:Base3D in objects){
                    o.redraw(m, rm);
                }

                // 本当はZオーダーを考慮して並べ替える
                if(rm.n33 < 0){
                    setChildIndex(objects[0],2);
                    setChildIndex(objects[1],1);
                    setChildIndex(objects[2],0);
                }else{
                    setChildIndex(objects[0],0);
                    setChildIndex(objects[1],1);
                    setChildIndex(objects[2],2);
                }
            }
        }
}

internal class Base3D extends Sprite{
    public var xx:int ;
    public var yy:int ;
    public var zz:int ;

    public function redraw(m:Matrix3D, rm:Matrix3D):void{
    }

    protected function convertPoint(p:Number3D, m:Matrix3D, rm:Matrix3D):Point{

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

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

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

import flash.display.Sprite;
import flash.geom.*;

import org.papervision3d.core.math.*;

internal class Triangle extends Base3D {

    public function Triangle() {
    }

    public override function redraw(m:Matrix3D, rm:Matrix3D):void{
        graphics.clear();
        graphics.lineStyle(1, 0, 1);
        graphics.beginFill(0xff0000);
        var p:Point = convertPoint(new Number3D(-30,-30,zz), m, rm);
        var p2:Point = convertPoint(new Number3D(30,30,zz), m, rm);
        var p3:Point = convertPoint(new Number3D(-30,30,zz), m, rm);

        graphics.moveTo(p.x, p.y);
        graphics.lineTo(p2.x, p2.y);
        graphics.lineTo(p3.x, p3.y);
        graphics.endFill();

    }
}

internal class Rectangle extends Base3D {

    public function Rectangle() {
    }

    public override function redraw(m:Matrix3D, rm:Matrix3D):void{
        graphics.clear();
        graphics.lineStyle(1, 0, 1);
        graphics.beginFill(0xff00);
        var p:Point = convertPoint(new Number3D(0,0,zz), m, rm);
        var p2:Point = convertPoint(new Number3D(0,150,zz), m, rm);
        var p3:Point = convertPoint(new Number3D(150, 150,zz), m, rm);
        var p4:Point = convertPoint(new Number3D(150, 0,zz), m, rm);

        graphics.moveTo(p.x, p.y);
        graphics.lineTo(p2.x, p2.y);
        graphics.lineTo(p3.x, p3.y);
        graphics.lineTo(p4.x, p4.y);
        graphics.endFill();

    }
}

internal class Star extends Base3D{
    public function Star(){
    }

    public override function redraw(m:Matrix3D, rm:Matrix3D):void{
        graphics.clear();
        graphics.lineStyle(1, 0xff, 0.8);
        graphics.beginFill(0xff);
        var seq:Array=[2,4,1,3,0];
        var p0:Point = convertPoint(new Number3D(100, 200, zz), m, rm);
        graphics.moveTo(p0.x, p0.y);
        for(var j:int = 0 ; j < 5 ; j++){
            var rad:Number = seq[j] * Math.PI * 2 / 5;
            var p:Point = convertPoint(new Number3D(-Math.sin(rad)*100+100, Math.cos(rad)*100+100, zz), m, rm);
            graphics.lineTo(p.x, p.y);
        }
        graphics.endFill();

    }
}

スポンサーサイト