How can I compensate for the global directional force applied on the local axis?

I want to apply force forward with respect to the local axis of the object, but I only use one that allows me to apply force over the global axis.

I have access to the global rotation of an object as a quaternion. However, I am not familiar with the use of quats (usually untrained in advanced math). Is this enough information to shift the applied force along the desired axis? How?

For example, to move forward globally, I would do:

this.entity.rigidbody.applyForce(0, 0, 5); 

but in order for this force to be applied along the local axis of the object, I need to distribute the applied force differently along the axes based on the rotational quat of the object, for example:

 w:0.5785385966300964 x:0 y:-0.815654993057251 z:0 

I researched the quaternions, trying to understand this, but watching the video about what they are and why they are used did not help me understand how to actually work with them, even starting to figure out how to apply the offset required here.

What I tried so far was a kind of hunch about how to do this, but this is wrong:

 Math.degrees = function(radians) { return radians * 180 / Math.PI; }; //converted this from a python func on wikipedia, //not sure if it working properly or not function convertQuatToEuler(w, x, y, z){ ysqr = y * y; t0 = 2 * (w * x + y * z); t1 = 1 - 2 * (x * x + ysqr); X = Math.degrees(Math.atan2(t0, t1)); t2 = 2 * (w * y - z * x); t2 = (t2 >= 1) ? 1 : t2; t2 = (t2 < -1) ? -1 : t2; Y = Math.degrees(Math.asin(t2)); t3 = 2 * (w * z + x * y); t4 = 1 - 2 * (ysqr + z * z); Z = Math.degrees(Math.atan2(t3, t4)); console.log('converted', {w, x, y, z}, 'to', {X, Y, Z}); return {X, Y, Z}; } function applyGlobalShift(x, y, z, quat) { var euler = convertQuatToEuler(quat.w, quat.x, quat.y, quat.z); x = x - euler.X; // total guess y = y - euler.Y; // total guess z = z - euler.Z; // total guess console.log('converted', quat, 'to', [x, y, z]); return [x, y, z]; } // represents the entity current local rotation in space var quat = { w:0.6310858726501465, x:0, y:-0.7757129669189453, z:0 } console.log(applyGlobalShift(-5, 0, 0, quat)); 

Do not laugh about my terrible conjecture on how to calculate the displacement: P I knew that he was not even close, but I really do not know much about mathematics

+5
source share
1 answer

Quaternions are used as a replacement for Euler angles. Thus, your approach defeats their goal. Instead of trying to use Euler angles, apply the properties of a quaternion.

  • A quaternion has 4 components, 3 vector components and a scalar component.

     q = x*i + y*j + z*k + w 

    Thus, the quaternion has the vector part x*i + y*j + z*k and the scalar part w . Thus, the vector is a quaternion with a zero scalar or real component.

  • It is important to note that a vector multiplied by a quaternion is another vector. This can be easily proved using the rules of multiplication of quaternion elements (on the left as an exercise for the reader).

  • The reverse quaternion is simply its conjugate divided by its magnitude. The quaternion conjugate w + (x*i + y*j + z*k) is simply w - (x*i + y*j + z*k) , and its value is sqrt(x*x + y*y + z*z + w*w) .

The rotation of a vector is simply a vector obtained by rotating this vector at an angle around its axis. Rotational quaternions represent such a rotation on the angular axis, as shown here.

The vector v can be rotated around the axis and through the angle represented by the quaternion of rotation q by conjugating v from q . In other words,

 v' = q * v * inverse(q) 

Where v' is the rotated vector, and q * v * inverse(q) is the pairing operation.

Since the quaternion is a rotation, it can be reasonably assumed that its value is unity, which makes inverse(q) = q* where q* conjugate to q .

When dividing q into the real part s and the vector part u and simplifying the operation of the quaternion (as shown here here ),

 v' = 2 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2 * s * cross(u, v) 

Where dot returns the product of the points of two vectors, and cross returns the transverse product of two vectors.

By entering the above code (pseudo),

 function rotate(v: vector3, q: quaternion4) -> vector3 { u = vector3(qx, qy, qz) s = qw return 2 * dot(u, v) * u + (s*s - dot(u, u)) * v + 2 * s * cross(u, v) } 

Now that we know how to rotate a vector with a quaternion, we can use the global rotation quaternion to find the corresponding world direction (or axis) for the local direction by matching the local direction using the rotation quaternion.

The local front axle is always specified by the symbol 0*i + 0*j + 1*k . Therefore, to find the main front axis for the object, you must hide the vector (0, 0, 1) with the quaternion of rotation of the world.

Using the above function, the front axle becomes

 forward = rotate(vector3(0, 0, 1), rotationQuaternion) 

Now that you have the world front axle, the force exerted along it will be just a scalar multiple of the world front axle.

+7
source

Source: https://habr.com/ru/post/1274741/


All Articles