Quarterion "lookAt" function

I am struggling with the following problem. Im working with bone animation, and I want (i.e.) the player’s head to follow another object in space. My axis is above + Z, my front axis is + Y, and the quaternion value is in W. I tried to use the mesa code for gluLookAt and use the 3x3 matrix to convert to quaternion, but it doesn’t work properly so I'm going in the other direction ...

So far I have received the following code that almost “works”, at least the player’s head rotates (however, the angle X apparently affects the rotation axis Y) in a good direction, but instead he looks directly at the next object on floor about 65 degrees:

qt LookRotation( v3 lookAt, v3 upDirection ) { qt t; v3 forward = lookAt; v3 up = upDirection; OrthoNormalize( &forward, &up ); v3 right = v3_cross( up, forward ); mat3 m = mat3_make( right.x, up.x, forward.x, right.y, up.y, forward.y, right.z, up.z, forward.z ); tw = sqrtf( 1.0f + mr[ 0 ].x + mr[ 1 ].y + mr[ 2 ].z ) * 0.5f; float w4_recip = 1.0f / ( 4.0f * tw ); tx = ( mr[ 2 ].y - mr[ 1 ].z ) * w4_recip; ty = ( mr[ 0 ].z - mr[ 2 ].x ) * w4_recip; tz = ( mr[ 1 ].x - mr[ 0 ].y ) * w4_recip; t = qt_normalize( t ); return t; } 

... ... ...

 v3 v = v3_sub( vec4_to_v3( transform.world.r[ 3 ] /* The object XYZ location in the world */), skeleton->final_pose.location[ i ] /* i = The head joint location */ ); v = v3_normalize( v ); qt q = LookRotation( v, v3_make( 0.0f, 0.0f, 1.0f ) ); 

Can someone help me sort this out ... I am a little new with quaternions and don't know where I could get mixed up. After quite some research, basically what I want to do is something like the Unity API: http://docs.unity3d.com/Documentation/ScriptReference/Quaternion.LookRotation.html

+4
source share
2 answers

I think this function will do what you need:

 /// <summary> /// Evaluates a rotation needed to be applied to an object positioned at sourcePoint to face destPoint /// </summary> /// <param name="sourcePoint">Coordinates of source point</param> /// <param name="destPoint">Coordinates of destionation point</param> /// <returns></returns> public static Quaternion LookAt(Vector3 sourcePoint, Vector3 destPoint) { Vector3 forwardVector = Vector3.Normalize(destPoint - sourcePoint); float dot = Vector3.Dot(Vector3.forward, forwardVector); if (Math.Abs(dot - (-1.0f)) < 0.000001f) { return new Quaternion(Vector3.up.x, Vector3.up.y, Vector3.up.z, 3.1415926535897932f); } if (Math.Abs(dot - (1.0f)) < 0.000001f) { return Quaternion.identity; } float rotAngle = (float)Math.Acos(dot); Vector3 rotAxis = Vector3.Cross(Vector3.forward, forwardVector); rotAxis = Vector3.Normalize(rotAxis); return CreateFromAxisAngle(rotAxis, rotAngle); } // just in case you need that function also public static Quaternion CreateFromAxisAngle(Vector3 axis, float angle) { float halfAngle = angle * .5f; float s = (float)System.Math.Sin(halfAngle); Quaternion q; qx = axis.x * s; qy = axis.y * s; qz = axis.z * s; qw = (float)System.Math.Cos(halfAngle); return q; } 

This code comes from here: https://gamedev.stackexchange.com/questions/15070/orienting-a-model-to-face-a-target I just modified it a bit to fit my case, which was an implementation of transform.LookAt without using Unity3D

+7
source

You do not need to use acos and axis angle (in turn, make two more trigger functions) to get a quaternion of 2 vectors:

 public static Quaternion LookAt(Vector3 sourcePoint, Vector3 destPoint) { Vector3 forwardVector = Vector3.Normalize(destPoint - sourcePoint); Vector3 rotAxis = Vector3.Cross(Vector3.forward, forwardVector); float dot = Vector3.Dot(Vector3.forward, forwardVector); Quaternion q; qx = rotAxis.x; qy = rotAxis.y; qz = rotAxis.z; qw = dot+1; return q.normalize(); } 

The reason for point + 1 and subsequent normalization is that if you do not get a quaternion for double rotation. These 2 steps will effectively execute slerp(identity, q, 0.5) , which will be the right amount.

0
source

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


All Articles