forked from: ジンバルロックを体験してみよう!(PV3D編)

by ohisama forked from ジンバルロックを体験してみよう!(PV3D編) (diff: 146)
★ジンバルロックを体験してみよう!

0.左上のrotationXYZの立方体に注目
1.初期状態(又はReset後)に「Y+=30」を三回クリックして、
Y軸90度回転をする。
2.「Z+=30」をクリックしてみる。Z軸回転したことを確認。
3.「Z-=30」をクリックして戻す。
4.「X-=30」をクリックすると、、、アレレ!「Z+=30」と同じ
Z軸回転しちゃうぞ!
これがジンバルロックであります。
いろいろ回転させていろいろ試してくださいませ。

課題
ジャイロスコープを作ったらもうちょっとわかりやすくなるよね、、、。そのうち、、、。
あと、FlashPlayer10のビルトイン関数のMatrix3Dではどうなるかのほうが
一般性があるよね。遠くないうちにやります。
=============================

Papervision3Dにおいて、rotationX,localRotationX,Quaternion
の使い分け。

左下のボタン、一回クリックごとにそれぞれの値を変化させる。

■rotationXYZ
簡単なものなら、rotationXで足りるものもあるんだろうけど、
自在に回転させるとなると、どうしてもジンバルロックが問題になる。
値がわかりやすいってのが強み。

■localRotationXYZ
localRotationXってのは、なんだろうと思ってたけど、比較すると良くわかった。
ジンバルロック回避だけなら、これでなんとかなっちゃうこともあるかも。

■Quaternion
本命はやっぱりQuaternion。
ジンバルロックは無いし、画面上と同じX,Y軸回転をするからUIとの
統合もしやすい。
内部的にはちょっとめんどくさくなるのは嫌だけど。
♥0 | Line 400 | Modified 2013-02-07 15:47:56 | MIT License
play

ActionScript3 source code

/**
 * Copyright ohisama ( http://wonderfl.net/user/ohisama )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/aZUL
 */

// forked from umhr's ジンバルロックを体験してみよう!(PV3D編)
/*
 * ★ジンバルロックを体験してみよう!
 * 
 * 0.左上のrotationXYZの立方体に注目
 * 1.初期状態(又はReset後)に「Y+=30」を三回クリックして、
 * Y軸90度回転をする。
 * 2.「Z+=30」をクリックしてみる。Z軸回転したことを確認。
 * 3.「Z-=30」をクリックして戻す。
 * 4.「X-=30」をクリックすると、、、アレレ!「Z+=30」と同じ
 * Z軸回転しちゃうぞ!
 * これがジンバルロックであります。
 * いろいろ回転させていろいろ試してくださいませ。
 * 
 * 課題
 * ジャイロスコープを作ったらもうちょっとわかりやすくなるよね、、、。そのうち、、、。
 * あと、FlashPlayer10のビルトイン関数のMatrix3Dではどうなるかのほうが
 * 一般性があるよね。遠くないうちにやります。
 * =============================
 * 
 * Papervision3Dにおいて、rotationX,localRotationX,Quaternion
 * の使い分け。
 * 
 * 左下のボタン、一回クリックごとにそれぞれの値を変化させる。
 * 
 * ■rotationXYZ
 * 簡単なものなら、rotationXで足りるものもあるんだろうけど、
 * 自在に回転させるとなると、どうしてもジンバルロックが問題になる。
 * 値がわかりやすいってのが強み。
 * 
 * ■localRotationXYZ
 * localRotationXってのは、なんだろうと思ってたけど、比較すると良くわかった。
 * ジンバルロック回避だけなら、これでなんとかなっちゃうこともあるかも。
 * 
 * ■Quaternion
 * 本命はやっぱりQuaternion。
 * ジンバルロックは無いし、画面上と同じX,Y軸回転をするからUIとの
 * 統合もしやすい。
 * 内部的にはちょっとめんどくさくなるのは嫌だけど。
 * 
 * 
 * */

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.DisplayObject3D;
    import flash.display.SimpleButton;
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]
    public class Test3 extends Sprite
    {
        private var dodai : DisplayObject3D = new DisplayObject3D();
        public function Test3() : void 
        {
            var c0 : CubeView = new CubeView();
            c0.x = -110;
            c0.y = -110;
            addChild(c0);
            var c1 : CubeView = new CubeView();
            c1.x = 110;
            c1.y = -110;
            addChild(c1);
            var c2 : CubeView = new CubeView();
            c2.x = 0;
            c2.y = 65;
            addChild(c2);
            var btnX1 : SimpleButton = Create.newSimpleButton([5, 396, 60, 20, "X+=30"]);
            var btnX0 : SimpleButton = Create.newSimpleButton([70, 396, 60, 20, "X-=30"]);
            var btnY1 : SimpleButton = Create.newSimpleButton([5, 418, 60, 20, "Y+=30"]);
            var btnY0 : SimpleButton = Create.newSimpleButton([70, 418, 60, 20, "Y-=30"]);
            var btnZ1 : SimpleButton = Create.newSimpleButton([5, 440, 60, 20, "Z+=30"]);
            var btnZ0 : SimpleButton = Create.newSimpleButton([70, 440, 60, 20, "Z-=30"]);
            var reset : SimpleButton = Create.newSimpleButton([400, 440, 60, 20, "Reset"]);
            btnX1.name = "X1";
            btnX0.name = "X0";
            btnY1.name = "Y1";
            btnY0.name = "Y0";
            btnZ1.name = "Z1";
            btnZ0.name = "Z0";
            btnX1.addEventListener(MouseEvent.CLICK, CLICK);
            btnX0.addEventListener(MouseEvent.CLICK, CLICK);
            btnY1.addEventListener(MouseEvent.CLICK, CLICK);
            btnY0.addEventListener(MouseEvent.CLICK, CLICK);
            btnZ1.addEventListener(MouseEvent.CLICK, CLICK);
            btnZ0.addEventListener(MouseEvent.CLICK, CLICK);
            reset.addEventListener(MouseEvent.CLICK, resetCLICK);
            addChild(btnX1);
            addChild(btnX0);
            addChild(btnY1);
            addChild(btnY0);
            addChild(btnZ1);
            addChild(btnZ0);
            addChild(reset);
            var tfc0 : TextField = Create.newTextField([90, 110, 100, 20, "rotationXYZ",0xFFFFFF],[["selectable",false]]);
            var tfc1 : TextField = Create.newTextField([295, 110, 100, 20, "localRotationXYZ",0xFFFFFF],[["selectable",false]]);
            var tfc2 : TextField = Create.newTextField([200, 290, 100, 20, "Quaternion",0xFFFFFF],[["selectable",false]]);
            addChild(tfc0);
            addChild(tfc1);
            addChild(tfc2);
            var tf0x : TextField = Create.newTextField([5, 5, 120, 20, "rotationX:0", 0xFFFFFF],[["selectable",false]]);
            var tf0y : TextField = Create.newTextField([5, 25, 120, 20, "rotationY:0", 0xFFFFFF],[["selectable",false]]);
            var tf0z : TextField = Create.newTextField([5, 45, 120, 20, "rotationZ:0", 0xFFFFFF],[["selectable",false]]);
            addChild(tf0x)
            addChild(tf0y)
            addChild(tf0z)
            var tf1x : TextField = Create.newTextField([340, 5, 120, 20, "rotationX:0", 0xFFFFFF],[["selectable",false]]);
            var tf1y : TextField = Create.newTextField([340, 25, 120, 20, "rotationY:0", 0xFFFFFF],[["selectable",false]]);
            var tf1z : TextField = Create.newTextField([340, 45, 120, 20, "rotationZ:0", 0xFFFFFF],[["selectable",false]]);
            addChild(tf1x)
            addChild(tf1y)
            addChild(tf1z)
            var tf2x : TextField = Create.newTextField([300, 315, 120, 20, "rotationX:0", 0xFFFFFF],[["selectable",false]]);
            var tf2y : TextField = Create.newTextField([300, 335, 120, 20, "rotationY:0", 0xFFFFFF],[["selectable",false]]);
            var tf2z : TextField = Create.newTextField([300, 355, 120, 20, "rotationZ:0", 0xFFFFFF],[["selectable",false]]);
            addChild(tf2x)
            addChild(tf2y)
            addChild(tf2z)
            function CLICK(e : MouseEvent = null) : void 
            {
                if (count > 0) 
                { 
                    return 
                };
                var axis : String = e.currentTarget.name.substr(0, 1);
                var d : Number = Number(e.currentTarget.name.substr(1, 1)) * 60 - 30;
                if ("X" == axis) 
                {
                    toRotationXYZ[0] = d;
                }
                else if ("Y" == axis) 
                {
                    toRotationXYZ[1] = d;
                }
                else if ("Z" == axis) 
                {
                    toRotationXYZ[2] = d;
                }
                count = 10;
            }
            function resetCLICK(e : MouseEvent) : void 
            {
                c0.reset();
                c1.reset();
                c2.reset();
                count = 1;
                ENTER_FRAME(e);
                tf0x.text = tf1x.text = tf2x.text = "rotationX:0";
                tf0y.text = tf1y.text = tf2y.text = "rotationY:0";
                tf0z.text = tf1z.text = tf2z.text = "rotationZ:0";
            }
            var toRotationXYZ : Array = [0, 0, 0];
            var count : int = 0;
            addEventListener(Event.ENTER_FRAME, ENTER_FRAME);
            function ENTER_FRAME(e : Event) : void 
            {
                if (count <= 0) 
                { 
                    return 
                };
                count --;
                var _x : Number = toRotationXYZ[0] * 0.1;
                var _y : Number = toRotationXYZ[1] * 0.1;
                var _z : Number = toRotationXYZ[2] * 0.1;
                if (count == 0) 
                {
                    toRotationXYZ[0] = toRotationXYZ[1] = toRotationXYZ[2] = 0;
                }
                c0.rotationXYZ(_x, _y, _z);
                c1.localRotationXYZ(_x, _y, _z);
                c2.quaternionXYZ(_x, _y, _z);
                tf0x.text = "rX:" + near(c0._cube.rotationX);
                tf0y.text = "rY:" + near(c0._cube.rotationY);
                tf0z.text = "rZ:" + near(c0._cube.rotationZ);
                tf1x.text = "rX:" + near(c1._cube.rotationX);
                tf1y.text = "rY:" + near(c1._cube.rotationY);
                tf1z.text = "rZ:" + near(c1._cube.rotationZ);
                tf2x.text = "rX:" + near(c2._cube.rotationX);
                tf2y.text = "rY:" + near(c2._cube.rotationY);
                tf2z.text = "rZ:" + near(c2._cube.rotationZ);
            }
        }
        private function near(num : Number) : Number 
        {
            return Math.round(num * 1000000) / 1000000;
        }
    }
}
import flash.events.Event;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.view.BasicView;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.core.math.Matrix3D;
import flash.display.SimpleButton;
class CubeView extends BasicView
{
    public var _cube : DisplayObject3D = GetCubeClass.getCube(200);
    public function CubeView() : void
    {
        scene.addChild(_cube);
        startRendering();
    }
    public function rotationXYZ(degreeX : Number = 0, degreeY : Number = 0, degreeZ:Number = 0) : void 
    {    
        _cube.rotationX += degreeX;
        _cube.rotationY += degreeY;
        _cube.rotationZ += degreeZ;
    }
    public function localRotationXYZ(degreeX : Number = 0, degreeY : Number = 0, degreeZ:Number = 0) : void 
    {
        _cube.localRotationX -= degreeX;
        _cube.localRotationY -= degreeY;
        _cube.localRotationZ -= degreeZ;
    }
    public function quaternionXYZ(degreeX : Number = 0, degreeY : Number = 0,degreeZ:Number = 0) : void 
    {
        var pos1:Quaternion = Quaternion.createFromMatrix(_cube.transform);
        var pos2:Quaternion = Quaternion.createFromEuler(degreeY, degreeZ, degreeX, true);
        pos2.normalize();
        pos2.mult(pos1);
        pos2.normalize();
        _cube.copyTransform(Matrix3D.quaternion2matrix(pos2.x, pos2.y, pos2.z, pos2.w));
    }
    public function reset():void 
    {
        _cube.copyTransform(new Matrix3D());
        _cube.rotationX = _cube.rotationY = _cube.rotationZ = 0;
    }
}
class GetCubeClass
{
    public static function getCube(size : Number = 100) : DisplayObject3D 
    {
        var light:PointLight3D = new PointLight3D();
        var colors_array : Array = [0x00FF00, 0xFF0000, 0x00FFFF, 0xFF00FF,0x0000FF, 0xFFFF00 ];
        var base : DisplayObject3D = new DisplayObject3D();
        var ml : MaterialsList = new MaterialsList( 
        { 
            front : new FlatShadeMaterial(light, colors_array[0], 0x333333),
            back : new FlatShadeMaterial(light, colors_array[1], 0x333333),
            right : new FlatShadeMaterial(light, colors_array[2], 0x333333),
            left : new FlatShadeMaterial(light, colors_array[3], 0x333333),
            top : new FlatShadeMaterial(light, colors_array[4], 0x333333),
            bottom : new FlatShadeMaterial(light, colors_array[5], 0x333333)
        })
        var _cube : Cube = new Cube(ml, size, size, size);
        base.addChild(_cube);
        ml = new MaterialsList( { all:new FlatShadeMaterial(light, colors_array[2], 0x333333)})
        _cube = new Cube(ml, size, 10, 10);
        _cube.x = size;
        base.addChild(_cube);
        ml = new MaterialsList( { all:new FlatShadeMaterial(light, colors_array[3], 0x333333)})
        _cube = new Cube(ml, size, 10, 10);
        _cube.x = -size;
        base.addChild(_cube);
        ml = new MaterialsList( { all:new FlatShadeMaterial(light, colors_array[0], 0x333333)})
        _cube = new Cube(ml, 10, size, 10);
        _cube.z = size;
        base.addChild(_cube);
        ml = new MaterialsList( { all:new FlatShadeMaterial(light, colors_array[1], 0x333333)})
        _cube = new Cube(ml, 10, size, 10);
        _cube.z = -size;
        base.addChild(_cube);
        ml = new MaterialsList( { all:new FlatShadeMaterial(light, colors_array[4], 0x333333)})
        _cube = new Cube(ml, 10, 10, size);
        _cube.y = size;
        base.addChild(_cube);
        ml = new MaterialsList( { all:new FlatShadeMaterial(light, colors_array[5], 0x333333)})
        _cube = new Cube(ml, 10, 10, size);
        _cube.y = -size;
        base.addChild(_cube);
        return base;
    }
}
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.SimpleButton;
class Create
{
    public static var defaultTextFormat : TextFormat = new TextFormat();
    public static function newSimpleButton(x_y_w_h_txt:Array = null,property:Array=null,graphics:Array=null):SimpleButton
    {
        var upState:Sprite = newSprite([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0xCCCCCC,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
        upState.addChild(newShape([2,2],null,[["beginFill",[0xE5E5E5,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2]-4,x_y_w_h_txt[3]-4,6]]]))
        var overState:Sprite = newSprite([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0xBBBBBB,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
        overState.addChild(newShape([2,2],null,[["beginFill",[0xEEEEEE,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2]-4,x_y_w_h_txt[3]-4,6]]]))
        var downState:Sprite = newSprite([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0xAAAAAA,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
        downState.addChild(newShape([2,2],null,[["beginFill",[0xDDDDDD,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2]-4,x_y_w_h_txt[3]-4,6]]]))
        var hitTestState:Shape = newShape([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
        if(x_y_w_h_txt[4])
        {
            upState.addChild(newTextField([0,2,x_y_w_h_txt[2],x_y_w_h_txt[3]-2],[["defaultTextFormat",new TextFormat("_sans", null, null, null, null, null, null, null, "center")],["text",x_y_w_h_txt[4]]]));
            overState.addChild(newTextField([0,2,x_y_w_h_txt[2],x_y_w_h_txt[3]-2],[["defaultTextFormat",new TextFormat("_sans", null, null, null, null, null, null, null, "center")],["text",x_y_w_h_txt[4]]]));
            downState.addChild(newTextField([0,3,x_y_w_h_txt[2],x_y_w_h_txt[3]-3],[["defaultTextFormat",new TextFormat("_sans", null, null, null, null, null, null, null, "center")],["text",x_y_w_h_txt[4]]]));
        }
        var sb:SimpleButton = new SimpleButton(upState,overState,downState,hitTestState);
        return sb;
    }
    public static function newShape(x_y_w_h_sh:Array = null,property:Array=null,graphics:Array=null):Shape
    {
        var i:int;
        var sh:Shape;
        if(x_y_w_h_sh && x_y_w_h_sh[4])
        {
            sh = x_y_w_h_sh[4];
        }
        else
        {
            sh = new Shape();
        }
        if(x_y_w_h_sh)
        {
            if (x_y_w_h_sh[0]) { sh.x = x_y_w_h_sh[0] };
            if (x_y_w_h_sh[1]) { sh.y = x_y_w_h_sh[1] };
        }
        if(property)
        {
            for (i = 0; i < property.length; i++) 
            {
                if(property[i] && property[i].length > 1)
                {
                    sh[property[i][0]] = property[i][1];
                }
            }
        }
        if(graphics)
        {
            for (i = 0; i < graphics.length; i++) 
            {
                if(graphics[i] && graphics[i].length > 1)
                {
                    sh.graphics[graphics[i][0]].apply(null, graphics[i][1]);
                }
            }
        }
        if(x_y_w_h_sh)
        {
            if (x_y_w_h_sh[2]) { sh.width = x_y_w_h_sh[2] };
            if (x_y_w_h_sh[3]) { sh.height = x_y_w_h_sh[3] };
        }
        return sh;
    }
    public static function newSprite(x_y_w_h_sp:Array = null,property:Array=null,graphics:Array=null,addChild:DisplayObject = null):Sprite
    {
        var i:int;
        var sp:Sprite;
        if(x_y_w_h_sp && x_y_w_h_sp[4])
        {
            sp = x_y_w_h_sp[4];
        }else
        {
            sp = new Sprite();
        }
        if(x_y_w_h_sp)
        {
            if (x_y_w_h_sp[0]) { sp.x = x_y_w_h_sp[0] };
            if (x_y_w_h_sp[1]) { sp.y = x_y_w_h_sp[1] };
        }
        if(property)
        {
            for (i = 0; i < property.length; i++) 
            {
                if(property[i] && property[i].length > 1)
                {
                    sp[property[i][0]] = property[i][1];
                }
            }
        }
        if(graphics)
        {
            for (i = 0; i < graphics.length; i++) 
            {
                if(graphics[i] && graphics[i].length > 1)
                {
                    sp.graphics[graphics[i][0]].apply(null, graphics[i][1]);
                }
            }
        }
        if(addChild)
        {
            sp.addChild(addChild);
        }
        if(x_y_w_h_sp)
        {
            if (x_y_w_h_sp[2]) { sp.width = x_y_w_h_sp[2] };
            if (x_y_w_h_sp[3]) { sp.height = x_y_w_h_sp[3] };
        }
        return sp;
    }
    public static function newTextField(x_y_w_h_txt_color_alpha:Array = null,property:Array=null,method:Array=null):TextField
    {
        var i:int;
        var ta:TextField = new TextField();
        ta.defaultTextFormat = defaultTextFormat;
        if(x_y_w_h_txt_color_alpha)
        {
            if (x_y_w_h_txt_color_alpha[0]) { ta.x = x_y_w_h_txt_color_alpha[0] };
            if (x_y_w_h_txt_color_alpha[1]) { ta.y = x_y_w_h_txt_color_alpha[1] };
            if (x_y_w_h_txt_color_alpha[2]) { ta.width = x_y_w_h_txt_color_alpha[2] };
            if (x_y_w_h_txt_color_alpha[3]) { ta.height = x_y_w_h_txt_color_alpha[3] };
            if (x_y_w_h_txt_color_alpha[4]) { ta.text = x_y_w_h_txt_color_alpha[4] };
            if (x_y_w_h_txt_color_alpha[5]) { ta.textColor = x_y_w_h_txt_color_alpha[5] };
            if (x_y_w_h_txt_color_alpha[6]) { ta.alpha = x_y_w_h_txt_color_alpha[6] };
        }
        if(property)
        {
            for (i = 0; i < property.length; i++) 
            {
                if(property[i] && property[i].length > 1)
                {
                    ta[property[i][0]] = property[i][1];
                }
            }
        }
        if(method)
        {
            for (i = 0; i < method.length; i++) 
            {
                if(method[i] && method[i].length > 1)
                {
                    ta[method[i][0]].apply(null, method[i][1]);
                }
            }
        }
        return ta;
    }
}