2012-09-15 3 views
4

임 다음 문제로 어려움을 겪고 있습니다. 임 뼈 애니메이션으로 작업하고 나는 (즉) 플레이어의 머리가 우주의 다른 대상을 따라 가기를 원합니다. 내 업스트림 축은 + Z이고 앞으로 축은 + Y이며 쿼터니언의 크기는 W입니다. gluLookAt에 대한 메사 코드를 사용하고 쿼터니언으로 변환하기 위해 3x3 매트릭스를 사용하려고했지만 예상대로 작동하지 않습니다. 그래서 나는 다른 방향으로 나아 간다 ...Quaternion "lookAt"기능

지금까지 "거의"작동하는 코드는 플레이어의 헤드가 적어도 회전하고있다 (그러나 X 각은 Y 회전축에 영향을 미친다).

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

... ... ...

: 방향하지만이 약 65 정도에서 바닥에 물체를 추적 할 대신에 똑바로 찾고 좋은
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)); 

누군가가 나를이 문제를 알아내는 데 도움이 될 수 있습니까? 4 분법으로는 다소 새로운 것이고 엉망으로 만들었을 수도 있습니다. 내가하고 싶은 것을 기본적으로 꽤 많은 연구가 유니티 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 난 그냥 Unity3D를 사용하지 않고 변환을 구현 한 나의 경우에 약간 수정했습니다.

+1

제 의견으로는 첫 번째 회전 후에 벡터를 사용하여 좌표계를 수정해야합니다. 다른 경우에는 변형에 원치 않는 롤 각이 생깁니다. – majakthecoder

+0

왜'dot + 1.0f' 대신'dot - (-1.0f)'입니까? –

+0

@AndyRay 또 다른 비교는'dot - (...) '이고, 괄호 안의 값은'1.0f' 또는'-1.0f' 일 수 있습니다. 비슷한 방식으로 입력하는 것이 좋습니다. 그래서 멋지게 보입니다. –

0

acosaxis angle (두 개 이상의 trig 함수를 수행 할 것입니다)을 사용하여 qu 이 벡터에서 aternion : 당신이 이중 회전 사원 수를 얻을 당신이 경우에 때문에 점 + 1 이후 정상화를위한

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

이유입니다. 그 2 단계는 효과적으로 적절한 quaterion 될 slerp(identity, q, 0.5) 할 것입니다.

관련 문제