여러 가지 방법이 있습니다. 아바타에 대한 절대 방향 또는 회전을 계산할 수 있습니다. 즉 새 방향 = avatarOrientation * q를 의미합니다. 후자는 다음과 같습니다.
아바타의 단위 순방향 벡터와 단위 벡터의 교차 곱을 아바타에서 대상으로, 새로운 순방향 벡터를 대상으로하여 회전축을 계산합니다.
vector newForwardUnit = vector::normalize(target - avatarPosition);
vector rotAxis = vector::cross(avatarForwardUnit, newForwardUnit);
내적을 사용하여 회전 각도 계산
float rotAngle = acos(vector::dot(avatarForwardUnit, newForwardUnit));
rotAxis와 rotAngle을 사용하여 쿼터니언을 만들고 아바타의 현재 방향과 곱하십시오
quaternion q(rotAxis, rotAngle);
quaternion newRot = avatarRot * q;
아바타의 현재 순방향 벡터를 찾는 데 도움이 필요하면 1에 대한 입력 만하십시오. :)
편집 : 절대 방향을 계산하는 것이 실제로 조금 더 쉽습니다. 아바타 순방향 벡터 대신 ID- 행렬의 순방향 벡터를 1) 및 2)의 입력으로 사용하십시오. 3)에 곱하지 말고 대신 새 방향으로 직접 사용하십시오.newRot = q
참고 사항 : 이 솔루션에는 교차 제품의 특성으로 인해 두 가지 이상이 있습니다.
순방향 벡터가 동일한 경우 여기서 해결책은 단순히 정체성 쿼터니언을 반환하는 것입니다
벡터가 정확히 반대 방향을 가리키는 경우. 여기서 해결책은 아바타 축을 회전 축으로 사용하고 180.0도 각도로 쿼터니언을 만드는 것입니다.
이러한 경우를 처리하는 C ++의 구현은 다음과 같습니다. C #으로 쉽게 변환 할 수 있습니다.
// returns a quaternion that rotates vector a to vector b
quaternion get_rotation(const vector &a, const vector &b, const vector &up)
{
ASSERT_VECTOR_NORMALIZED(a);
ASSERT_VECTOR_NORMALIZED(b);
float dot = vector::dot(a, b);
// test for dot -1
if(nearly_equal_eps_f(dot, -1.0f, 0.000001f))
{
// vector a and b point exactly in the opposite direction,
// so it is a 180 degrees turn around the up-axis
return quaternion(up, gdeg2rad(180.0f));
}
// test for dot 1
else if(nearly_equal_eps_f(dot, 1.0f, 0.000001f))
{
// vector a and b point exactly in the same direction
// so we return the identity quaternion
return quaternion(0.0f, 0.0f, 0.0f, 1.0f);
}
float rotAngle = acos(dot);
vector rotAxis = vector::cross(a, b);
rotAxis = vector::normalize(rotAxis);
return quaternion(rotAxis, rotAngle);
}
편집 : Marc의 XNA 코드 수정
// the new forward vector, so the avatar faces the target
Vector3 newForward = Vector3.Normalize(Position - GameState.Avatar.Position);
// calc the rotation so the avatar faces the target
Rotation = Helpers.GetRotation(Vector3.Forward, newForward, Vector3.Up);
Cannon.Shoot(Position, Rotation, this);
public static Quaternion GetRotation(Vector3 source, Vector3 dest, Vector3 up)
{
float dot = Vector3.Dot(source, dest);
if (Math.Abs(dot - (-1.0f)) < 0.000001f)
{
// vector a and b point exactly in the opposite direction,
// so it is a 180 degrees turn around the up-axis
return new Quaternion(up, MathHelper.ToRadians(180.0f));
}
if (Math.Abs(dot - (1.0f)) < 0.000001f)
{
// vector a and b point exactly in the same direction
// so we return the identity quaternion
return Quaternion.Identity;
}
float rotAngle = (float)Math.Acos(dot);
Vector3 rotAxis = Vector3.Cross(source, dest);
rotAxis = Vector3.Normalize(rotAxis);
return Quaternion.CreateFromAxisAngle(rotAxis, rotAngle);
}
0*(rotation A) + 1*(rotation B)
다시 말해 회전을 회전 B로 설정하는 것입니다. Slerp은 회전이 중간에 어떤 방향 (0 % <x <100 %)으로 보일지를 결정하기위한 것입니다.