Home > 梅原 > [PV3D]ジンバルロックを体験してみよう!2

[PV3D]ジンバルロックを体験してみよう!2

20090724
Category:梅原 /Tags:

[PV3D]ジンバルロックを体験してみよう!2ジャイロスコープの形してたほうが、ジンバルロックのかかり方がわかりやすいと思って作った。

Get Adobe Flash player

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

赤いわっかの軸(突き出た部分)と青いわっかの軸の位置が
一致しているのが注目点。

いろいろ回転させていろいろ試してくださいませ。

マウスドラッグで、視点を変えられます。

▼関連
http://www.mztm.jp/wp/2009/07/21/pv3dジンバルロックを体験してみよう!/
http://www.mztm.jp/wp/2009/07/31/ジンバルロックを体験してみよう!3(ビルトイン/

【参考】ジャイロスコープ
http://marupeke296.com/DXG_No10_Quaternion.html

▼Wonderfl
http://wonderfl.net/code/d88d4e844c8f48afbc04736ef1ff8c6bbc639106

▼ActionScript AS3(FP9)

/*
★ジンバルロックを体験してみよう!2

ジャイロスコープの形してたほうが、ジンバルロックのかかり方が
わかりやすいと思って作った。

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

赤いわっかの軸(突き出た部分)と青いわっかの軸の位置が
一致しているのが注目点。

いろいろ回転させていろいろ試してくださいませ。

マウスドラッグで、視点を変えられます。

↓こちらもどうぞ。
ジンバルロックを体験してみよう!

http://wonderfl.net/code/2d5664a811359bb65aeebb97422f4668250a74c9

【参考】ジャイロスコープ

http://marupeke296.com/DXG_No10_Quaternion.html

*/

package
{
	import org.papervision3d.view.BasicView;
	import org.papervision3d.objects.parsers.DAE;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.objects.DisplayObject3D;
	import flash.events.Event;
	import flash.display.SimpleButton;
	import flash.events.MouseEvent;
	import caurina.transitions.Tweener;
	import flash.display.Sprite;
	import flash.text.TextField;

	[SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
	public class Main2 extends BasicView
	{
		private var gyroX:DAE = new DAE();
		private var gyroY:DAE = new DAE();
		private var gyroZ:DAE = new DAE();
		private var colorCubeRight:Cube;
		private var base:DisplayObject3D = new DisplayObject3D();

		public function Main2()
		{
			//Button&TextField
			var btnX1:SimpleButton = Create.newSimpleButton([5,396,100,20,"rotationX+=30"]);
			var btnX0:SimpleButton = Create.newSimpleButton([110, 396, 100, 20, "rotationX-=30"]);
			var btnY1:SimpleButton = Create.newSimpleButton([5,418,100,20,"rotationY+=30"]);
			var btnY0:SimpleButton = Create.newSimpleButton([110, 418, 100, 20, "rotationY-=30"]);
			var btnZ1:SimpleButton = Create.newSimpleButton([5,440,100,20,"rotationZ+=30"]);
			var btnZ0:SimpleButton = Create.newSimpleButton([110, 440, 100, 20, "rotationZ-=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";
			reset.name = "reset";
			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, CLICK);
			addChild(btnX1);
			addChild(btnX0);
			addChild(btnY1);
			addChild(btnY0);
			addChild(btnZ1);
			addChild(btnZ0);
			addChild(reset);
			//rotationXYZ
			var tf0x:TextField = Create.newTextField([225, 396, 120, 20, "rotationX:0", 0xFFFFFF],[["selectable",false]]);
			var tf0y:TextField = Create.newTextField([225, 418, 120, 20, "rotationY:0", 0xFFFFFF],[["selectable",false]]);
			var tf0z:TextField = Create.newTextField([225, 440, 120, 20, "rotationZ:0", 0xFFFFFF],[["selectable",false]]);
			addChild(tf0x)
			addChild(tf0y)
			addChild(tf0z)

			//3D
			scene.addChild(base);
			base.rotationX = -15;
			base.rotationY = 30;
			base.y = 40;
			var light:PointLight3D = new PointLight3D();
			camera.z = -4000;
			camera.focus = 100;

			//ジャイロスコープを作る。
			var ml:MaterialsList = new MaterialsList( { all:new FlatShadeMaterial(light, 0x0000FF, 0) } );
			gyroZ.load("http://mztm.heteml.jp/umhr/wonderfl/gyroZ.dae", ml);
			ml = new MaterialsList( { all:new FlatShadeMaterial(light, 0x00FF00, 0) } );
			gyroY.load("http://mztm.heteml.jp/umhr/wonderfl/gyroY.dae",ml);
			ml = new MaterialsList( { all:new FlatShadeMaterial(light, 0xFF0000, 0) } );
			gyroX.load("http://mztm.heteml.jp/umhr/wonderfl/gyroX.dae",ml);
			base.addChild(gyroZ);
			gyroZ.addChild(gyroY);
			gyroY.addChild(gyroX);
			//突き出た棒
			ml = new MaterialsList( { all:new FlatShadeMaterial(light, 0xFF0000, 0)})
			var _cube:Cube = new Cube(ml, 25, 8, 8);
			_cube.x = 110;
			gyroX.addChild(_cube);
			_cube = new Cube(ml, 25, 8, 8);
			_cube.x = -110;
			gyroX.addChild(_cube);
			ml = new MaterialsList( { all:new FlatShadeMaterial(light, 0x00FF00, 0)})
			_cube = new Cube(ml, 8, 8,25);
			_cube.y = 140;
			gyroY.addChild(_cube);
			_cube = new Cube(ml, 8, 8,25);
			_cube.y = -140;
			gyroY.addChild(_cube);
			ml = new MaterialsList( { all:new FlatShadeMaterial(light, 0xFF, 0)})
			_cube = new Cube(ml, 8, 45,8);
			_cube.z = 180;
			gyroZ.addChild(_cube);
			_cube = new Cube(ml, 8, 45,8);
			_cube.z = -180;
			gyroZ.addChild(_cube);

			//キューブ部分
			var colors_array:Array = [  0x00FF00, 0xFF0000, 0x00FFFF, 0xFF00FF,0x0000FF, 0xFFFF00 ];
			ml = 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)
			})
			//右側の対照用のキューブ
			colorCubeRight = new Cube(ml, 100, 100, 100);
			base.addChild(colorCubeRight);

			//コントロール部
			var isMOUSE_DOWN:Boolean;
			var xy_array:Array = [0, 0];
			addEventListener(MouseEvent.MOUSE_MOVE,MOUSE_MOVE);
			function MOUSE_MOVE(e:MouseEvent):void {
				isMOUSE_DOWN = e.buttonDown;
				if (!isMOUSE_DOWN) {
					xy_array = [stage.mouseX, stage.mouseY];
				}
			}
			addChildAt(Create.newSprite(null,null, [["beginFill", [0x000000, 1]], ["drawRect", [0, 0, 465, 465]]]),0);
			addEventListener(Event.ENTER_FRAME, ENTER_FRAME);
			function ENTER_FRAME(e:Event):void {
				if(isMOUSE_DOWN){
					base.rotationY += (xy_array[0] - stage.mouseX)/2;
					base.rotationX += (xy_array[1] - stage.mouseY)/2;
					xy_array = [stage.mouseX, stage.mouseY];
				}
				//回転数表示を更新
				tf0x.text = "rX:" + near(colorCubeRight.rotationX);
				tf0y.text = "rY:" + near(colorCubeRight.rotationY);
				tf0z.text = "rZ:" + near(colorCubeRight.rotationZ);
			}

			//描画スタート
			startRendering();
		}
		private function near(num:Number):Number {
			return Math.round(num*1000000)/ 1000000;
		}

		//クリックした時の動作
		private function CLICK(e:MouseEvent):void {
			if (e.currentTarget.name == "reset") {
				Tweener.addTween(base, { rotationX:-15,rotationY:30, time:1 } );
				Tweener.addTween(gyroX, { rotationX:0, time:1 } );
				Tweener.addTween(gyroY, { rotationY:0, time:1 } );
				Tweener.addTween(gyroZ, { rotationZ:0, time:1 } );
				Tweener.addTween(colorCubeRight, { rotationX:0,rotationY:0,rotationZ:0, time:1 } );
				return;
			}
			var axis:String = e.currentTarget.name.substr(0,1);
			var d:Number = Number(e.currentTarget.name.substr(1, 1)) * 60 - 30;
			var num:Number;
			if ("X" == axis) {
				Tweener.addTween(gyroX, { rotationX:gyroX.rotationX + d, time:1 } );
				Tweener.addTween(colorCubeRight, { rotationX:colorCubeRight.rotationX + d, time:1 } );
			}else if ("Y" == axis) {
				Tweener.addTween(gyroY, { rotationY:gyroY.rotationY + d, time:1 } );
				Tweener.addTween(colorCubeRight, { rotationY:colorCubeRight.rotationY + d, time:1 } );
			}else if ("Z" == axis) {
				Tweener.addTween(gyroZ, { rotationZ:gyroZ.rotationZ + d, time:1 } );
				Tweener.addTween(colorCubeRight, { rotationZ:colorCubeRight.rotationZ + d, time:1 } );
			}
		}
	}
}

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;
    }
}

関連記事:

Comments are closed.