쿼터니언 사용 : 그들과 함께 무엇을 할 수 있습니까? (수학없이)


24

저는 게임 개발자이며 수학을 공부하지 않았습니다. 그래서 나는 Quaternions를 도구로 사용하고 싶습니다. 그리고 3D 회전으로 작업하려면 쿼터니언 (또는 행렬)을 사용해야합니다. 그러나이 질문에서 쿼터니언에 머물도록하겠습니다. 많은 개발자들이 사용하는 것이 중요하다고 생각합니다. 그렇기 때문에 지식을 공유하고 희망을 채우고 싶습니다. 지금....

내가 이해하는 한 :

쿼터니언은 다음 두 가지를 설명 할 수 있습니다.

  1. 3D 객체의 현재 방향입니다.
  2. 객체가 할 수있는 회전 변형. (rotationChange)

쿼터니언으로 할 수 있습니다 :

곱셈 :

  1. 쿼터니언 endOrientation = 쿼터니언 rotationChange * 쿼터니언 currentOrientation;

    예를 들어, 내 3D 개체가 왼쪽으로 90 ° 회전하고 내 회전에 180 ° 오른쪽으로 회전하면 3D 개체 90 °가 오른쪽으로 회전합니다.

  2. 쿼터니언 rotationChange = 쿼터니언 endRotation * 쿼터니언 .Inverse (startRotation);

    이것으로 당신은 다른 방향에 적용 할 수있는 rotationChange를 얻습니다.

  3. Vector3 endPostion = 쿼터니언 rotationChange * Vector3 currentPosition;

    예를 들어, 내 3D 객체는 위치 (0,0,0)에 있고 내 회전은 180도 오른쪽으로 회전하며 내 위치는 (0, -50,0)과 같습니다. 그 쿼터니언 안에는 축이 있고 그 축을 중심으로 회전합니다. 그 축을 중심으로 Y도를 돌립니다.

  4. Vector3 rotatedOffsetVector = 쿼터니언 rotationChange * Vector3 currentOffsetVector;

    예를 들어 : 시작 방향이 위로-(0,1,0)을 표시하고 내 회전에 곱하기 회전이 180도에서 오른쪽으로, 끝 방향이 아래로 표시됩니다. (0, -1,0)

블렌딩 (Lerp and Slerp) :

  1. 쿼터니언 currentOrientation = 쿼터니언 .Slerp (startOrientation, endOrientation, 보간 기)

    보간 기가 1 인 경우 : currentOrientation = endOrientation

    보간 기가 0 인 경우 : currentOrientation = startOrientation

    Slerp는보다 정밀하게 보간하고, Lerp는 성능이 더 뛰어납니다.

내 질문 :

지금까지 설명한 모든 것이 정확합니까?

쿼터니언으로 "모두"할 수 있습니까? (obv. 아님)

그들과 다른 무엇을 할 수 있습니까?

2 개 쿼터니언 사이의 Dot 제품과 Cross 제품은 무엇입니까?

편집하다:

일부 답변으로 업데이트 된 질문


2 개가 아니라 n다른 방향 (태도, 자세 등) 이 있다고 가정 해보십시오 . 그런 다음 가중치를 사용하여 평균화하여 효과적으로 slerp / lerp를 일반화 할 수 있습니다. 쿼터니언을 로터로 변환 할 수도 있는데, 이는 일정 시간 동안 강체에 각속도를 적용하는 것과 같습니다. 따라서 쿼터니언과 각속도 통합을 설명 할 수 있습니다. 또한 서로 다른 두 방향이 어떻게되는지를 추정 할 수 있습니다 (초 구면의 두 쿼터니언이 차지하는 호의 길이 계산).
teodron

그리고 그렇습니다. 언뜻 보면, 당신의 이론적 근거는 옳습니다. 댓글에 부적합하지만 축하합니다! 기술적으로 재능이있는 사람조차도 모든 쿼터니언 사용을 알지 못하지만, 용도에 따라 소프트웨어 엔지니어링 도구로 사용하기도합니다.
teodron

4
"3D 회전으로 작업하려면 쿼터니언을 사용해야합니다."나는이 문장이 얼마나 허위인지 충분히 강조 할 수 없습니다. Euler 또는 Tait-Bryan 앵글을 게임 개발에 사용할 수 있습니다. 유일한 문제는 짐벌 잠금입니다. 게임 개발자가 되려면 한 번에 수학이 필요합니다.
Bálint

1
"게임 개발자"와 "수학 공부하지 않음"은 옥시 모론입니다.
마가렛 블룸

2
질문으로 무엇을하려고했는지 감사하지만 답변은 질문이 아니라 답변에 있어야합니다. 조합 할 가치가 있다고 생각되면 "요약"답변을 작성하십시오.
기본

답변:


23

곱셈

적어도 Unity의 Quaternions 구현 측면에서 질문에 설명 된 곱셈 순서가 올바르지 않습니다. 이것은 3D 회전이 정류 적이 지 않기 때문에 중요 합니다.

따라서 객체를 rotationChange시작 하여 객체를 회전하려면 currentOrientation다음과 같이 작성하십시오.

Quaternion newOrientation = rotationChange * currentOrientation;

(즉, 변환은 왼쪽까지 쌓입니다-Unity의 매트릭스 규칙과 동일합니다. 가장 오른쪽 회전은 "가장 로컬"인 끝에 적용됩니다)

그리고 회전에 의해 방향 또는 오프셋 벡터를 변환하려면 다음과 같이 작성하십시오.

Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;

(반대하면 Unity가 컴파일 오류를 생성합니다)

블렌딩

대부분의 경우 Lerping 회전으로 벗어날 수 있습니다. 이는 쿼터니언에서 "후드 아래"에 사용 된 각도가 회전 각도의 절반 이기 때문에 Matrix와 같은 것보다 Lerp의 선형 근사치에 실질적으로 더 가깝기 때문입니다 (일반적으로 Lerp 는 그렇지 않습니다 ). 자세한 내용은이 비디오에서 약 40 분 정도 확인하십시오 .

실제로 Slerp가 필요한 경우는 애니메이션 타임 라인의 키 프레임 간 보간과 같이 시간이 지남에 따라 일관된 속도가 필요한 경우입니다. 애니메이션의 블렌딩 레이어와 같이 두 입력 사이에 출력이 중간 정도 인 것을 걱정하는 경우 일반적으로 Lerp가 잘 작동합니다.

그 밖의 무엇?

두 단위 쿼터니언 의 내적 은 두 각도 사이의 코사인을 제공하므로 회전을 비교해야하는 경우 내적을 유사성의 척도로 사용할 수 있습니다. 이것은 조금 애매하지만, 더 읽기 쉬운 코드에서는 종종 Quaternion.Angle (a, b)를 사용합니다.

Unity가 Quaternions에 제공하는 이러한 유형의 편의 방법은 매우 유용합니다. 거의 모든 프로젝트에서 나는 이것을 적어도 몇 번 사용합니다 .

Quaternion.LookRotation(Vector3 forward, Vector3 up)

이것은 다음과 같은 쿼터니언을 만듭니다.

  • forward벡터 인수를 따라 정확히 가리 키도록 로컬 z + 축을 회전합니다.
  • up제공된 경우 또는 (0, 1, 0)생략 된 경우 벡터 인수에 최대한 가깝도록 로컬 y + 축을 회전합니다.

"최대"가 "가능한 한 근접한"경우에만 시스템이 과도하게 결정 되었기 때문입니다. z +가 forward두 개의 자유도 (즉, 요와 피치)를 사용하도록함으로써 자유도는 하나만 남습니다 (롤).

나는 종종 정확한 속성과 반대되는 것을 원한다. 나는 로컬 y +가 정확하게 따라 up가고 로컬 z +가 가능한 한 forward자유에 가까워지기를 원한다 .

예를 들어 이동 입력을 위해 카메라 기준 좌표 프레임을 만들려고 할 때 발생합니다. 로컬 위쪽 방향을 바닥이나 경사 표면 법선에 수직으로 유지하려고합니다. 따라서 입력으로 캐릭터를 지형으로 터널링하지 않습니다. 또는 그것들을 공중에서 빼내십시오.

탱크의 포탑 하우징이 목표물을 향하게하고, 위 / 아래를 조준 할 때 탱크의 몸체를 벗겨 내지 않으면이 결과를 얻을 수도 있습니다.

우리는 LookRotation무거운 리프팅을 사용하여이를 위해 편리한 기능을 만들 수 있습니다 .

Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
    Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
    Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);

    return rotateZToUp * rotateYToZ;
}

먼저 로컬 y +를 z +로, 로컬 z +를 y-로 회전합니다.

그런 다음 우리는 새로운 z +를 위쪽 방향으로 회전하고 (따라서 순 결과는 로컬 y + 지점을 따라 직접 exactUp), 부정확 한 전방 방향에 최대한 가깝게 새로운 y +를 습니다 (따라서 순 결과는 가능한 한 로컬 z + 지점에 가깝습니다) approximateForward)

또 다른 편리한 편의 방법은입니다 Quaternion.RotateTowards.

Quaternion newRotation = Quaternion.RotateTowards(
                             oldRotation, 
                             targetRotation,
                             maxDegreesPerSecond * Time.deltaTime
                         );

이를 통해 targetRotation프레임 속도에 관계없이 일관되고 제어 가능한 속도로 가까이 갈 수 있습니다. 이는 캐릭터의 움직임을 돌리거나 플레이어에서 터렛 트랙 인을하는 등 게임 플레이 메커니즘의 결과 / 공정에 영향을주는 회전에 중요합니다. 이 상황에서 순진하게 Lerping / Slerping을 수행하면 높은 프레임 속도에서 움직임이 더 빠르게 진행되어 게임 밸런스에 영향을 미치는 경우가 쉽게 발생할 수 있습니다. (이러한 방법이 잘못되었다는 것은 아닙니다. 공정성을 바꾸지 않고 올바르게 사용하는 방법이 있습니다. 관리 만하면됩니다. RotateTowards이를 위해 편리한 바로 가기를 제공합니다)


도움말 : 동영상 URL 끝에 & t = 40m을 추가하면 바로 홉 (40m5와 같이)으로 튀어 나옵니다. 쿼터니언 도트 제품은 구형 게임 월드를 처리 할 때 또는 회전 구의 덩어리 방향을 지정할 때 편리합니다.
Luke Briggs

@Luke Briggs : 구형 게임 월드 포인트는 자신이 원하는 경우 자체 답변 (특히 다이어그램)으로 자세히 살펴볼 가치가있는 것처럼 들립니다. :)
DMGregory

좋은 생각입니다-여기는 오전 3시입니다 (그래서 조금 횡설수설로 생각합니다!). 그러나 내일 무언가를 함께 가져 와서 기뻐할 것입니다 (기억한다면!)
Luke Briggs

1
편집 : 답변에 대해 조금 생각이 들었으므로 도전이 받아 들여졌습니다! P : 사람들이 그것으로 갔다 늦은 밤 화상을 인식 할 수 있도록 나는 적어도 거친 인하로 표시합니다
누가 복음 브릭스

우리는 거기에 갈! 귀하의 답변이 이미 기본 기능을 실제로 잘 다루고 있다는 점을 바탕으로 그래픽 개요로 다루려고했습니다. 잠을 잘 시간이라고 생각합니다!
Luke Briggs

14

내적 제품은 어디에 사용됩니까?

두 사원 수를 통해 동일한 경우 확인할 때마다 유니티에서, 내적의 가장 일반적인 사용자 중 하나입니다 ==또는 !=. Unity는 내적 x, y, z, w 값을 직접 비교하지 않고 유사성을 확인하기 위해 내적을 계산합니다. 예상보다 비싸게 전화하므로이 점을 명심해야합니다.

우리는 또한 흥미로운 유스 케이스에서도 사용합니다.

쿼터니언 도트 제품으로 즐기는 즐거움-구형 세계 및 궤도

전체 행성과 심지어 전체 태양계의 시뮬레이션이 점점 일반화되고 있습니다. 실시간으로 이것을 없애려면 쿼터니언 도트 제품도 필요합니다. 그들 중 많은. 쿼터니언 도트 제품은 많이 사용되지는 않지만 확실히 그 용도가 있습니다. 한번 살펴 봅시다!

먼저, 다음과 같은 일련의 회전을 고려해야합니다.

  1. (선택 사항) 은하계 중심의 별
  2. 별 주위의 행성
  3. 행성의 기울기
  4. 행성의 스핀
  5. 근처 그리드 셀의 위치 (행성 코어를 중심으로 회전) *
  6. 다중 궤도면

그것들을 모두 결합하면 많은 복잡성 (많은 수의 숫자)이 생깁니다. 시청자가 지구 표면에 서있을 때, 우리는 그들이 게임 월드 공간을 통해 미친 듯이 빠른 속도로 아프게하고 싶지 않습니다. 우리는 실제로 그것들이 정지되어 있고 원점 근처에있는 것이 었습니다. 대신 플레이어 주위로 우주를 움직이십시오.

회전 행성

중요하게,이 시나리오에서 지구의 회전과 기울기를 올바르게하려면, 축을 고정하여 위의 이미지에서만 위 / 아래로 스윙 할 수 있도록해야합니다 (예 : 플레이어가 이동할 때 "위로"스윙) 북쪽). 쿼터니언 도트 제품이 나오는 곳입니다. 여기에서 도트 제품을 사용하지 않고 기울기를 곱하면 다음과 같은 일이 발생합니다.

잘못 기울어 진 '행성'

우리의 궤도 '행성'의 극이 항상 별을 향해 기울어지는 방법에 주목하십시오. 이것은 실제로 일어나지 않습니다. 기울기는 고정 된 방향 입니다.

너무 멀리 주제를 다루지 않고 간단한 요약은 다음과 같습니다.

  • 구에서 방향은 표면 위치를 깔끔하게 묘사합니다.
  • 우리는 함께 많은 회전을 가지고 있습니다.
  • 모든 것을 회전으로 묘사하십시오. 시청자의 위치도 이는 궁극적으로 더 적은 작업을 수행함에 따라 성능을 향상시키는 데 도움이됩니다.
  • 회전 각도 (도트 제품)는 경도를 측정하는 데 도움이되며 특히 기울기를 처리하는 데 효과적입니다.

각도 만 얻어서 원치 않는 회전 중 일부를 떨어 뜨립니다 . 동시에 우리는 또한 지역 기후뿐만 아니라 항해에 유용한 경도 측정으로 끝났습니다 .

* 행성은 많은 그리드 셀로 구성 됩니다. 실제로는 주변 사람 만 표시됩니다.


2
이것은 장면을 설정하고 문제를 일으키는 훌륭한 일을하지만, 여전히 쿼터니언 도트 곱 의 수학 (즉 , 우리가 사슬을 묶는 데 사용하는 dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w쿼터니언 구성 과 반대로 스칼라 곱) 에 대해 약간 모호합니다 . 회전)이이 문제를 해결하는 데 도움이됩니다. 나중에 조금 더 자세히
설명해 주시면 기뻐할 것입니다

@DmGregory 짧은 대답은 기울기입니다. 그 행성을 제외하고는 모든 것이 멋지게 구성되어 있습니다 (그렇지 않으면 별이 지구 주위를 맴도는 것처럼 보일 것입니다). 내일 더 많은 맥락을 추가하겠습니다.
Luke Briggs

@DMGregory 추가 정보를 추가했습니다 (잠을 잘 수 없었습니다!).
Luke Briggs

1
약간 조밀 한 경우 죄송하지만 여러 번 다시 읽은 후에도 설명에서 변환을 달성하기 위해 공식에서 내적을 어떻게 사용하는지 알 수 없습니다. 명시 적으로 수행하는 작업을 배치하는 약간의 의사 코드를 추가 할 수 있습니까?
DMGregory

@DMGregory 나는 쿼터니언에 익숙하지 않지만 이것이 구의 회전 인 경우 이것은 회전 컴포지션이 아닙니다. 이것은 벡터와 함께 구형 지오메트리를 사용하여 구면 AKA의 표면에서 "선"에 대한 법선 벡터를 계산합니다. 다시 한 번, 그 대답은 의미가 없으며이 질문에도 불구하고 구형 형상을 사용하고 있다고 생각합니다.
그레이트 덕
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.