대상을 향하도록 모델 방향 지정


28

두 개의 객체 (대상 및 플레이어)가 있으며 둘 다 위치 (벡터 3)와 회전 (쿼터니언)이 있습니다. 대상이 회전하고 플레이어를 향하고 싶습니다. 목표물은 무언가를 쏠 때 바로 플레이어를 쏴야합니다.

나는 플레이어에게 slerping의 많은 예를 보았지만, 증분 회전을 원하지는 않는다.

참고-위치와 회전을 사용하여 다른 많은 작업을 수행 할 수 있었고이 마지막 조각을 제외하고는 모두 잘 작동합니다.

코드 샘플은 Target의 클래스에서 실행됩니다. Position = 대상 위치, Avatar = 플레이어.

편집하다

Im은 현재 Maik의 C # 코드를 사용하고 있으며 훌륭하게 작동합니다!


4
100 % 수면을하는 경우, 수면을 사용하지 않는 것입니다. 회전을 회전으로 설정하는 것입니다. 0*(rotation A) + 1*(rotation B)다시 말해 회전을 회전 B로 설정하는 것입니다. Slerp은 회전이 중간에 어떤 방향 (0 % <x <100 %)으로 보일지를 결정하기위한 것입니다.
doppelgreener

좋아, 말이 되겠지만, 목표는 여전히 그 코드로 플레이어를 향해 완전히 회전하지는 않는다.
Marc

답변:


20

여러 가지 방법이 있습니다. 아바타에 대한 절대 방향 또는 회전을 계산할 수 있습니다. 즉 새 방향 = avatarOrientation * q를 의미합니다. 후자는 다음과 같습니다.

  1. 아바타의 단위 순방향 벡터와 단위 벡터의 교차 곱을 아바타에서 대상으로, 새로운 순방향 벡터를 대상으로하여 회전축을 계산합니다.

    vector newForwardUnit = vector::normalize(target - avatarPosition);
    vector rotAxis = vector::cross(avatarForwardUnit, newForwardUnit);
  2. 내적을 사용하여 회전 각도 계산

    float rotAngle = acos(vector::dot(avatarForwardUnit, newForwardUnit));
  3. rotAxis와 rotAngle을 사용하여 쿼터니언을 만들고 아바타의 현재 방향과 곱하십시오

    quaternion q(rotAxis, rotAngle);
    quaternion newRot = avatarRot * q;

아바타의 현재 순방향 벡터를 찾는 데 도움이 필요하면 1에 대한 입력 만하십시오. :)

편집 : 절대 방향을 계산하는 것이 실제로 조금 더 쉽습니다. 아바타 순방향 벡터 대신 ID- 행렬의 순방향 벡터를 1) 및 2)의 입력으로 사용하십시오. 3)에 곱하지 말고 대신 새 방향으로 직접 사용하십시오.newRot = q


참고 사항 : 이 솔루션에는 교차 제품의 특성으로 인해 두 가지 이상이 있습니다.

  1. 순방향 벡터가 동일한 경우 여기서 해결책은 단순히 정체성 쿼터니언을 반환하는 것입니다

  2. 벡터가 정확히 반대 방향을 가리키는 경우. 여기서 해결책은 아바타 축을 회전 축으로 사용하고 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);
}

좋아, 나는 질문에 대한 편집으로 볼 수 있듯이 코드를 제공했다. 문제가 무엇인지 확실하지 않습니다. a 및 b 입력은 순방향 벡터이거나 적어도 있다고 가정합니다.
Marc

@Marc은 내 대답에서 수정 된 XNA 코드 버전을 확인합니다. 이 두 문제가 있었다 : 새로운 전진 벡터의 1) 계산이 잘못 AvatarPosition 정상화해야했다 - rotAxis이 GetRotation의 제품 간 후 정상화해야 TargetPosition 2)
Maik Semder

@Marc, 2 개의 사소한 변경 사항 : 3) 소스 및 대상이 이미 정규화되어 있으므로 GetRotation에서 다시 정규화 할 필요가 없습니다. 4)
GetRotation

흠, 여전히 작동하지 않습니다. 동일한 스케일링이 모델에서 발생하고 대상이 아바타쪽으로 회전하지 않습니다 (귀하의 의견에서 아바타를 대상쪽으로 회전하려고합니다 .... 다른 방향으로 이동해야 함) ... 기본적으로 시도 플레이어를 향한 폭도 (3 인칭 카메라의 아바타)를 구합니다. getRotation 메소드가 대상과 아바타의 현재 회전에 대해 알고 있지 않아야합니다. newForward가 올바르게 작성되었다고 생각하십니까?
Marc

객체의 크기가 조절되면 쿼터니언의 단위 길이가 아님을 의미하며 rotAxis가 정규화되지 않았 음을 의미합니다. rotAxis 정규화로 마지막 코드 변경을 추가 했습니까? 그러나 현재 코드를 표시하고 작동하지 않는 예제의 경우 : newForward rotAngle rotAxis및의 값도 게시 하십시오 returned quaternion. 폭도의 코드는 동일합니다. 일단 아바타와 작동하게되면 어떤 객체의 제목도 쉽게 바꿀 수 있습니다.
Maik Semder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.