Jump to content

Euler/Quaternoin conversion (bug?)


hen
 Share

Recommended Posts

another idea with an intermediate step :

compute your quaternion from the know euler angles

apply your quaternion rotation to your mesh

apply it also to the vertex triplet (X, Y, Z), the World axis normalized vectors, this will give you the rotated vectors (Xr, Yr, Zr)

then use RotationFromAxis(Xr, Yr, Zr), this will compute back the euler angles to rotate X, Y, Z to Xr, Yr, Zr

 

This may work, I hope ...

Link to comment
Share on other sites

@jerome I'm not sure I understand the 'triple vertex'. Your idea sounds interesting to recreate a Quaternion to Euler conversion function. But Euler to Quaternion, it seems more complex still.

Too bad babylon has no such function. @Deltakosh you think this kind of function is achievable? QuaternionToEuleur () and EulerToQuaternion () would help would be great and really much

Link to comment
Share on other sites

Using three vertices to represent orientation/rotation is not without it's uses, but I don't think it sounds practical here (as far as concept goes, it has uses, such as in understanding how a soft body spring system can produce rigid body like behaviour without explicit rotational terms - something I think was discussed in the Hitman whitepaper on using Verlet integration for rag dolls).

Can the OP's issue not be identified/corrected?

Link to comment
Share on other sites

Hi!  @Dad72, don't those functions already exist?

http://doc.babylonjs.com/classes/2.2/Quaternion#toeulerangles-rarr-vector3-classes-2-2-vector3-

http://doc.babylonjs.com/classes/2.2/Vector3#toquaternion-rarr-quaternion-classes-2-2-quaternion-

Now, as for producing expected results, I don't know about that.  :)  Let's visit a website...

http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/

@chg - notice the talk about "problems" and "The cutoff point for singularities is set to 0.499 and -0.499".

@hen - notice the talk about swapping Y and Z.

Down in a section titled "Alternative Euler Angle Sequences"...  Regarding Amy de Buitléir's paper...

Quote

Instead of defining the quaternion in terms of rotations about the absolute coordinates i, j and k the document defines 3 mutually perpendicular axes e1, e2 and e3. So, to generate the mapping for a given set of Euler angles the user needs to map e1, e2 and e3 to i, j or k in the appropriate order. This involves the value e which seems to define a sort of left or right handedness, but on its own this is not enough to define the Euler angle sequence, will still need to define the e1, e2, e3 to i, j, k mapping.

It's all alien to me.  I think we need to be raised around Euclidians or Orthogonoids... to understand any of it.  But Jerome might be talking about the theory quoted above.  Who would know, unless you can speak Orthogona.  heh.  But there is one possible problem with the Jerome idea.  The quaternion values could be applied via things like applyImpulse and springs and other physics engine stuff.  Therefore, if the 3-axis values need to be applied WHILE the object is in rotation (real-time/live), then the physics engine will need to be the code that sets values on those three axes.  In other words, the physics engine would maintain its own body.currentEulerValues, and that could slow down the motion of the ocean (bog the physics).

If there is no need for live/real-time converting (converting while a physics or animation motion is happening)... then things are easier... probably...  like I have a clue.

chg says "Can the OP's (original poster) issue not be identified/corrected?"  hehe.  THAT is the hardest question so far!  :D

http://urbanproductions.com/wingy/babylon/thruster/t26/flyer26.htm

My goofy flyer.  Hit/hold rotate buttons, see the "qRot" quaternion X, Y, Z, W values changing at the top of the screen.  ApplyImpulse-driven Quat Rot.  Pretty fast numbers, eh?  Convert to Euler on the fly?  hmm.

Link to comment
Share on other sites

Hey D72, you just repeated the topic title.  [bug?]  :D

hahaha... sorry.  But this is funny!  I got some experience with quat.toEuler() when I coded that flying craft.  It's evil.  :D  I don't think there is a bug in the code.  Yet, toEuler() is seriously unpredictable (or should I say predictable, but ONLY with predictable input data?).  It is a very unusual function.  It works and doesn't work, all at the same time!  hehe.  Not normal for software, eh?

So... when you tried to categorize this topic into "Bugs" category... it was the PERFECT opportunity for me to ask "What IS a bug, Dad72?"

Comedy-wise, it all worked perfectly!  You did tests, saw un-predictable results,  and asked if it is a bug.  haha.  Oh man, that's just too funny.  I hope you can laugh along with me, Dad.

Truth is, I think attempting to "debug" quat.toEuler... will give anyone/everyone... a huge tumor.  It's crazy.  No human should try it... and if you do, have a medical team standing by. :)  I once heard a statement about Quats.  You never copy one.  Only make a new one.  This is because the ORDER that they were created... must be known... in order to copy one.  So, when a physics engine creates one to track the bounce of an impostor off-of a wall, the physics engine makes the quaternion (yaw, pitch, roll) in the order IT wants to use for THAT bounce (the shortest direction of rotation to accomplish the wanted bounce trajectory).  Then, the physics engine completely forgets what order of rotation it used.  It doesn't record the order.

So, now, along comes "toEuler"... and makes a bunch of assumptions about axes order... and using IT'S assumptions, might be successful, might fail.  IF the toEuler() successfully GUESSES the axes order of the Quat... we have success.  What does that amount-to?  hmm.  :)  1 in 9 chance of being successful on a random Quaternion of unknown order?  hehe. 

Anyway, I'm just speculating.  Are you going to study it deep, Dad?  Wear a safety helmet, and pack lots of food!  :)  I'm watching from the sidelines... but with full (safe) interest.

Link to comment
Share on other sites

27 minutes ago, Wingnut said:

I once heard a statement about Quats.  You never copy one.  Only make a new one.  

That sounds a bizarre claim for a mathematical property described by 4 numbers and without extra hidden state. If two quaternions have the same numbers for each of their 4 respective components they represent the same rotation.

So, when a physics engine creates one to track the bounce of an impostor off-of a wall, the physics engine makes the quaternion (yaw, pitch, roll) in the order IT wants to use for THAT bounce (the shortest direction of rotation to accomplish the wanted bounce trajectory).

Why would a physics engine using quaternions use yaw, pitch and roll for that? That's insane! Maybe it might use axis-angle for rotation and convert that to a quaternion...

Then, the physics engine completely forgets what order of rotation it used.  It doesn't record the order.

Axis order is something important to be consistent with when working with Euler angles, I'm almost completely sure it doesn't actually apply to working with quaternions.

As far as axis order goes though, I don't think it's asking too much of an engine that it pick a convention, at least as a default, and then document that it uses it, and and then use it consistent when working with angles. The OPs example involves converting from Euler to quaternions and back again, without supplying any hint as to axis ordering, surely one can expect the axis order convention to be consistent between conversions to and from Euler angles.

Link to comment
Share on other sites

In made Wingnut, there is a bug (I think) that if the Y value of Vector3 is 0, the conversion toEulerAngles() (after conversion quaternion)  returns a bad result, but if we put 0.000001 (! = 0) the result of the conversion of quaternion to vector3 is correct.

The other value X and Z may be 0, it works well it is the Y value is 0, which foiled the conversion toEulerAngles()

see line 24 and 25 : http://www.babylonjs-playground.com/#20LBVQ#15

No need to laugh Wingnut. The goal is to discover what created this abnormal behavior and maybe it is because of this value Y 0 on a vector3 and conversion to quaternion and again in conversion to Euleur.

try to uncomment the line 25 and line 24 to comment and see the difference results.

 


 

Link to comment
Share on other sites

:)  Have you tried testing negative values?   Maybe try var r = new BABYLON.Vector3(-3.14, -.001, 1.57);  ==>

{ x: 0.0015926535897932, y: 0.0009999999999921686, z: -1.5715926535897933 }  (x & y slightly bad [un-rounded], and all values changed signs)

Also, you are using BJS vector3.toQuaternion() for your tests.  A physics engine might NOT use BJS vector3.toQuaternion().  It might use its OWN quaternion-maker (possibly using a different order).  Not sure.

Using 6-12 applyImpulse "jets" on the test box... might be interesting.  Maybe place 6 buttons on-screen... for impulse Right/Left, Up/Down, clockwise/counter-clockwise.  Maybe place the readout of quaternion and toEuler on a plane with dynamicTexture text... so we can watch values while impulsing.

To do this perfectly, you will need TWELVE (12) impulsers.  http://urbanproductions.com/wingy/babylon/misc/info01.jpg

(see the left side of this diagram.)  If you want to use applyImpulse to rotate a mesh WITHOUT any position change, you need use TWO impulses to rotate a single direction on each axis.  For example, a negative Y rotation needs a +X-aimed impulse AND a -X-aimed impulse, both the same power.  They happen on opposite sides of the center, offset the same amount as each other (twisting action).  Otherwise, the box will change position when impulse-rotated.

Visiting the flyer again, when you hit the rotate +Y button, two impulses happen... to cause a rotation without position change.  Perfect rotation without positional "skid".

I don't know if you want to build a physics-based impulse-rotater test scene, but if you did, we could then use keypresses (or on-screen buttons) to rotate the box negative or positive on any axis, and watch quat.toEuler() doing real-time calculations, printed to screen.  This would be a more-complex, but more-thorough test scene.  *shrug*

http://urbanproductions.com/wingy/babylon/thruster/t26/js/controller08.js

That is the "controller" code for the flyer.  In the first half of that file, you will see the rotation functions (rotPositiveX, rotNegativeX, etc), and each has a little ascii diagram showing what is being done.  Each func does 2 impulsings. Feel free to use that code, as wanted.  All 6 of my rotation funcs... COULD be done with a single function, and a switch/case statement, I suspect.  :)

Link to comment
Share on other sites

For the spectators:  I keep talking about physics engines (PE)... because PE need Quaternions.  If a user creates a mesh, rotates it via Vector3 Euler, and then calls mesh.setPhysicsState(...), the Euler rotation will be nulled to 0, 0, 0.  Physics engines want nothing to do with Vector3 Euler rotation.

To this day, I don't think anyone has EVER been able to set a physics impostor rotation... using a vector3 Euler.  There IS an .updatePhysicsBodyPosition() on AbstractMesh.  It works for positioning an imposter (a mesh with setPhysicsState).  But we do not have an updatePhysicsBodyRotation().  The PE's would hate us... if we built one.  :D

So, this is why Wingnut likes having Physics Engine mesh.applyImpulse(random, random)... create the Quaternions for our .toEuler testing.  Nothing creates a better random Quaternion... than a tumbling physics-active box.  Boxes tumble quite actively, so the Quaternion rotation values of the tumbling box... are made by the PE and should be quite random.

In short, PE-made Quats should be great testing sources for toEuler(), yes?  I think so.  :)

Link to comment
Share on other sites

http://urbanproductions.com/wingy/babylon/phytater/phytater03.html

Early tests :)  Click the +x, -x, +y, etc.  (repeatedly ok, but not set for button hold-down)

Right now, the STOP button un-registers the mesh from the physics engine, so once you click stop, you must reload... to do more rotating.

The EULERIZE button... is for AFTER clicking STOP.  What it does... is set the non-physics mesh.rotation... to the current Euler values.  You can see a report in the console.

I truly expected.... that when I click STOP and then EULERIZE... I would see the mesh "jerk" or "jump".  It does not.  I am surprised at that.  Ain't learning GREAT?!

These rotations are using the dual applyImpulse method... mentioned in my previous post.  Rotation power can be adjusted using the global 'offset' variable, and/or adjust box mass.  The zip version is available here:  http://urbanproductions.com/wingy/babylon/phytater/phytater03.zip

Want to see something fun?  Click the +Y button about 20 times.  Now watch the toEulerAngles X and Z values.  They alternate back and forth between -1.570796 and +1.570796.  Interesting! 

Do the same with +X button.  X and Z Eulers are doing strange things with 0 and 3.141.  Z is alternating between +3.14 and 0 and -3.14.  X never gets a negative 3.14.  Weird.

 

Link to comment
Share on other sites

Looks like i found something that works!
Thanks to cannon.js!

toEuler : function(mesh, target, order){
        order = order || "YZX";

        var heading, attitude, bank;
        var x = mesh.rotationQuaternion.x, y = mesh.rotationQuaternion.y, z = mesh.rotationQuaternion.z, w = mesh.rotationQuaternion.w;

        switch(order){
            case "YZX":
                var test = x*y + z*w;
                if (test > 0.499) { // singularity at north pole
                    heading = 2 * Math.atan2(x,w);
                    attitude = Math.PI/2;
                    bank = 0;
                }
                if (test < -0.499) { // singularity at south pole
                    heading = -2 * Math.atan2(x,w);
                    attitude = - Math.PI/2;
                    bank = 0;
                }
                if(isNaN(heading)){
                    var sqx = x*x;
                    var sqy = y*y;
                    var sqz = z*z;
                    heading = Math.atan2(2*y*w - 2*x*z , 1 - 2*sqy - 2*sqz); // Heading
                    attitude = Math.asin(2*test); // attitude
                    bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
                }
                break;
            default:
                throw new Error("Euler order "+order+" not supported yet.");
        }

        target.y = heading;
        target.z = attitude;
        target.x = bank;
    },

 

Link to comment
Share on other sites

Interesting!  Heading, attitude, and bank, instead of yaw, pitch, and roll.  hmm.   All in all, good research work, Hen!

http://urbanproductions.com/wingy/babylon/phytater/phytater04.html   (and phytater04.zip)

This one displays both toEuler conversions.  Also, after clicking stop (un-register mesh from PE)... the Eulerize button in this version... sets mybox.rotation to the values returned from the CannonJS toEuler().  No mesh rotation change upon Eulerize.  Working fine.  I am using the default CannonJS toEuler() order.  (see http://schteppe.github.io/cannon.js/docs/files/src_math_Quaternion.js.html#l288 as wanted).

Good deal.  Glad to hear you are rolling again, Hen!

@chg - I never really addressed your post, because... I barely know what I am doing AT ALL.  :)  I could not agree or dispute anything you said, because I needed to do MUCH more research and testing before answering anything.  My apologies if I seemed cold... but you brought up all sorts of great points and thoughts... and I don't have any experience.  I am a "need to see it happen" kind of person, and thus I failed high school Algebra 3 years straight (42 years ago). Those teachers could not show me any real world examples of needing to "factor polynomials".  :D  Party on!

@dad72 - I still can't determine if we have any bugs in BJS toEulerAngles().  Your thoughts?  Anyone's thoughts?  (thx)

Link to comment
Share on other sites

1 hour ago, Wingnut said:

@dad72 - I still can't determine if we have any bugs in BJS toEulerAngles().  Your thoughts?  Anyone's thoughts?  (thx)

I give up. it took too my head whether 'bug' or 'no bug'.
Hen seems to be reached to use Euler with Cannon.js if I understand. Too bad Oimo.js does not offer the same thing and with so many impostor. because Oimo is faster, but Cannon, now more complete.

Link to comment
Share on other sites

10 minutes ago, Dad72 said:

I give up. it took too my head whether 'bug' or 'no bug'.
Hen seems to be reached to use Euler with Cannon.js if I understand. Too bad Oimo.js does not offer the same thing and with so many impostor. because Oimo is faster, but Cannon, now more complete.

You can still use Oimo.. just use that code snipped i posted above to convert the quaternoin to euler.

Link to comment
Share on other sites

Oimo not proposing any impostors Cannon offers. There are certain things which should Oimo and other Cannon is a better choice, but you can not use 2 physics engine, the choice would be to have a 3rd plugin that mélangerais Oimo and Cannon.
I have another solution, I put my projects going in the trash and I turn to other things :)

Link to comment
Share on other sites

@hen  Yes, I just put Cannon's toEuler... onto the Babylon Quaternion class.  So, the old version is called toEulerAngles() and the new version is called toEuler().  They do not have the same parameter syntax, but no big deal.

http://playground.babylonjs.com/#I764D#3

See our new func at line 312.  That new func is called in the printstuff() func... at line 866.

This PG version is running OimoJS.  I had some trouble getting the impulses to work.  I had to set a gravity of neg or pos 3.9 in line 356.  When I did that, the impulses started working, but that makes the box fall or rise... because the box has a mass of 0.1.  I heard that Oimo needs SOME values, or else it ignores the parameter.   Not sure about all that.

But yes, Cannon's toEuler works as a stand-alone func, or as a member of most/any Quaternion-class objects, it seems.

So how did I keep mybox from sinking?  By constantly lifting it back up into place... in the render loop.  See line 875.  I was surprised to NOT need line 876, the updatePhysicsBodyPosition().  In fact, the impulses quit working again, once I activated line 876.

Thus... I might have said something wrong, earlier.  Maybe we CAN manually rotate a physics-active mesh, and call updatePhysicsBodyPosition(), and it will take that rotation onto the imposter.  In other words, updatePhysicsBodyPosition() might do both position AND ROTATION updating.  COOL!  Not sure.  Someday I'll try it.

Meantime, that need for a >3.8 gravity... is not right.  Impulses should work fine, with 0, 0, 0 gravity.  They don't.  Try setting line 356 to 0, 0, 0.  Impulses will fail.  Likely a Wingnut mistake.  :)  Party on!

PS:  For those who have curiosity about the "twisting"  2-impulse-per-button physics-rotating system,  see the global offset variable in line 276?  That is the distance from box center... that the twin-impulses are happening (the contact_points).  The box is size 10, so one would expect that the maximum setting for offset is 4.99.  Anything larger would make the impulses "miss" the box surface.  But you can set that offset to 25 or more... no problems.  The impulse power becomes quite "beefy"... due to leverage.  Cool, eh?  *nod*   The Twisting Wingnut ear size.  Big Wingnut ears = high twisting torque. :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...