2012-09-15 30 views
4

Im正在努力解决以下问题。我正在使用骨骼动画,我希望(即)玩家的头部跟随太空中的另一个物体。我的上轴是+ Z我的前轴是+ Y,而四元数的大小是在W.我尝试使用gluLookAt的台面代码并使用3x3矩阵转换为四元数,但它不能按预期工作所以我走向另一个方向...Quaternion“lookAt”功能

到目前为止,我得到了下面的代码是“几乎”工作,至少在播放器的头部旋转(但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; 
} 

... ... ...

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)); 

有人可以帮我弄清楚这个问题...我有点新与四元组,并不真正知道我可以搞砸了。经过相当长的一段研究基本上是我想要做的是一样的东西统一API:http://docs.unity3d.com/Documentation/ScriptReference/Quaternion.LookRotation.html

回答

6

我觉得这个功能会做你需要的东西:

/// <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; 
} 

代码来自这里: https://gamedev.stackexchange.com/questions/15070/orienting-a-model-to-face-a-target 我只是稍微修改它,以适应我的情况,这是实施变换.LookAt不使用Unity3D

+1

在我看来,你应该在第一次旋转之后使用向量来固定坐标系 - 在其他情况下,你的变换会得到不想要的侧倾角。 – majakthecoder

+0

为什么'dot - (-1.0f)'而不是'dot + 1.0f'? –

+0

@AndyRay还有另外一个比较,它有'dot - (...)',括号内的值可以是'1.0f'或'-1.0f'。以类似的方式输入它们是有意义的,所以它看起来不错。 –

0

你不需要使用acosaxis angle(而这又将做2个更多的三角函数)来获得曲线从2个载体aternion:

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; 
    q.x = rotAxis.x; 
    q.y = rotAxis.y; 
    q.z = rotAxis.z; 
    q.w = dot+1; 

    return q.normalize(); 
} 

的原因圆点+ 1和随后的正常化是因为如果你没有得到你的双旋转的四元数。这两个步骤将有效地做slerp(identity, q, 0.5)这将是适当的quaterion。