#Rotating vector with quaternion

6 messages · Page 1 of 1 (latest)

pure swan
#

Hello! I am making a 2D game and I have an entity on which I have a Velocity component (a Vec2) and I want to increase the entity's velocity in the direction that the entity is facing. So to do that I get the entity's Quat rotation from its Transform and save it as forward and I have the velocity I want to add as velocity. In order to get my velocity in the same direction as the entity, I am trying to use p' = qpq⁻¹, which I found on wikipedia, here: https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation.

let rotated_vel = forward * velocity * forward.conjugate();

However, the following line of code doesn't compile because multiplying by quaternions is not implemented for vectors and as far as I'm aware quaternion multiplication is not commutative.

error[E0277]: cannot multiply `bevy::prelude::Vec3` by `bevy::prelude::Quat`
   --> src\gameplay\shared.rs:212:54
    |
212 |                 let rotated_vel = forward * velocity * forward.conjugate();
    |                                                      ^ no implementation for `bevy::prelude::Vec3 * bevy::prelude::Quat`
    |
    = help: the trait `Mul<bevy::prelude::Quat>` is not implemented for `bevy::prelude::Vec3`

How should I get around this? Otherwise, is there a different way of achieving my original goal?

glossy creek
#

You can do Quat * Vec3 but not the other way around

pure swan
#

Yes, but how can I do p' = qpq⁻¹ then? it is saying Quat * Vec3 * Quat.
I tried with just Quat * Vec3 (in the code above, let rotated_vel = forward * velocity;) but that gives me the wrong rotation for the vector, which I suspect is because of not multiplying by q⁻¹.

glossy creek
#

You shouldn't need to multiply with the quaternion twice to get the desired result.
How are you creating the Quat?

quasi marlin
#

I believe the formula you are referring to is to rotate a quaternion by axis and angle and not rotating a vector.

If i understood you correctly, to achieve your initial goal, you have two options.

The simple solution: you can simply take the forward vector of your transform (which already points "forward", and has length 1) and scale it to the needed length.

let global_velocity_change = 50.0 * transform.forward();
entity_velocity += global_velocity_change;

(And transform.forward() is a method on Transform which takes care of the heavy lifting for you. You can also take a look at the left/right/up/down/local_y/local_y/local_z methods which are analogous to forward and return vectors that point into said direction within the reference frame of that transform)

The manual option: can create you velocity vector under the assumption that the Z axis is forward and then rotate it by multiplying it with the rotation of the transform

//Create a change in velocity that is 50 units forward and 0.2 units upward
//(This vector can be seen as existing in the local reference frame of your entity, where Y is up and Z is forward)
let local_velocity_change = vec3(0.0, 0.2, 50.0); 

//Rotate the change in velocity into the global reference frame
let global_velocity_change = transform.rotation * local_velocity_change;

//Add the new velocity to the existing velocity of your entity
entity_velocity += global_velocity_change;

Note that this is really only necessary if you also want to apply some sideways velocity and not just straight forward velocity. If you only care about the forward velocity, the simple solution is a bit quicker.

pure swan