|
Iogen, Newbie
Posted: 23 March 2013 06:53 PM Total Posts: 9
Hello there, hoping someone can help with this deceptively simple problem.
I’ve got an ObjectContainer3D (container) containing (for simplicity) a single cube mesh. I’m trying to rotate the container around it’s X, Y and Z axis in various combinations of 90 degree increments. This would create the effect of being able to roll the cube left, right, forwards and backwards.
I’ve run into many problems, but the main one it stems from is that rotating the container, also rotates it’s axis. That means after I rotate on the X axis, the Y and Z axis are no longer pointing in the directions you assume they are.
I’ve searched the forums and tried all manner of different solutions:
-Incrementing rotationX, rotationY, rotationZ gives me the first problem.
-Using container.rotate() with a defined global axis works fine for the first rotation, but then it behaves strangely (the cube starts to rotate along unexpected axis).
-Hard coding the rotations based on what face you are on seems to produce a gimbal lock (both the X and Z axis become the same).
-Resetting the rotation using MeshHelper.applyRotation() seems to freeze my application for 5 seconds and not do anything.
I’ve attached some sample code below. I would be extremely grateful if anyone can give me an alternative solution / provide insight / provide some sample code of rotation on an ObjectContainer3D on all 3 axis by a variable amount.
private function rotateContainer(x:int, y:int, z:int):void { //The incremental rotations (everything is a multiple of 90). Can be negative too. totalX += x; totalY += y; totalZ += z; //Seems to produce gimbal lock container.rotateTo(totalX,totalY,totalZ); //First rotation works, but then starts rotating on completely random axis (something to do with my pivotPoint perhaps?) container.rotate(new Vector3D(0,1,0), totalZ); container.rotate(new Vector3D(0,1,0), totalY); container.rotate(new Vector3D(0,0,1), totalZ); //Axis changes with rotation, so produces incorrect rotation after first method call Tweener.addTween(innercontainer, { time:3, rotationX:totalX, rotationY:totalY, rotationZ:totalZ}); //Freezes application for 5 seconds and doesn't seem to do much else MeshHelper.applyRotations(container.getChildAt(0)); //Also freezes MeshHelper.applyRotationsContainer(container); }
|
ranoya, Newbie
Posted: 23 March 2013 09:02 PM Total Posts: 29
[ # 1 ]
Iogen, can you define exactly what you expect from using object’s rotationX, rotationY and rotationZ properties? They represent the Eulers angles from the object’s transformation matrix. The euler angles can be calculated in diferrent orders, producing different results. I supose that away3d assume the XYZ order, but i’m not sure. Furtheremore, the euler angles are relative to the original state of the object.
But you could use another approach on determining object’s orientation, using Matrix3D methods. If you want to rotate the object around his own y axis, for example, you can do this:
var axis:Vector3D = new Vector3D(); object.transform.copyColumnTo(1, axis); object.transform.appendRotation(angle, axis);
If you want to rotate it along the world y axis:
object.transform.appendRotation(angle, Vector3D.Y_AXIS);
I think that this way, compounding sucessive rotations, you can produce the exact orientation that you want for the object.
|
Iogen, Newbie
Posted: 24 March 2013 07:38 AM Total Posts: 9
[ # 2 ]
Ranoya, thanks for the reply. I’m pretty new to 3D modelling. I was using the rotationX, rotationY and rotationZ as a way to (unsuccessfully) tween rotation animations. All a bit of trial and error up to this point to be honest
I’ve tried implementing your solution as follows:
private function rotateGame(x:int, y:int, z:int):void { var temp:Matrix3D = new Matrix3D(); totalY += y; totalX += x; totalZ += z; temp.appendRotation(totalX, Vector3D.X_AXIS); temp.appendRotation(totalY, Vector3D.Y_AXIS); temp.appendRotation(totalZ, Vector3D.Z_AXIS); container.transform = temp; trace('X: ' + totalX + '. Y: ' + totalY + '. Z: ' + totalZ); }
Unfortunately this also produces 2 problems:
1. The rotations don’t seem to use the global axis. First I rotate 90 degrees on the X axis. Then I attempt to rotate 90 degrees on the Z axis. The Z axis seems to have moved with the object and behaves like you would expect the global Y axis too.
2. If I hard code the rotations instead (I know I’m on face 4. I want to go to face 6. I know I need to rotate local Z by 90 and local X by 90 from this position) I get gimbal lock. The Z axis and X axis both turn on the same axis.
Can you spot anything I’m doing wrong? Any alternative solutions? Who would have thought such a seemingly simple task would give me such a headache!
|
Luca, Sr. Member
Posted: 24 March 2013 08:27 AM Total Posts: 230
[ # 3 ]
|
Iogen, Newbie
Posted: 24 March 2013 08:54 AM Total Posts: 9
[ # 4 ]
I’m not familiar with quaternion. The documentation is a bit cryptic . Do you have a simple example or know of any useful threads / tutorials?
|
|
Luca, Sr. Member
Posted: 24 March 2013 10:24 AM Total Posts: 230
[ # 6 ]
|
Iogen, Newbie
Posted: 24 March 2013 10:28 AM Total Posts: 9
[ # 7 ]
Thanks for that -
Did a bit of digging myself and came up with this (broken) solution:
private function rotateGame(direction:String):void { var newM:Matrix3D = new Matrix3D(); var oldQ:Quaternion = new Quaternion(); var newQ:Quaternion = new Quaternion(); var resultQ:Quaternion = new Quaternion(); switch(direction){ case 'forwards': newM.appendRotation(-90, Vector3D.X_AXIS); break; case 'backwards': newM.appendRotation(90, Vector3D.X_AXIS); break; case 'left': newM.appendRotation(-90, Vector3D.Y_AXIS); break; case 'right': newM.appendRotation(90, Vector3D.Y_AXIS); break; } oldQ.fromMatrix(container.transform); newQ.fromMatrix(newM); resultQ.multiply(oldQ, newQ); container.transform= resultQ.toMatrix3D(); }
This works fine for the initial rotation. But any subsequent rotations don’t work correctly. I think I’m doing something fundamentally wrong.
I’ll take a look at the documentation and example you posted.
|
Luca, Sr. Member
Posted: 24 March 2013 12:12 PM Total Posts: 230
[ # 8 ]
What do you think about this ?
package { import away3d.containers.*; import away3d.core.math.*; import away3d.debug.Trident; import away3d.entities.*; import away3d.materials.*; import away3d.primitives.*; import away3d.utils.*; import flash.display.*; import flash.events.*; import flash.geom.Matrix3D; import flash.geom.Vector3D; [SWF(backgroundColor="#000000", width="800", height="600", frameRate="60", quality="LOW")] public class QuaternionTest extends Sprite { //engine variables private var _view:View3D; //scene objects private var _plane:Mesh; private var Cube:Mesh; private var tri:Trident; private var RotateByQuaternion:Boolean;
public function QuaternionTest() { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; //setup the view _view = new View3D(); addChild(_view); //setup the camera _view.camera.x = 0.0; _view.camera.y = 0.0; _view.camera.z = -250.0; _view.camera.lookAt(new Vector3D()); tri = new Trident( 100, true ); _view.scene.addChild( tri ); Cube = new Mesh( new CubeGeometry( 50, 50, 50 ), null ); _view.scene.addChild( Cube ); Cube.x = 0.0; Cube.y = 0.0; Cube.z = 0.0; Cube.rotationX = 90; // <- THIS SWAP Y-Z AXIS ? // RotateByQuaterni // setup the render loop addEventListener( Event.ENTER_FRAME, _onEnterFrame ); // stage.addEventListener( Event.RESIZE, onResize ); // onResize(); } private function Qr():void { var RotationQX:Number = 0.01; var RotationQY:Number = 0.01; var RotationQZ:Number = 0.01; var qrx:Quaterni Quaternion(); var qry:Quaterni Quaternion(); var qrz:Quaterni Quaternion(); qrx.fromAxisAngle( new Vector3D( 1, 0, 0 ), RotationQX ); qry.fromAxisAngle( new Vector3D( 0, 1, 0 ), RotationQY ); qrz.fromAxisAngle( new Vector3D( 0, 0, 1 ), RotationQZ ); var mrx:Matrix3D = new Matrix3D(); mrx.identity(); var mry:Matrix3D = new Matrix3D(); mry.identity(); var mrz:Matrix3D = new Matrix3D(); mrz.identity(); qrx.toMatrix3D( mrx ); qry.toMatrix3D( mry ); qrz.toMatrix3D( mrz ); //Cube.sceneTransform.append( mrx ); Cube.sceneTransform.append( mry ); //Cube.sceneTransform.append( mrz ); }
private function Mr():void { var RotationQX:Number = 0.01; var RotationQY:Number = 0.01; var RotationQZ:Number = 0.01; var mrx:Matrix3D = new Matrix3D(); mrx.identity(); var mry:Matrix3D = new Matrix3D(); mry.identity(); var mrz:Matrix3D = new Matrix3D(); mrz.identity(); mry.appendRotation( 1, new Vector3D( 0, 1, 0 ) ); //Cube.sceneTransform.append( mrx ); Cube.sceneTransform.append( mry ); //Cube.sceneTransform.append( mrz ); } /** * render loop */ private function _onEnterFrame(e:Event):void { if( RotateByQuaternion ) Qr(); else Mr(); _view.render(); } /** * stage listener for resize events */ private function onResize(event:Event = null):void { _view.width = stage.stageWidth; _view.height = stage.stageHeight; } } }
|
Luca, Sr. Member
Posted: 24 March 2013 12:16 PM Total Posts: 230
[ # 9 ]
i have found a bug ...
i wrote in the previous post:
var qrx:Quaternion = new Quaternion();
var qry:Quaternion = new Quaternion();
var qrz:Quaternion = new Quaternion();
|
Iogen, Newbie
Posted: 24 March 2013 12:37 PM Total Posts: 9
[ # 10 ]
Thank you. Code looks interesting. When running your example I just get a blank screen though.
I tried to implement your QR method in my project but it doesn’t seem to rotate at all now.
private function rotateGame(x:int, y:int, z:int):void { var RotationQX:Number = x; var RotationQY:Number = y; var RotationQZ:Number = z; var qrx:Quaternion = new Quaternion(); var qry:Quaternion = new Quaternion(); var qrz:Quaternion = new Quaternion(); qrx.fromAxisAngle( new Vector3D( 1, 0, 0 ), RotationQX ); qry.fromAxisAngle( new Vector3D( 0, 1, 0 ), RotationQY ); qrz.fromAxisAngle( new Vector3D( 0, 0, 1 ), RotationQZ ); var mrx:Matrix3D = new Matrix3D(); mrx.identity(); var mry:Matrix3D = new Matrix3D(); mry.identity(); var mrz:Matrix3D = new Matrix3D(); mrz.identity(); qrx.toMatrix3D( mrx ); qry.toMatrix3D( mry ); qrz.toMatrix3D( mrz );
container.sceneTransform.append( mrx ); container.sceneTransform.append( mry ); container.sceneTransform.append( mrz ); }
The cube just remains stationary no matter what values I pass in.
|
ranoya, Newbie
Posted: 24 March 2013 12:45 PM Total Posts: 29
[ # 11 ]
Iogen, didn’t you try just this simpler solution? :
private function rotateGame(direction:String):void {
switch(direction){ case 'forwards': container.transform.appendRotation(-90, Vector3D.X_AXIS); break; case 'backwards': container.transform.appendRotation(90, Vector3D.X_AXIS); break; case 'left': container.transform.appendRotation(-90, Vector3D.Y_AXIS); break; case 'right': container.transform.appendRotation(90, Vector3D.Y_AXIS); break; }
The quaternions are necessry when you plan to interpolate orientations, whith Tween, for example. But I think that it’s not the actual case.
|
Luca, Sr. Member
Posted: 24 March 2013 12:46 PM Total Posts: 230
[ # 12 ]
Yes, rotate container won’t work…. mmmm
|
Iogen, Newbie
Posted: 24 March 2013 12:49 PM Total Posts: 9
[ # 13 ]
I’ll try rotating all children instead.
|
Iogen, Newbie
Posted: 24 March 2013 12:53 PM Total Posts: 9
[ # 14 ]
This doesn’t seem to work either
for(var i:int; i < container.numChildren; i++){ container.getChildAt(i).sceneTransform.append( mrx ); container.getChildAt(i).sceneTransform.append( mry ); container.getChildAt(i).sceneTransform.append( mrz ); }
The simple solution above causes gimbal locks (some of the axis become locked in the same axis). I also just changed X and Y for simplicity. I will also be changing the Z axis to orientate to the correct edge (although I could move the camera for this).
|
ranoya, Newbie
Posted: 24 March 2013 01:00 PM Total Posts: 29
[ # 15 ]
Is this container children of other object?
|