0
\$\begingroup\$

This used to be on the physics stack exchange but I was told to put it here:

I'm making a game (with physics) and I have a 3D ball rolling down a flat plane. It moves perfectly fine, but the rotation is messed up. It seems way too fast, and the axis seems to be all wrong. Here's the code that runs every tick (20 times per second). (normal is the normal to the plane, acceleration is gravity vector projected onto the plane, in m/tick2, and velocity is the velocity in m/tick.)

vec3 rotationAxis = normalize(cross(normal, acceleration));
quat newRotation = rotate(oldRotation, length(velocity) / sphereRadius, rotationAxis); // rotate by v/r radians about the rotationAxis

I'm not sure why this doesn't work, since according to angular mechanics, v=rω and ∆θ=v∆t/r (and ∆t=1 since velocity is in meters/tick). Am I doing something wrong? Why is the rotation so much faster than it should be? And is my axis of rotation correct?

Rephrased in a more physics way, is this correct in 3D:

$$\hat{x} = \frac{\hat{N} \times \vec{a}}{|\hat{N} \times \vec{a}|}$$

$$\Delta \theta \textrm{ about } \hat{x} = \frac{v}{r} \Delta t$$

And if it is correct, then what’s wrong with my code?

\$\endgroup\$
3
  • \$\begingroup\$ I think you need to add the code that creates the rotation rotate(...). I'm wondering why the new rotation needs to know about the old rotation. \$\endgroup\$
    – Mark H
    May 15 '20 at 21:14
  • \$\begingroup\$ It’s part of the math library I use (glm). It takes in a quaternion and outputs it with the rotation applied. It does it like this because the objects are effectively immutable. The docs are here: glm.g-truc.net/0.9.0/api/… (and I forgot to mention that I do convert to degrees as required, but it’s not shown in the code above) \$\endgroup\$ May 15 '20 at 21:24
  • \$\begingroup\$ It seems wrong that you want to rotate the rotation quaternion. Shouldn't the argument of rotate() be a vector representing the orientation of the ball? \$\endgroup\$
    – Mark H
    May 16 '20 at 3:30
0
\$\begingroup\$

Your rotationAxis should be the cross product between your velocity vector and the surface normal vector as velocity contains the direction of movement whereas acceleration is not necessarily in the direction of movement. (E.g. Projectile motion where acceleration is always down.)

i.e. vec3 rotationAxis = normalize(cross(normal, velocity));

∆θ = length(velocity) / sphereRadius seems right since

$$ 2\pi Radius \ meters/tick = 1 \ (full) \ rotations/tick = 2\pi \ radians/tick $$

So, $$ x \ meters/tick = \frac{x}{Radius} \ radians / tick $$

You say velocity is per tick so length(velocity) is the speed in meters/tick. Hence, $$|Velocity| \ meters/tick = \frac{|Velocity|}{Radius} \ radians / tick $$

Therefore, every new tick, you should rotate by $$\frac{|Velocity|}{Radius} \ radians$$ which is what you're doing.

Make sure your sphereRadius is also in meters as length(velocity) is in meters/tick.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.