2012-09-15 56 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。