McB*_*Bob 6 c opengl math quaternions
我正在努力解决以下问题.我正在使用骨骼动画,我希望(即)玩家的头部跟随太空中的另一个物体.我的上轴是+ Z我的前轴是+ Y,四元数的大小是W.我试着使用gluLookAt的mesa代码并使用3x3矩阵转换为四元数但它不能按预期工作所以我走向另一个方向......
到目前为止,我得到了以下代码"几乎"工作,至少玩家的头部正在旋转(但X角度似乎影响Y旋转轴)在良好的方向,但它直视上面而不是跟随一个对象约65度的地板:
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 );
t.w = sqrtf( 1.0f +
m.r[ 0 ].x +
m.r[ 1 ].y +
m.r[ 2 ].z ) * 0.5f;
float w4_recip = 1.0f / ( 4.0f * t.w );
t.x = ( m.r[ 2 ].y - m.r[ 1 ].z ) * w4_recip;
t.y = ( m.r[ 0 ].z - m.r[ 2 ].x ) * w4_recip;
t.z = ( m.r[ 1 ].x - m.r[ 0 ].y ) * w4_recip;
t = qt_normalize( t );
return t;
}
Run Code Online (Sandbox Code Playgroud)
...... ......
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 ) );
Run Code Online (Sandbox Code Playgroud)
有人可以帮助我解决这个问题......我有点新的四元数,并不知道我可能搞砸了哪里.经过相当多的研究后,基本上我想要做的就是Unity API:http://docs.unity3d.com/Documentation/ScriptReference/Quaternion.LookRotation.html
小智 11
我认为这个功能可以满足您的需求:
/// <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;
q.x = axis.x * s;
q.y = axis.y * s;
q.z = axis.z * s;
q.w = (float)System.Math.Cos(halfAngle);
return q;
}
Run Code Online (Sandbox Code Playgroud)
这段代码来自这里:https: //gamedev.stackexchange.com/questions/15070/orienting-a-model-to-face-a-target 我只是稍微修改它以适应我的情况,这是变换的实现. LookAt不使用Unity3D.
当前的两个答案对于边缘情况都有各种问题。由于其他原因,所接受的答案是不正确的,包括它为其中一种情况设置 w=pi 并且它没有执行适当的规范这一事实。经过大量查看并测试了几个案例后,我还发现您需要 front 和 up 向量来完成此计算。因此,不用多说,下面是我正在使用的代码:
Quaternion lookAt(const Vector3f& sourcePoint, const Vector3f& destPoint, const Vector3f& front, const Vector3f& up)
{
Vector3f toVector = (destPoint - sourcePoint).normalized();
//compute rotation axis
Vector3f rotAxis = front.cross(toVector).normalized();
if (rotAxis.squaredNorm() == 0)
rotAxis = up;
//find the angle around rotation axis
float dot = VectorMath::front().dot(toVector);
float ang = std::acosf(dot);
//convert axis angle to quaternion
return Eigen::AngleAxisf(rotAxis, ang);
}
Run Code Online (Sandbox Code Playgroud)
Bove 使用流行的 Eigen 库。如果您不想使用它,那么您可能需要以下替换Eigen::AngleAxisf:
//Angle-Axis to Quaternion
Quaternionr angleAxisf(const Vector3r& axis, float angle) {
auto s = std::sinf(angle / 2);
auto u = axis.normalized();
return Quaternionr(std::cosf(angle / 2), u.x() * s, u.y() * s, u.z() * s);
}
Run Code Online (Sandbox Code Playgroud)
请注意,点积 0 或 1 或 -1 的特殊情况会自动处理,因为 normalized() 对于 Eigen 库中的零向量返回 0。
顺便说一句,对于您所有的转换担忧,这是一个很好的文档。