Page 1 of 1

How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Thu Oct 08, 2020 8:54 pm
by haydeng21
I'm new to Bullet so please excuse any noobness in my question :)

I'm working on a skateboard simulation using Ammo.js, the javascript version of Bullet, and my objective is for the skateboard to do a varial (rotate around the local Z_forward axis and the local Y_up axis at the same time). Here's a slow mo video of a varial for reference: https://www.youtube.com/watch?v=K1FHvxXh5NU

In my simulation I'm using a btRaycastVehicle as the skateboard and I've been successful at using torque to make the skateboard rotate around the Z axis or the Y axis, but only when torque is applied to one of those axis at a time. If I apply torque to both the Z and Y axis it results in a spiraling motion, which is undesired. You can see what I mean by going to the simulation (https://skateboard.workroomvr.com) and once in the park press space to jump and then hold H and Y at the same time. I've searched the web for solutions to this problem and many sources state that a rigid body (RB) can only rotate around 1 axis at a time, although that axis can shift. That appears to be exactly what happens when I apply a combined torque to the skateboard.

So the only potential solution I've found (https://answers.unity.com/questions/375 ... eousl.html) is to use two different objects parented together and rotate each one around a single axis. That solution made sense to me but when I tried to achieve that with Bullet rigid bodies, I got stumped. I found no way to create a parent-child relationship between two rigid bodies. If you can please let me know but even so, I still foresee a problem with this solution because of the relationship between the parent RB (lets say it would receive the Y axis torque), the child raycastVehicle RB (receive all driving inputs and the Z axis torque), and the graphic skateboard (copying transform of raycastVehicle RB). Then I thought about making the raycastVehicle RB be the parent, have a child RB (for Y axis torque), and make the graphics skateboard copy the transform of the child RB. Makes some sense to me but that will result in the problem of the graphics skateboard and the raycastVehicle RB having separate transforms, which would eventually cause undesired effects.

Other thoughts and solutions I tried:

I looked into using compound shapes but I believe I need 2 rigid bodies to achieve the solution outlined above, since I need to apply different torque to both rigid bodies.

I've also tried using p2p, hinge, and 6dof constraints between the raycastVehicle RB and another RB to somewhat act as a parent-child relationship, but I couldn't make sense of how to put together a proper solution with that method.

I'm to the point now that I'm thinking I may have to resort to doing some sort of graphics-only animation based implementation of the varial (simple to create in blender) but I really want to figure out a physics implementation if possible, and I have a feeling it's not impossible.

Could anyone provide some insight on how I could accomplish my objective using physics? If not, would you go the route of creating an animation in blender and applying that to the graphics skateboard? My concern with that route is the graphics and physics will diverge when the animation is occurring.

Is there something I'm totally missing here? Maybe a way to achieve my objective without torque or a graphic animation?

Thanks in advance for any help!

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Fri Oct 09, 2020 4:17 pm
by drleviathan
Your skate simulation looks nice. It is off to a good start.

I watched the varial video carefully and played around with your sim. I have some ideas about things you could try, but first some feedback/perspective:

In physical games there are often trade offs between realistic physics and fun/playability of the game. Sometimes correct physics makes for not-fun games. The classic example is car-race-em games. The fact of the matter is: when a real car crashes at high speed it can go from in-control to out-of-control very quickly, and the crash itself can set the car tumbling faster than the human mind can track. For this reason car-race-em games typically tweak the physics: they might artificially increase gravity when the car is tracking the road (more friction) but reduce it when the car gets airborne (longer jumps). And they might inflate the car's intertia tensor in a crash, or artificially limit its angular velocity so the crash isn't so confusing.

All that ^^^ to say: when making a fun game it is ok to use "game physics" instead of "real physics". A key-framed varial might be the right fun solution.

Now on the task at hand: How to make the skateboard do a varial?...

I noticed that your ollie move is not realistic. The skateboard pops straight up whereas in a real ollie the skateboarder kicks the back down, causing the skateboard to rotate about a Y-axis centered at the rear wheel touch-point and gives the board's center-of-mass (COM) a non-zero linear velocity UP, and then uses their front foot to change the rotation to be about an opposite Y-axis centered at their foot touch-point (non-zero UP linear velocity is mostly unchanged, so the board continues moving up). Finally the board is stopped by their back foot (more or less horizontal to the ground) and the board and skater fall to the ground. A three-part motion, four-part if you differentiate the final rotation stop from the linear fall.

I mention that ^^^ because it seems to me a proper varial is very similar. From the video: kick-up to about 45-degrees (and the board's center of mass has non-zero upward velocity), then skater's heel sets the board in a ballistic rotation (upward linear velocity is mostly unchanged). When the board is parallel to the ground again but with the board flipped front to back and several inches off the ground... the skater stops the rotation, and they fall under gravity.

So the idea that occurs to me is: If you could figure out how to implement the ollie with such a logic structure: (1) kick, (2) change to ballistic angular motion, (3) stop angular velocity, (4) fall... then a varial would be a slight modification where the angular velocity at (2) is set "just right".

Which raises the question: What would be the "just right" angular velocity?

The answer to this is a little complicated and I don't want to get bogged down by details when there might be a simple approximation that will suffice, so I will mention the complication and then ignore it: when a rigid body has a non-symmetric inertia tensor its angular velocity is NOT invariant under ballistic tumbling. Its angular momentum is constant but its angular velocity varies over time! But the variation over time might be slow relative to the duration of the motion so we will assume that is the case and forget this complication.

Let's pretend the angular velocity of the skateboard body is constant while it tumbles...

There is an initial rotation of the body, let's call it Q0 (Q is for quaternion, which is how the rotation is probably represented under the hood).

There is a final rotation of the body when it is stopped and we'll call it Q1.

There is a duration of the tumble we'll call t01 (time from Q0 to Q1).

There is a rotation (call it Q01) which takes the body from Q0 to Q1. Rotation math allows us to write it as:

Q01 = Q0' * Q1 (where Q0' denotes the "inverse of Q0")

The rotation Q01 has an associated axis and angle which can be computed:

angle01 = Q01.getAngle()
axis01 = Q01.getAxis()


The constant angular velocity of the tumble can then be computed:

angularVelocity = (angle01 / t01) * axis01

So what this means is:

(1) if you know the initial and final rotations of the motion...
(2) and you know the duration of the motion...
(3) and if angular velocity is constant over time (approximately true)...
(4) then you can compute the angular velocity to achieve the motion

You set the angular velocity to from (4) and start a timer. When the timer is up (duration of time you used at (3)) you zero the angular velocity... and the body will be at approximately the rotation you wanted it to be.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Tue Oct 13, 2020 4:09 pm
by haydeng21
First off, thank you very much drleviathan for your time spent crafting this response to help me out! I greatly appreciate it.

In regards to the ollie, you're correct and I believe you've hit the nail on the head for how to create a realistic ollie. However, this skate simulation is just meant to be a fun game acting as a branding experience for skateboards.com so it doesn't need to be perfectly real, which is why I went with a central upwards force for the ollie.

I also agree that a proper varial would be very similar to a proper ollie like you've described, but for simplicity I'd like the varial to be implemented as an ollie (central upwards force) followed by a simultaneous rotation around the up and forward axis.

From my tests, research, and now your reply it appears that it's not going to be possible in the way that I desire - the user pressing both the Y and H keys to apply simultaneous torque to the rigidBody.

So here's my takeway from your answer. Please let me know if I'm thinking about this incorrectly.

Your breakdown of the simplistic way to calculate the correct angular velocity makes a lot of sense. But it seems to create a varial I'd have to use the steps and equations you laid out many times very quickly, right? So I'd set different target rotations (Q1's) throughout the desired varial rotation and use the equations you have suggested. Is that why you brought up that the varial should use logic similar to the ideal ollie? Meaning, Q0 would be the board riding on the ground and Q1 would be the board's rotation after it's been kicked up, then Q0 would become the rotation after the board was kicked up and Q1 would be the board's rotation after it's been kicked by the heel and sent into ballistic rotation, and so on? If that's the case then the solution seems to be calculating the correct sequence of angular velocities and the correct points in time throughout the varial trick to change the angular velocity. Do you have suggestions about which target rotations would result in the simplified varial I desire? I'm very rusty on my physics/quaternions so please correct me if I'm wrong but it seems like I'd need lots of different target rotations and lots of changes in angular velocity (maybe every frame?) to perform the varial correctly? If so, it means I'd need to make the varial be it's own separate button for the user to press, which would engage the sequence of rotations to make the board varial. That seems like a better solution than a key-framed varial since there'd be no mismatch between the graphics and physics skateboard, so that's what I'd like to do!

Thank you again for sharing your thoughts and knowledge and thanks in advance for any further help you can provide!

P.S. You mentioned that a key-framed/animated varial might be the way to go, and it would definitely be a simpler implementation than all these physics calculations, but how would you suggest solving for the mismatch between the graphics skateboard and physics skateboard? The main problem I foresee is that the forward-axis rotation would be graphic only (key-framed) and if the physics board were to land on its wheels when the graphic board was on it's deck (180 degrees difference) lets say, it would either look like the board was driving on its deck or there would need to be an instantaneous 180 degree rotation by the board to make the graphics and physics board match up again, which would look very unrealistic obviously.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Wed Oct 14, 2020 2:34 pm
by drleviathan
First of all I should mention: I now realize my recipe for making a varial is incorrect. The step where the delta rotation Q01 is computed is wrong because I was assuming the skateboard would take the shortest possible rotation from Q0 to Q1 and that is not what happens. It actually takes a more circuitous path to arrive at the orientation where the feet stop it. Unfortunately at this moment I don't know how to compute that path through quaternion space. I will think about it: clearly there are an infinite number of long paths that would work, but the one you want uses an angular velocity with an integral ratio between its components and/or its length.

No you wouldn't have to continually update the target rotation using my recipe. You would compute the angular velocity to move from A to B in time T, then set the body rotating and allow the physics engine to update the body until T seconds have passed. It is prescriptive only by slamming the angular velocity at t=0 and stopping it again at t=T. While playing the game it would be possible to start a varial next to an obstacle and have the tumbling motion interrupted by collisions. In this scenario your game would check the rotation at t=T to see if it was close to the expected rotation Q1 and if yes: stop the velocity (with the "feet") and land the varial. If not: the varial failed and you let it tumble and eventually reset to upright if necessary.

A "keyframed" solution would indeed render the skateboard as tumbling but wouldn't actually move the "physical" skateboard. This might work if you had a character+skateboard game and just wanted to make it easy for the character to appear to do tricks and always land them. But you're making a physical skateboard game so simple keyframe effects won't fit. Nevertheless, the point I was trying to make, and which you already seem to have adopted is: it is ok to fudge the physics in games to make them fun.

My idea was: a proper ollie is nearly identical to a varial and if you were to change your ollie to use the more complicated recipe, then it might take only a slight tweak of that to produce a varial. Right now I don't have any other ideas for how to do it.

In any case, the varial definitely has a complicated multi-step motion. At the very beginning the skateboard is on the ground and at the very end it is also on the ground but with front now pointing back. Ultimately it is a mere 180 degree flip about the vertical Y-axis, but it doesn't take the shortest path to get there.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Wed Oct 14, 2020 3:37 pm
by haydeng21
Thank you again for the quick response and updated thoughts!
drleviathan wrote: Wed Oct 14, 2020 2:34 pm No you wouldn't have to continually update the target rotation using my recipe. You would compute the angular velocity to move from A to B in time T, then set the body rotating and allow the physics engine to update the body until T seconds have passed. It is prescriptive only by slamming the angular velocity at t=0 and stopping it again at t=T.

In any case, the varial definitely has a complicated multi-step motion. At the very beginning the skateboard is on the ground and at the very end it is also on the ground but with front now pointing back. Ultimately it is a mere 180 degree flip about the vertical Y-axis, but it doesn't take the shortest path to get there.
In regards to these parts of your response, I'm slightly confused. You are correct in that the varial is a multi-step motion where the board (basically) ends in the same spot it starts at except for it's flipped around the vertical y-axis 180 degrees. But the varial also requires a 360 degree rotation around the forward z-axis. So with your recipe I'd guess the computation of angular velocity from start to end would be somewhat simple - rotate the board 180 degrees around the Y axis (basically). But that angular velocity won't result in the varial. So my confusion stems from your statement that I could compute 1 angular velocity to create this whole varial motion. Again, I'm not very familiar with physics/quaternions but it seems like I'd need to be changing the angular velocity throughout the trick to create proper varial motion. Computing 1 angular velocity would be the simplest solution though so if this is a viable route please correct me.

My updated thoughts on how to pull this off are along these lines, let me know if you think this could work. In blender I've created the correct varial animation with keyframes and I can see how the board's quaternion changes throughout the trick to result in the varial. For simplicity, lets say the skateboard in my sim has no rotation, so quaternion is (0, 0, 0, 1), at the start of the varial. I'm thinking that I could then, frame by frame, update the physical skateboard's quaternion (via world transform) to the correct values that I've plotted via blender keyframes.

A nuance would be that I'd need to stop the prescribed quaternion "keyframes" (applied to the physical body) if the board collides with something. Also the board would rarely have a quaternion rotation of (0, 0, 0, 1) when starting the varial so there would need to be calculations (that are currently over my head) to apply the proper quaternion "keyframe" deltas to create a varial motion.

If we had 2 objects that were parented and weren't hooked into the physics engine, it would be easy to apply 1 axis of rotation to each object and it would result in the correct varial motion. But it guess there's no way to do that with Bullet rigidBodies via parenting or some setup with constraints? I'm just somewhat shocked that there's not a way to rotate a rigidBody around 2 axis independently and simultaneously.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Wed Oct 14, 2020 4:24 pm
by drleviathan
Yes, you could apply impulses (or better yet: just slam the angular velocity) to follow a "keyframe" of rotations. That is pretty much what I'm suggesting except I claim there are only (as I count them)... one, two, three... inflection points in minimal keyframe path. Or to put it another way: there are four distinct periods of "ballistic" velocities

(1) before varial starts (skateboard is on ground):
angular_velocity = zero
linear_velocity = forward

(2) pop up (constant-angular velocity, ballistic linear-velocity):
angular-velocity = constant non-zero about local X-axis
linear_velocity = forward with ballistic vertical component

Note: in period (2) the angular and linear velocities are related such that as the skateboard rises and rotates... its lower wheels remain touching (or nearly touching) the ground. In other words: there is an equation which relates the angular_velocity magnitude to the vertical linear_velocity component. The duration T2 of period (2) can be computed as the time it takes for the skateboard to rotate to the angle at which we want to start (3).

(3) tumble (constant angular_velocity, ballistic linear velocity):
angular_velocity = some off-axis tumble which is needs to be computed, but is nevertheless constant during the tumble and will bring the skateboard around correctly after time T3
linear_velocity = continues forward with ballistic vertical component

Note: the time T3 (aka the "duration of period (3)) is somewhat variable but is bounded: It can't take longer than the time for the vertical ballistic motion to bring the skateboard back to the ground.

(4) tumble stops:
angular_velocity = zero
linear_velocity = continues forward with ballistic vertical component

In the local-frame the rotations at the keyframe inflection points would be "known" (pre-computed), and the corresponding expected world-frame rotations are related by some constant:

Q_world(t) = Q_local_to_world_offset * Q_local_rotation(t)

Since this is true for the duration of the trick, the constant offset is easy: it is the local-to-world rotation of the skateboard (e.g. the body's rotation) right before the trick starts.

The fundamental reason you can't just "rotate a rigidBody around 2 axis independently and simultaneously" is because in general: rotations don't commute. It is a mathematical property of rotations as a group, and by "group" I mean: under "group theory".

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Wed Oct 14, 2020 5:08 pm
by haydeng21
Thank you for the wonderful breakdown of this in detail, it makes a lot of sense!

One final question before this is solved: How do I calculate the angular velocity of the desired varial (tumble phase)? I've been searching online but can't find anything that helps me wrap my brain around that calculation.

Less importantly, I looked up ballistic in regards to velocity but all I'm finding is talk about the motion of an object as a result of gravitation forces on it. What do you mean when you say ballistic velocity?

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Wed Oct 14, 2020 8:35 pm
by drleviathan
How do I calculate the angular velocity of the desired varial (tumble phase)?
That is the question. I don't know, but I've been thinking about it:

(1) I wonder if my assumption that the angular velocity remains constant for the duration of the tumble is valid. The board needs to perform a full twist about its long-axis and I worry that might be plenty of time to allow the angular velocity to wander. For now I will continue to assume the approximation as valid and if you ever manage to attempt it and find the board never manages to end up at the right final orientation then we could revisit this.

(2) Watching the video again carefully I can see how the skater is applying angular impulse (e.g. torque with moment-arm over some short amount of time). Assuming the impulse is straight into the plane of the board in direction of board's local Y-axis and the moment arm has only components along Z and X... then I would guess the resulting velocity in the local-frame immediately after the impulse would be something like...

local_angular_velocity = C * <0.375, 0, 1>

Where the local-frame cardinal axes point:
C = some constant
X = left
Y = up
Z = forward

Note: I'm guessing the two relative components because from the video it seems to me the board performs one full spin rotation about its long axis and something like a 3/8 rotation about the other. Also I'm using this vector equation:

torque = force X arm

Which is merely used to figure out which axes are non-zero with force = <0,-y,0> and arm = <x, 0, y>. The torque must be perpendicular to the force, and hence has zero Y-component.

The world-frame value would be:

world_angular_velocity = skateboard_rotation * local_angular_velocity (at moment of impulse)

and would remain constant in world-frame for the tumble, as per the aforementioned assumption.

Time to spin about the long axis would be: T = (2*pi) / C but really you would mandate T (say ~ 0.3 sec) and solve for C. Remember units of angular_velocity is radians/sec.

Dunno if that works out right, but if I were trying it then I'd start there and adjust the relative local-frame angular-velocity components to get the tumble to line up to the end target.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Fri Oct 16, 2020 2:35 pm
by haydeng21
I tested your suggested angular velocity and more combinations but no luck so far. I've setup a sandbox to directly test different angular velocities (https://varial--awesome-franklin-02c975.netlify.app).

Once you're in the park, jump with "space" and then press "v" to varial. For now, I've kept the ollie/varial simple so the space bar creates a central force upwards then the V key sets the angular velocity to the values specified by you in the top left drop-down panel. The panel values are hooked up to the code like so:

Code: Select all

this.body.setAngularVelocity(new this.Ammo.btVector3(this.xav * this.avFac, this.yav * this.avFac, this.zav * this.avFac)); 
FYI, I wasn't able to make the conversion from local AV to world AV yet but just press R to reset the board so local and world rotation are equal.
world_angular_velocity = skateboard_rotation * local_angular_velocity (at moment of impulse)
How do I multiply the skateboard rotation (comes as a quaternion) with the local angular velocity? I tried multiplying the quaternion and vector3 AV together as well as using quaternion.getAxis() and multiplying that by the vector3 AV - neither worked.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Fri Oct 16, 2020 11:09 pm
by drleviathan
Hrm... the V button wasn't doing anything for me, but I did manage to land a kick-flip.

Looking back at what I said... I would add:

(a) The numbers I was using were for a board that was starting its varial part while already kicked nose-up about 45 degrees. If your simple varial is starting with the board level then I would guess the initial velocity should be something like:

angular_velocity = C * <0.5, 0, 1>

Because it would do a full rotation about local Z-axis for half rotation about local X-axis.

(b) I think the rotation about the (left) X-axis is actually be negative (as per the right hand rule). So (a) should be changed to:

angular_velocity = C * <-0.5, 0, 1>

(c) Bullet does not provide btQuaternion * btVector3 operator. Well... it does but the operator doesn't do what you think it would. I won't get into the details of that. Instead I will outline what how I would go about it:

Code: Select all

// just the rotation part
btTransform transform = body->getWorldTransform();
btQuaternion varial_start_rotation = transform.getRotation();
transform.setIdentity();
transform.setRotation(varial_start_rotation);

// compute world velocity and use it
// Note: we're assuming the skateboard is FORWARD along its local Z-axis
// (the local-frame angular velocity would be different when moving backwards in local-frame)
btScalar varial_duration = 1.0; // seconds (set this to what it should be)
btScalar varial_speed_about_z = TWO_PI / varial_duration;
btVector3 varial_angular_velocity_local_frame = varial_speed_about_z * btVector3(-0.5, 0.0, 1.0);
btVector3 varial_angular_velocity_world_frame = transform * varial_angular_velocity_local_frame;
body->setAngularVelocity(varial_angular_velocity_world_frame);

// start a timer to wait for varial_duration seconds

// ...when timer is up, check to see if skateboard's rotation is close to expected
btTransform transform = body->getWorldTransform();
btQuaternion varial_end_rotation = transform.getRotation();
btQuaternion flip_about_y = btQuaternion(0.0, 1.0, 0.0, 0.0);
btQuaternion expected_rotation = varial_start_rotation * flip_about_y;

// Note: the way to think about rotations in Bullet is... they always operate "from the left"
// on hypothetical vectors located "at the far right"
// which allows us to order these rotations correctly: flip about y-first in local-frame,
// then apply the local-to-world offset to get to world-frame where the trick
// is actually happening.
//
// in this case, I just happen to know that a 180-degree flip about the Y-axis
// is <x,y,z,w> = <0,1,0,0> in Quaternion form.

// two quaternions are close when their dot-product is very close to 1.0
// (or close to -1.0 when on on opposite hemi-hyperspheres)
btScalar dot_product = expected_rotation.dot(varial_end_rotation);
if (dot_product < 0.0) {
    // keep both quaternions on the same hemi-hypersphere
    dot_product *= -1.0;
}
// For 30-degree misalignment (plenty of slop) the dot-product would be
// (cos((30 * pi / 180)/2))^2 = 0.93301
btScalar MIN_DOT_PRODUCT = 0.93301;
if (dot_product > MIN_DOT_PRODUCT) {
    // yay, the varial worked!
    // stop the tumble "with the feet"
    body->setAngularVelocity(btVector(0.0, 0,0, 0,0));
} else {
    // something went wrong...
    // either our math is wrong or there was a collision
}
Note, that ^^^ is pseudo-code: I didn't try to compile it.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Mon Oct 19, 2020 3:50 pm
by haydeng21
Did you change the values in the top left panel? The V key won't do anything unless you change those values, since the default angular velocity is 0.

I just tried your new angular velocity suggestion but it's not causing a varial. I've tried many combinations of angular velocity and none are getting close to a varial so I'm starting to think the desired varial requires more than 1 angular velocity, meaning I'd have to change the angular velocity throughout the trick.

Awesome, I will try implementing your calculations for local to world!

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Mon Oct 19, 2020 4:56 pm
by drleviathan
Ah I see the controls now.

Yeah, I tried lots of values and could not get anything that looks like a varial. In fact, I was having trouble getting the skateboard tips to flip front to back on landing for anything. I could contrive to land some fancy flips but the front would return to facing forward. Meanwhile, the velocity on the local X-axis should defintely NOT be negative. Perhaps the skateboard's forward axis is along -Z instead of +Z? I was trying to apply the "right-hand rule" to figure out directions of axes.

Dunno where to go from here. Perhaps you really do need to turn it into a two-stage trick. If you do: maybe try reducing gravity while manually tuning the angular velocity to use so you can spin it slower and watch it more carefully. Finally, maybe color front and back tip differently so they are easier to watch.

Re: How to rotate rigid body around Y and Z axis independently and simultaneously?

Posted: Mon Oct 19, 2020 6:27 pm
by haydeng21
Yes, in three.js the default forward axis is -Z. After these attempts I do think that the trick requires a multi-staged approach, which I probably won't be able to try right now but If I do I'll keep you updated. Please let me know if you think of any other possible solutions to this, especially a bullet-equivalent solution like this (https://gamedev.stackexchange.com/quest ... ect=1&lq=1)

Thanks for all your quick replies, I appreciate it a lot.