スポンサーサイト

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

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

PV3Dで人型ロボット4

2008-01-27 | 13:30

マウスの動きにロボット達が反応します。
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 Robot8 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 pointLight:PointLight3D;

            private var robots:Array = [];

                private var W:int = 600;
                private var H:int = 400;

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

                addChild(viewport);

                camera.y = -200;
                camera.z = -2200;
                camera.x = 0;
                camera.focus = 1100;
                camera.zoom = 1;

                pointLight = new PointLight3D();
                pointLight.y = 300;
                pointLight.z = -100;

                for(var i:int = 0  ; i < 5; i++){
                    var robot:Robot = new Robot(scene, new PhongMaterial(pointLight, 0x88ff00 + i*30, 0x111111, 1) );
                    robot.x = -800 + 400*i;
                    robot.waist.ry = -0.2 + 0.1*i;
                    robots.push(robot);
                }
                for(var j:int = 0  ; j < 4; j++){
                    var robotz:Robot = new Robot(scene, new PhongMaterial(pointLight, 0xddff00 + j*30, 0x111111, 1) );
                    robotz.x = -600 + 400*j;
                    robotz.z = 400;
                    robots.push(robotz);
                }

                addEventListener(Event.ENTER_FRAME, function(e:*):void{
                        renderer.renderScene(scene, camera, viewport);
                        });

                stage.addEventListener( MouseEvent.MOUSE_MOVE, function(e:*):void{
                        if( stage.mouseY > 0 && stage.mouseY < H){
                        for each (var r:Robot in robots)
                        r.stretch((stage.mouseX - W/2) * 2.2, (H - stage.mouseY) * 1.6 , 300);
                        }
                        });
            }

        }
}

import org.papervision3d.objects.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.scenes.* ;
import org.papervision3d.core.geom.*;
import org.papervision3d.core.math.*;
import org.papervision3d.materials.shadematerials.* ;
import caurina.transitions.Tweener;

internal class Robot{
    public    var leftArm2:LinkFrame;
    public    var leftArm:LinkFrame;
    public    var rightArm2:LinkFrame;
    public    var rightArm:LinkFrame;
    public    var body:LinkFrame;
    public    var head:LinkFrame;
    public    var waist:LinkFrame;

    private    var leftLeg2:LinkFrame;
    private    var leftLeg:LinkFrame;
    private    var rightLeg2:LinkFrame;
    private    var rightLeg:LinkFrame;

    private var scene:Scene3D;

    private var param:Object = {};
    private var jumping:Boolean = false;
    public function Robot(scene:Scene3D, material:PhongMaterial){
        this.scene = scene;

        param.legWidth2 = 50;
        param.legWidth = 40;
        param.legLen2 = 120;
        param.legLen = 120;

        createBody(material);
    }
    private function createBody(material:PhongMaterial):void{
        waist = new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 120, 50, 60));
        waist.direction = new Number3D(0, -1, 0);
        waist.offset = new Number3D(0, 0, 0);
        waist.len = 60;

        body= new LinkFrame(scene,
                new Cube(new MaterialsList( {all:material} ), 120, 50, 140));
        body.len = 140;
        body.offset = new Number3D(0, 0, 0);
        body.direction = new Number3D(0, 1, 0);
        body.ryMax = Math.PI *(1/3);
        body.ryMin = -Math.PI * (1/3);
        body.rxMax = Math.PI /2;
        body.rxMin = -Math.PI /2;
        waist.addChild(body);

        head = new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 50, 30, 60));
        head.len = 60;
        head.offset = new Number3D(0, body.len, 0);
        head.direction = new Number3D(0, 1, 0);
        body.addChild(head);

        leftArm2= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 30, 30, 100));
        leftArm2.len = 100;
        leftArm2.offset = new Number3D(75, body.len, 0);
        leftArm2.direction = new Number3D(0, -1, 0);
        leftArm2.rxMax = Math.PI ;
        leftArm2.rxMin = -Math.PI /2;
        body.addChild(leftArm2);

        leftArm= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 30, 30, 100));
        leftArm.len = 100;
        leftArm.offset = new Number3D(0, -100, 0);
        leftArm.direction = new Number3D(0, -1, 0);
        leftArm.rxMax = Math.PI ;
        leftArm2.addChild(leftArm);

        rightArm2= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 30, 30, 100));
        rightArm2.len = 100;
        rightArm2.offset = new Number3D(-75, body.len, 0);
        rightArm2.direction = new Number3D(0, -1, 0);
        rightArm2.rxMax = Math.PI ;
        rightArm2.rxMin = -Math.PI /2;
        body.addChild(rightArm2);

        rightArm= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 30, 30, 100));
        rightArm.len = 100;
        rightArm.offset = new Number3D(0, -100, 0);
        rightArm.direction = new Number3D(0, -1, 0);
        rightArm.rxMax = Math.PI ;
        rightArm2.addChild(rightArm);

        leftLeg2= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 
                    param.legWidth2, param.legWidth2, param.legLen2));
        leftLeg2.len = param.legLen;
        leftLeg2.offset = new Number3D(param.legWidth2/2 + 10, -waist.len, 0);
        leftLeg2.direction = new Number3D(0, -1, 0);
        leftLeg2.rxMax = Math.PI /2;
        leftLeg2.rxMin = -Math.PI /2;
        waist.addChild(leftLeg2);

        leftLeg= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 
                    param.legWidth, param.legWidth, param.legLen));
        leftLeg.len = param.legLen;
        leftLeg.offset = new Number3D(0, -param.legLen2, 0);
        leftLeg.direction = new Number3D(0, -1, 0);
        leftLeg.rxMax = 0;
        leftLeg.rxMin = -Math.PI /2;
        leftLeg2.addChild(leftLeg);

        rightLeg2= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 
                    param.legWidth2, param.legWidth2, param.legLen2));
        rightLeg2.len = param.legLen2;
        rightLeg2.offset = new Number3D(-param.legWidth2/2 - 10, -waist.len, 0);
        rightLeg2.direction = new Number3D(0, -1, 0);
        rightLeg2.rxMax = Math.PI /2;
        rightLeg2.rxMin = -Math.PI /2;
        waist.addChild(rightLeg2);

        rightLeg= new LinkFrame(scene,
                new Cube(new MaterialsList({ all:material} ), 
                    param.legWidth, param.legWidth, param.legLen));
        rightLeg.len = param.legLen;
        rightLeg.offset = new Number3D(0, -param.legLen2, 0);
        rightLeg.direction = new Number3D(0, -1, 0);
        rightLeg.rxMax = 0;
        rightLeg.rxMin = -Math.PI /2;
        rightLeg2.addChild(rightLeg);

        waistCheck();
        waist.update();
    }

    private function waistCheck():void{
        if(!jumping){
            var left:Number = Math.cos(leftLeg2.rx) * param.legLen2 + 
                Math.cos(leftLeg2.rx + leftLeg.rx) * param.legLen;
            var right:Number = Math.cos(rightLeg2.rx) * param.legLen2 + 
                Math.cos(rightLeg2.rx + rightLeg.rx) * param.legLen;

            if(waist.offset == null)
                waist.offset = new Number3D(0, Math.min(left, right), 0);
            else
                waist.offset.y = Math.min(left,right);
        }
    }

    public function stretch(x:int, y:int, z:int):void{
        z = -400;
        var xx:Number = x - waist.offset.x;
        var txz:Number =  Math.atan(xx/z); // xz平面上の角度

        var d:Number = Math.sqrt(z*z + x*x); // 原点と(x,y,z)を結んでできる三角形の底辺の長さ
        var tx:Number = Math.atan((y-250)/d);
        var t:Number = 1;
        Tweener.addTween(body, {ry:txz, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(head, { rx:tx, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(rightArm2, { rx:tx+Math.PI/2, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(leftArm2, { rz:0.2, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(leftArm, { rx:tx+Math.PI/2, time:t, 
                transition:"easeOutBack"
                });

        var th:Number = 250;
        var tl:Number = (y >= th ) 
            ? 0
            : (Math.PI/2) * ((th - y)/ th);
        Tweener.addTween(leftLeg2, { rx:tl, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(rightLeg2, { rx:tl, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(leftLeg, { rx:-tl, time:t, 
                transition:"easeOutBack"
                });
        Tweener.addTween(rightLeg, { rx:-tl, time:t, 
                transition:"easeOutBack"
                ,onUpdate: update 
                });
    }

    private function update():void{
        waistCheck();
        waist.update();
    }

    public function set x(v:Number):void{
        waist.offset.x = v;
        waist.update();
    }
    public function set y(v:Number):void{
        waist.offset.y = v;
        waist.update();
    }
    public function set z(v:Number):void{
        waist.offset.z = v;
        waist.update();
    }
}

import org.papervision3d.objects.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.scenes.* ;
import org.papervision3d.core.geom.*;
import org.papervision3d.core.math.*;
import org.papervision3d.materials.*;
import org.papervision3d.materials.shadematerials.* ;
import org.papervision3d.materials.special.LineMaterial ;
import org.papervision3d.materials.utils.* ;
internal class LinkFrame{
    public var center:Sphere;
    private var lines:Array = null;
    private var scene:Scene3D;

    // 前のフレームに対する回転角
    private var _rx:Number = 0;
    private var _ry:Number = 0;
    private var _rz:Number = 0;

    public var rxMax:Number = Math.PI*2;
    public var rxMin:Number = -Math.PI*2;
    public var ryMax:Number = Math.PI*2;
    public var ryMin:Number = -Math.PI*2;
    public var rzMax:Number = Math.PI*2;
    public var rzMin:Number = -Math.PI*2;

    // 前のフレームからのオフセット
    public var offset:Number3D = new Number3D(0,0,0);;
    // フレームの中心を基準にしたアームの方向
    public var direction:Number3D = new Number3D(0,0,0);;
    private var arm:DisplayObject3D;

    public var len:int = 100;

    private var children:Array = [];
    public var parent:LinkFrame = null;

    public function LinkFrame(scene:Scene3D ,arm:DisplayObject3D=null){
        this.scene = scene;
        var greenwire:WireframeMaterial = new WireframeMaterial( 0xff00 );
        center = new Sphere(new ColorMaterial(0xff), 5);
        scene.addChild(center);

        if(arm != null){
            scene.addChild(arm);    
            this.arm = arm;
        }

        drawFrame();
    }

    public function addChild(child:LinkFrame):void{
        this.children.push(child);
        child.parent = this;
    }

    public function update():void{

        var mx:Matrix3D = Matrix3D.rotationMatrix(1,0,0,_rx);
        var my:Matrix3D = Matrix3D.rotationMatrix(0,1,0,_ry);
        var mz:Matrix3D = Matrix3D.rotationMatrix(0,0,1,_rz);

        var tr:Matrix3D = Matrix3D.translationMatrix (offset.x,offset.y,offset.z);

        var m:Matrix3D = Matrix3D.multiply(mx,my);
        m = Matrix3D.multiply(m, mz);
        m = Matrix3D.multiply(tr, m);

        // 前のフレームの姿勢行列 x 前のフレームに対する姿勢行列 = ワールド座標に対する姿勢行列
        if(parent != null)
            center.transform = Matrix3D.multiply( parent.center.transform, m);
        else
            center.transform = m;
        trace(center.y);
        arm.transform = Matrix3D.clone(center.transform);

        var dir:Number3D = direction.clone();
        // 姿勢行列の回転部分だけを取り出す
        var md:Matrix3D = Matrix3D.clone(arm.transform);
        md.n14 = md.n24 = md.n34 = 0;
        // アームの方向を求めて位置を調整
        Matrix3D.rotateAxis(md, dir);
        arm.x += dir.x*len/2;
        arm.y += dir.y*len/2;
        arm.z += dir.z*len/2;

        drawFrame();

        for each(var child:LinkFrame in children)
            child.update();
    }

    public function drawFrame():void{
        return ; // for debugging
        var llen:int = 100;
        if(lines != null){
            for each(var l:Lines3D in lines){
                scene.removeChild(l);
            }
        }
        lines = [];

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

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

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

        var dir:Number3D = direction.clone();
        var md:Matrix3D = Matrix3D.clone(arm.transform);
        md.n14 = md.n24 = md.n34 = 0;
        Matrix3D.rotateAxis(md, dir);
        var dl:Lines3D = new Lines3D(new LineMaterial(0x0));
        scene.addChild (dl);
        dl.addNewLine(1, center.x,center.y ,center.z,
                center.x + dir.x*llen, center.y + dir.y*llen , center.z + dir.z*llen);
        lines.push(dl);
    }

    public function set rx(v:Number):void{
        if(v >= rxMin && v <= rxMax){
            _rx = v;
            if(_rx >= Math.PI*2 || _rx <= -Math.PI*2)
                _rx = 0;
        }
    }
    public function get rx():Number{
        return _rx;
    }
    public function set ry(v:Number):void{
        if(v >= ryMin && v <= ryMax){
            _ry = v;
            if(_ry >= Math.PI*2 || _ry <= -Math.PI*2)
                _ry = 0;
        }
    }
    public function get ry():Number{
        return _ry;
    }
    public function set rz(v:Number):void{
        if(v >= rzMin && v <= rzMax){
            _rz = v;
            if(_rz >= Math.PI*2 || _rz <= -Math.PI*2)
                _rz = 0;
        }
    }
    public function get rz():Number{
        return _rz;
    }
}


今後の課題
動きのパターンを表す独立したクラスを作成して、連続したモーションを自由に組み合わせられるようにする。
関節の角度を曲線的に補完したい。
スポンサーサイト
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。