Jump to content

New Feature : AddRotation()


jerome
 Share

Recommended Posts

Hi people,

I'm about to implement a new useful feature to the core. For now, it's called addRotation().

What is it for ?

Well, usually the BJS users aren't big fans of quaternions to manage their mesh rotations, although the quaternions are the best tools to achieve it.

Quaternion aren't intuitive, so people prefer the Euler angles, right ?

Moreover BJS imposes the rotation order, what is, if I'm not wrong, YXZ. This means that, when you set a mesh rotation (x, y, z), it is rotated first around Y, then around X and finally around Z in its local space. This is important because the rotation is not commutative : if you rotate a mesh for, say, 30° around Y and then for 20° around X, you won't get the same final orientation than if you rotate it first for 20° around X and then only for 30° around Y. In brief, the rotation order really matters !

So, you want to use only the Euler angles and you are constrained by the engine rotation order : no surprise you can hardly achieve the rotation you really want.

Here's comes addRotation(x, y, z) to the rescue !

addRotation() will do 3 things for you :

- to let you use only Euler angles, whatever the internal mesh rotation is Euler or quaternion based (note : under the hood, addRotation() works with quaternions, but it's hidden for your convenience)

- to allow you to decompose your rotation by steps in your custom order to achieve your final orientation : you can rotate a mesh first around X, then around Y, then around X again, then around Z, etc.

- to update the initial mesh rotation values for you : if the rotation is Euler based, it's updated as Euler angles (mesh.rotation), if it's a quaternionRotation (mesh.rotationQuaternion), the quaternion is updated.

How does it work ?

Just give the mesh an initial rotation, or none, (this rotation can be Euler angles or a quaternion, as you want), then add your rotation steps to achieve the wanted final orientation :

mesh.rotation.x = Math.PI / 4.0;        // initial rotation around x
mesh.addRotation(0, Math.PI / 3.0, 0);  // the mesh is fisrt rotated around X, then only around Y for PI/3

// you can even link all the rotation steps
// here X first, then Z, finally Y
mesh.addRotation(x1, 0, 0).addRotation(0, 0, z2).addRotation(0, y3, 0);

// the mesh rotation property is computed for you
console.log(mesh.rotation);

First demo :http://www.babylonjs-playground.com/#1PON40

The left box is the model box. The central box is rotated as usual for PI/3 around X and PI/2 around Y. The BJS rotation order makes it rotate first around Y, then around X.

The right box is given an initial rotation for PI/3 around X, then a rotation step is added for PI/2 around Y. You can see that the final orientation differs.

If you have a look at the console where the box2 rotation is displayed : http://www.babylonjs-playground.com/#1PON40#1 you will notice that the Euler angles needed to achieve this final orientation have a z value, although you didn't specify anything about Z. Simply because this is the Euler rotation to be done in the required BJS rotation order to achieve this final orientation. Something you wouldn't probably have found by yourself just playing with Euler angles ...

Let's go further with the torus wheel challenge.

Remember the number of times that, in this forum, people tried out to use the BJS provided shape called torus and to use it as a car wheel. It's damned complex because the torus is designed horizontally in its local space and we need to make rotate either around its central axis (rolling), either around a vertical axis (wheel direction). So some head hache with quaternions or mesh.rotate() once in the local space, once in the world space.

Let's try an easier way. Here's the just born torus : http://www.babylonjs-playground.com/#1PON40#2

Let's set it vertical as an initial rotation around Z : http://www.babylonjs-playground.com/#1PON40#3

Too bad the method debugLayer.shouldDisplayAxis() doesn't currently display anything, just keep in mind the torus local axis at this step :

  • Y is the torus central axis (so now horizontal after this first rotation around Z)
  • X is, now the torus is vertical, the vertical axis,
  • Z keeps unchanged along the world Z axis.

So in order to make the wheel roll, we will give each frame, from this initial rotation, an extra rotation around X first (wheel direction) and then a rotation around the torus central axis Y

http://www.babylonjs-playground.com/#1PON40#4

As you can see, the code is quite short and intuitive : I don't know the BJS required rotation, but I know how to set my torus orientation step by step using only Euler angles. No need for quaternion or space switching here. I just "build" each frame the way to achieve the final rotation with my own rotation steps and my own order.

Then it's quite easy to animate car wheels : http://www.babylonjs-playground.com/#1PON40#5 

 

Have fun ;)

 

 

Link to comment
Share on other sites

Brilliant work as ever  Jerome.

7 hours ago, jerome said:

Moreover BJS imposes the rotation order, what is, if I'm not wrong, YXZ

Having done quite a bit of work on rotations the imposed order is ZXY, you can check this out at http://babylonjsguide.github.io/advanced/Applying_Rotations.html

Obviously this makes no difference to your new addRotation function and I am being very pedantic.

I can see the new function being extremely useful.

Link to comment
Share on other sites

I just read accurately your documentation, John. Well, I've omitted to precise that mesh.addRotation() only modifies the mesh properties .rotation or .rotationQuaternion, what both sets the mesh rotation in its local space only.

So, it's coherent with your doc here : http://babylonjsguide.github.io/advanced/Applying_Rotations.html#yxz-local-axes-yaw-pitch-roll

Link to comment
Share on other sites

OK got it now.

When x, y, z are considered as rotations in LOCAL space then mesh.rotation(x, y, z)  applies the rotations in the order y, x, z   see  http://www.babylonjs-playground.com/#1ST43U#3

When x, y, z are considered as rotations in WORLD space then mesh.rotation(x, y, z)  applies the rotations in the order z, x, y see  http://www.babylonjs-playground.com/#1ST43U#2

Therefore addRotation is accumulating rotations in LOCAL space.

EDIT I work out this stuff then forget all about it.

 

Link to comment
Share on other sites

Actually both methods, addRotation() and rotate(), accumulates the rotation.

BJS only knows the order YXZ when it takes in account the mesh property values .rotation or .rotationQuaternion. BJS reads these values and computes the Wolrd Matrix from them before passing it to the GPU.

If you use addRotation(), you modify the initial .rotation or .rotationQuaternion values by accumulating your own values each call. At the end, you've got new values for .rotation or .rotationQuaternion. BJS will read them and compute the World Matrix using the YXZ order only.

The same if you use rotate() : you accumulate new rotation values, so the order of your call matters, because this modifies each call the value of mesh.quaternionRotation.

So if you call mesh.rotate(z) before mesh.rotate(y), you won't get the same final result than the inverse order.

Whatever the order you choose, what has a big importance for the final rotation, BJS just get the final state, it is to say the final value of .quaternionRotation, then computes the World Matrix ... using the YXZ order only again (if this order matters when talking about quaternions).

Example : I changed the order of the calls to rotate() here http://www.babylonjs-playground.com/#1ST43U#16

As you said, addRotation() is a helper tool, working directly with Euler angles and only in the local space whereas rotate() works only with quaternions, rotation axis but either in the local and the world spaces. 

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...