1

I have 3 vectors that represent the 3 local axis of an object I want to get the rotation from:

enter image description here

Red - Y local vector

Green - Z local vector

Blue - X local vector

I need to get the rotation quaternion to provide it to the rendering pipeline and the code base in C offers what appears to be a comprehensive quaternions library but unfortunately I don't fully dominate quaternions. I tried to read many different materials regarding quaternions and I more or less understand the concept but I still am not entirely sure on how to use them.

I would like if someone could point me the steps I have to take to obtain the total rotation quaternion. I think I'm creating the quaternion for each axis correctly but then I don't know what to do with them (and if I try to use just a single one it gives cursed results):

quat getAxisQuaternion(vec3 axisVector, vec3 referenceAxisVector)
{
    axisVector = axisVector.normal();
    vec3 a = axisVector.cross(referenceAxisVector);
    float w = sqrt((axisVector.length() * axisVector.length()) * (referenceAxisVector.length() * referenceAxisVector.length())) + axisVector.dot(referenceAxisVector);
    return quat(a.x, a.y, a.z, w);
}

//...

quat xQuaternion=getAxisQuaternion((leftJoint-rightJoint), vec3(1,0,0));
quat yQuaternion=getAxisQuaternion((lowJoint-upperJoint), vec3(0,1,0));
quat zQuaternion=getAxisQuaternion((frontJoint-backJoint), vec3(0,0,1));

EDIT:

I managed to go further with the following changes:

quat getAxisQuaternion(vec3 axisVector, vec3 referenceAxisVector, float angleOffset=0)
{
    axisVector = axisVector.normal();
    vec3 a = axisVector.cross(referenceAxisVector);
    float w = sqrt((axisVector.length() * axisVector.length()) * (referenceAxisVector.length() * referenceAxisVector.length())) + axisVector.dot(referenceAxisVector);
    return quat(a.x, a.y, a.z, w+angleOffset).normal();
}

//..

quat xQuaternion=getAxisQuaternion((leftJoint-rightJoint), vec3(1,0,0));
quat yQuaternion=getAxisQuaternion((lowJoint-upperJoint), vec3(0,-1,0), M_PI);
quat zQuaternion=getAxisQuaternion((backJoint-frontJoint), vec3(0,0,1), M_PI);

rot=yQuaternion*zQuaternion;

Essentially I normalized the quaternion, negated the reference y axis (it is inverted in the original tomb raiders engine) and added half rotation offset to make it match to correct rotation placement.

The problem is now the xQuaternion (rot=yQuaternionzQuaternionxQuaternion). Whatever I do I can't seem to make it work as intended.

https://i.imgur.com/HRIeThD.mp4

It rotates in the wrong direction (probably fixable with some signage tweaking) but the main issue is that it rotates twice as much as it should.

If I add an offset of M_PI/2 it only rotates between -45º and 45º (but with the correct rotation speed and polarity):

https://i.imgur.com/xiC7BlB.mp4

It almost feels like my getAxisQuaternion is somehow limiting to just one quadrant.

If I add an offset of M_PI it just wont rotate at all over that axis.

Any ideas?

RicardoSBA
  • 785
  • 1
  • 6
  • 18
  • see [Is there a way to calculate 3D rotation on X and Y axis from a 4x4 matrix](https://stackoverflow.com/a/56950130/2521214) – Spektre Sep 04 '22 at 04:32
  • The issue is no longer relevant and a new one arised. I'll edit the post to reflect the current status. – RicardoSBA Sep 04 '22 at 18:52

1 Answers1

0

It seems it really is tricky to do this for more then 2 axis at a time since it basically creates the same limitation of using euler angles to do too many rotations.

I was able to solve the issue using a transformation matrix:

mat4 m;
m.identity();
m.right() = xVector;
m.up() = yVector;
m.dir() = zVector;
rot = m.getRot();

with each vector being changed to a vec4(x, y, z, 0).

Unfortunately I found out my vectors were not properly ortogonal and thus created mayhem near a certain angle. I'm currently trying a different approach but that's out of scope for this topic.

RicardoSBA
  • 785
  • 1
  • 6
  • 18
  • yes Euler angles are nuisance and [coumulative transform matrix](https://stackoverflow.com/a/28084380/2521214) is the way ... to ensure orthogonality you can exploit cross product where you leave one (major direction) as is (I use forward) and align the other two with cross product to make them orthogonal ... – Spektre Sep 05 '22 at 06:13
  • I was getting the vectors by directly inspecting geometry vertices placement on a resulting mesh from the animation of another engine (it's a mod that blends sm64 into tomb raider) but now I found a way to just get the transformation matrices directly from the animation engine of sm64. The only issue is that the matrices polarity is not the same (TODO) and Mario's t-pose is totally strange with original geometry in weird angles. Now I have to transform the raw vertices of my target model to match Mario's weirdness: https://github.com/Fast-64/fast64/blob/main/images/mario_t_pose.gif – RicardoSBA Sep 05 '22 at 10:33