Rotating an ObjectContainer3D on all 3 axis. Looking for advice.

Software: Away3D 4.x

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:inty:intz: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:3rotationX:totalXrotationY:totalYrotationZ: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(1axis);
object.transform.appendRotation(angleaxis); 

If you want to rotate it along the world y axis:

object.transform.appendRotation(angleVector3D.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 smile

I’ve tried implementing your solution as follows:

private function rotateGame(x:inty:intz:int):void
  {
   
var temp:Matrix3D = new Matrix3D();
   
totalY += y;
   
totalX += x;
   
totalZ += z;
   
temp.appendRotation(totalXVector3D.X_AXIS);
   
temp.appendRotation(totalYVector3D.Y_AXIS);
   
temp.appendRotation(totalZVector3D.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!

 

   

Avatar
Luca, Sr. Member
Posted: 24 March 2013 08:27 AM   Total Posts: 230   [ # 3 ]

Use quaternion ?

   

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?

   

Avatar
Luca, Sr. Member
Posted: 24 March 2013 10:13 AM   Total Posts: 230   [ # 5 ]

I don’t have implemented them for now but look this:

https://github.com/LucaEstiva/AwayGameMaker
see the class CoreController

and see what is rotating ....

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix3D.html

http://en.wikipedia.org/wiki/Quaternion
http://www.toymaker.info/Games/html/matrices.html
http://www.estiva2.altervista.org/DirectX/DirectXGraphicsSDK.php
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2/Quaternions.php

import away3d.core.math

var q:Quaternion = new Quaternion();
var m:Matrix3D = new Matrix3D();
m.identity(); // If you want a uniform scaling
 
q.fromMatrix( m ); // or not
q.fromAxisAngle( new Vector3D( 1, 0, 0 ), 90 ); // DEGREE OR RADIANS ?
q.toMatrix3D( m );

can you try this for all and share ? smile

   

Avatar
Luca, Sr. Member
Posted: 24 March 2013 10:24 AM   Total Posts: 230   [ # 6 ]

http://www.estiva2.altervista.org/DirectX/DirectXGraphicsSDK.php

Windows DirectX Graphics Documentation
Direct3D 9
Reference for Direct3D 9
D3DX Reference
D3DX Structures
D3DXMATRIX Structure
D3DMATRIX
Transforms (Direct3D 9)

or

http://code.google.com/p/flint-particle-system/source/browse/trunk/src/org/flintparticles/threeD/geom/Quaternion.as

   

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(-90Vector3D.X_AXIS);
     break;
    case 
'backwards':
     
newM.appendRotation(90Vector3D.X_AXIS);
     break; 
    case 
'left':
     
newM.appendRotation(-90Vector3D.Y_AXIS);
     break;
    case 
'right':
     
newM.appendRotation(90Vector3D.Y_AXIS);
     break; 
   
}
   
   oldQ
.fromMatrix(container.transform);
   
newQ.fromMatrix(newM);
   
resultQ.multiply(oldQnewQ);
   
container.transformresultQ.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.

   

Avatar
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.0.0;
   
_view.camera.0.0;
   
_view.camera.= -250.0;
   
_view.camera.lookAt(new Vector3D());
   
   
tri = new Trident100true );
   
_view.scene.addChildtri );
   
   
   
Cube = new Mesh( new CubeGeometry505050 ), null );
   
_view.scene.addChildCube );
   
Cube.0.0;
   
Cube.0.0;
   
Cube.0.0;
   
   
Cube.rotationX 90// <- THIS SWAP Y-Z AXIS ?
   //    RotateByQuaterni
   
   // setup the render loop
   
addEventListenerEvent.ENTER_FRAME_onEnterFrame );
   
//
   
stage.addEventListenerEvent.RESIZEonResize );
   
//
   
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 Vector3D10), RotationQX );
   
qry.fromAxisAngle( new Vector3D01), RotationQY );
   
qrz.fromAxisAngle( new Vector3D00), RotationQZ );
   
   
   var 
mrx:Matrix3D = new Matrix3D();
   
mrx.identity();
   var 
mry:Matrix3D = new Matrix3D();
   
mry.identity();
   var 
mrz:Matrix3D = new Matrix3D();
   
mrz.identity();
   
   
qrx.toMatrix3Dmrx );
   
qry.toMatrix3Dmry );
   
qrz.toMatrix3Dmrz );
   
   
   
//Cube.sceneTransform.append( mrx );
   
Cube.sceneTransform.appendmry );
   
//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.appendRotation1, new Vector3D01) );
   
   
//Cube.sceneTransform.append( mrx );
   
Cube.sceneTransform.appendmry );
   
//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;
  
}
  
 }
   

Avatar
Luca, Sr. Member
Posted: 24 March 2013 12:16 PM   Total Posts: 230   [ # 9 ]

i have found a bug ... smile

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:inty:intz: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 Vector3D10), RotationQX );
   
qry.fromAxisAngle( new Vector3D01), RotationQY );
   
qrz.fromAxisAngle( new Vector3D00), RotationQZ );
   
   var 
mrx:Matrix3D = new Matrix3D();
   
mrx.identity();
   var 
mry:Matrix3D = new Matrix3D();
   
mry.identity();
   var 
mrz:Matrix3D = new Matrix3D();
   
mrz.identity();
   
   
qrx.toMatrix3Dmrx );
   
qry.toMatrix3Dmry );
   
qrz.toMatrix3Dmrz );

   
container.sceneTransform.appendmrx );
   
container.sceneTransform.appendmry );
   
container.sceneTransform.appendmrz );
  

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(-90Vector3D.X_AXIS);
     break;
    case 
'backwards':
     
container.transform.appendRotation(90Vector3D.X_AXIS);
     break; 
    case 
'left':
     
container.transform.appendRotation(-90Vector3D.Y_AXIS);
     break;
    case 
'right':
     
container.transform.appendRotation(90Vector3D.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.

   

Avatar
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:intcontainer.numChildreni++){
    container
.getChildAt(i).sceneTransform.appendmrx );
    
container.getChildAt(i).sceneTransform.appendmry );
    
container.getChildAt(i).sceneTransform.appendmrz );
   

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?

   
   

X

Away3D Forum

Member Login

Username

Password

Remember_me



X