월드 정렬 축을 중심으로 개체를 회전시키는 방법은 무엇입니까?


15

각 축마다 오일러 각이있는 Vector3이 있습니다.

일반적으로 회전 행렬을 만들려면 위의 회전 벡터에서 각 각도를 전달하는 D3DXMatrixRotationX와 같은 함수를 사용하고 행렬 (ZXY)을 곱하여 전체 객체 변환 행렬을 만드는 데 사용되는 전체 회전 행렬을 만듭니다.

그러나이 방법은 객체 공간에서 일련의 회전을 생성합니다. 즉, (90, 0, 90)의 벡터를 내 방법으로 전달하면 (90, 90, 0)의 세계 공간에 회전이 효과적으로 생성됩니다.

내 회전 벡터의 각 구성 요소가 각각의 월드 공간 정렬 축을 중심으로 회전하도록하는 방법이 있습니까?

편집하다:

이것은 현재 일어나고있는 일의 애니메이션입니다. 빨간색이 아닌 파란색 축을 중심으로 회전하는 방법을 원합니다.

오일러 각도

편집 2 :

나는 오일러 각도와 관련된 솔루션을 찾고 있지 않지만 단순히 세계 축을 중심으로 여러 회전의 변형을 나타낼 수있는 방법을 찾고 있습니다.


differnet 함수를 세 번 호출하고 원하지 않는 벡터의 일부를 필터링하면 (함수를 호출하기 전에 0으로 설정) 무엇이 문제입니까? 그렇지 않으면 당신이 무엇을 달성하려고하는지 잘 모르겠습니다.
TravisG

무엇을 필터링? 3 개의 개별 함수를 호출 한 다음 곱하여 변환 행렬을 만듭니다. 이것은 로컬 로테이션을 보관합니다.
Syntac_

오일러 각도 또는 월드 축에 대한 회전을 원하십니까? 오일러 각도 (예 : en.wikipedia.org/wiki/Euler_angles )를 정의 하면 알파 각도 만 절대적 으로 월드 축을 기준으로합니다. 다른 두 각도는 절대 좌표축과 반드시 ​​일치하지는 않는 기울어 진 축을 기준으로합니다.
DMGregory

1
오일러 각도를 사용하면 정점에 적용하기 전에 세 개의 회전 행렬을 모두 곱합니다. M, N, O가 회전 행렬 인 경우 결과 연산은 MNO v입니다. 제안한 것은 각 행렬을 개별적으로 적용하는 것입니다 : v1 = O v0, v2 = N v1 및 마지막으로 v3 = M v2. 이 방법으로 각 vi는 절대 좌표로되어 있고, 현재 좌표로 회전 좌표를 사용하면됩니다.
dsilva.vinicius

3
@ dsilva.vinicius 분리 된 변환은 결합 된 변환과 완전히 동일하거나 다른 방법으로 표현할 수 있습니다. MNO v == M * (N * (O v))
GuyRT

답변:


1

의견을 바탕으로 객체의 방향을 Euler angles 세트로 저장 하고 플레이어가 객체를 회전 할 때 각도를 감소 / 감소시키는 것으로 보입니다 . 즉, 다음 의사 코드와 같은 것이 있습니다.

// in player input handling:
if (axis == AXIS_X) object.angleX += dir;
else if (axis == AXIS_Y) object.angleY += dir;
else if (axis == AXIS_Z) object.angleZ += dir;

// in physics update and/or draw code:
matrix = eulerAnglesToMatrix(object.angleX, object.angleY, object.angleZ);

Charles Beattie가 지적했듯이 회전은 출퇴근하지 않기 때문에 플레이어가 회전을 eulerAnglesToMatrix()적용하는 순서와 동일한 순서로 플레이어를 회전하지 않으면 예상대로 작동하지 않습니다 .

특히 다음과 같은 회전 순서를 고려하십시오.

  1. X 축을 중심으로 개체를 x 도 회전시킵니다 .
  2. Y 축을 중심으로 개체를 y 도로 회전시킵니다 .
  3. X 축을 중심으로 -x 도 만큼 개체를 회전합니다 .
  4. Y 축을 중심으로 개체를 -y 도 회전시킵니다 .

순진한 오일러 각도 표현에서 위의 의사 코드에서 구현 된 것처럼 이러한 회전은 취소되고 객체는 원래 방향으로 돌아갑니다. 현실 세계에서는 이런 일이 일어나지 않습니다. 만약 당신이 나를 믿지 않는다면, 6 면체 주사위 나 루빅스 큐브를 잡고 x = y = 90 °로 설정하고 직접 시험해보십시오!

당신이 참고로이 솔루션은 자신의 대답에 ,하는 회전 행렬과 객체의 방향을 저장하는 사용자 입력을 기반으로하는 매트릭스 (또는 사원 수)를 업데이트합니다. 즉, 위의 의사 코드 대신 다음과 같은 작업을 수행하십시오.

// in player input handling:
if (axis == AXIS_X) object.orientation *= eulerAnglesToMatrix(dir, 0, 0);
else if (axis == AXIS_Y) object.orientation *= eulerAnglesToMatrix(0, dir, 0);
else if (axis == AXIS_Z) object.orientation *= eulerAnglesToMatrix(0, 0, dir);

// in physics update and/or draw code:
matrix = object.orientation;  // already in matrix form!

(기술적으로 모든 회전 행렬 또는 쿼터니언은 오일러 각도 세트로 표시 될 수 있으므로이를 사용하여 객체의 방향을 저장하는 것이 가능합니다. 그러나 각각 오일러 각도로 표시되는 두 개의 순차적 인 회전을 결합하기위한 물리적으로 올바른 규칙은, 단일 회전으로 변환하는 것은 다소 복잡하며 회전을 행렬 / 쿼터니언으로 변환하고 곱한 다음 결과를 다시 오일러 각도로 변환하는 것과 같습니다.)


예, 이것이 해결책이었습니다. 쿼터니언이 필요하지만 사실이 아니라는 인상을주기 때문에 이것이 concept3d의 대답보다 약간 낫다고 생각합니다. 현재 회전을 3 개의 오일러 각도가 아닌 행렬로 저장하는 한 괜찮 았습니다.
Syntac_

15

회전의 문제점은 대부분의 사람들이 이해하기 쉽기 때문에 오일러 각도로 생각한다는 것입니다.

그러나 대부분의 사람들은 오일러 각 이 3 개의 순차적 인 각 이라는 점을 잊습니다 . 즉, 첫 번째 축을 중심으로 회전하면 다음 회전이 첫 번째 원래 회전을 기준으로하므로 오일러 각도를 사용하여 3 개의 각 축을 중심으로 벡터를 독립적으로 회전 할 수 없습니다.

이것은 두 개의 행렬을 곱할 때 행렬로 직접 변환됩니다.이 곱셈은 한 행렬을 다른 행렬의 공간으로 변환하는 것으로 생각할 수 있습니다.

이것은 쿼터니언을 사용할 때에도 3 개의 순차적 회전으로 발생합니다.

여기에 이미지 설명을 입력하십시오

쿼터니언이 gi 블 잠금 솔루션아니라는 사실을 강조하고 싶습니다 . 쿼터니언을 사용하여 오일러 각도를 표현한 경우 실제로는 고정 잠금이 항상 발생합니다. 문제는 문제가, 표현하지 3 연속 단계.

해결책?

3 축을 중심으로 벡터를 독립적으로 회전시키는 솔루션은 은 단일 축과 단일 각도 결합 하는 것입니다. 이렇게하면 순차적 곱셈을 수행해야하는 단계를 없앨 수 있습니다. 이것은 효과적으로 다음과 같이 번역됩니다 :

내 회전 행렬은 X와 Y 및 Z를 중심으로 한 회전 결과를 나타냅니다.

오일러 해석보다는

내 회전 행렬은 X, Y, Z를 중심으로 한 회전을 나타냅니다.

이것을 명확히하기 위해 Wikipedia Euler의 회전 정리에서 인용 할 것입니다.

오일러의 회전 정리에 따르면, 고정 점에 대한 강체 또는 좌표계의 회전 또는 회전 순서는 고정 점을 통과하는 고정 축 (오일러 축이라고 함)에 대해 주어진 각도 θ에 의한 단일 회전과 같습니다. 오일러 축은 일반적으로 단위 벡터 u →로 표시됩니다. 따라서, 3 차원에서의 임의의 회전은 벡터 u →와 스칼라 θ의 조합으로 표현 될 수있다. 쿼터니언은이 축 각도 표현을 4 개의 숫자로 인코딩하고 R3의 원점을 기준으로 점을 나타내는 위치 벡터에 해당 회전을 적용하는 간단한 방법을 제공합니다.

3 개의 행렬을 곱하면 항상 3 개의 순차적 회전이 나타 납니다 .

이제 3 축 주위의 회전을 결합하려면 X, Y, Z 주위의 회전을 나타내는 단일 각도와 단일 각도가 필요합니다. 다시 말해, 순차 회전을 제거하려면 Axis / Angle 또는 쿼터니언 표현을 사용해야합니다.

이는 일반적으로 초기 방향 (방향은 축 각도로 생각할 수 있음)으로 시작하여 일반적으로 쿼터니언 또는 축 각도로 표시 한 다음 목적지 방향을 나타내도록 해당 방향을 수정하여 수행됩니다. 예를 들어, ID 쿼터니언으로 시작한 다음 차이로 회전하여 대상 방향에 도달합니다. 이 방법으로 자유도를 잃지 않습니다.


통찰력이있는 것처럼 답변으로 표시됩니다.
Syntac_

이 답변으로 무엇을 말하려고하는지 알아내는 데 어려움이 있습니다. 단순히 객체의 방향을 오일러 각도로 저장하지 않습니까? 그렇다면 왜 그렇게 말하지 않습니까?
Ilmari Karonen

@IlmariKaronen보다 명확하게 설명 할 수 있지만 concept3d가 축 각도 표현을 촉진한다고 생각합니다. 축 각도와 쿼터니언의 관계에 대해서는 이 문서의 1.2.2 단원을 참조하십시오 . 축 각도 표현은 위의 이유로 구현하기가 쉽고 짐벌 잠금으로 고통받지 않으며 (적어도 나를 위해) 오일러 각도만큼 이해하기 쉽습니다.
NauticalMile

@ concept3d, 그것은 매우 흥미롭고, 나는 당신의 대답을 정말로 좋아합니다. 그러나 사람들이 키보드와 마우스를 사용하여 컴퓨터와 상호 작용하는 한 가지가 있습니다. 마우스를 생각하면 x와 y 마우스 델타에 대해 이야기하고 있습니다. 회전 행렬을 생성하는 데 사용할 수있는 단일 쿼터니언으로 이러한 x, y 델타를 표현하는 방법 (예 : 객체 방향 변경)?
gmagno

@gmagno 접근 방식은 일반적으로 객체 또는 장면에서 마우스 움직임을 투영하고 해당 공간의 델타를 계산하는 것입니다.이를 수행하려면 광선을 캐스팅하고 교차로를 계산하십시오. 레이 캐스팅, 프로젝트 및 프로젝트 해제를 검색하면 CG에서 몇 년 동안 일하지 않았으므로 세부 사항에 대해 거칠습니다. 도움이 되길 바랍니다.
concept3d

2

객체 공간에서 월드 공간으로 회전 조합을 전환하는 것은 쉽지 않습니다. 회전이 적용되는 순서를 반대로하면됩니다.

귀하의 경우 행렬을 곱하는 대신 Z × X × Y계산해야합니다 Y × X × Z.

이에 대한 이론적 근거는 Wikipedia에서 찾을 수 있습니다 . 본질적 회전과 외부 회전 간 변환 .


이것이 사실이라면 회전이 다를 수 있기 때문에 소스의 다음 진술은 사실이 아닙니다. "
Syntac_

1
나는 여기에 모순이 없다. 내 대답과 그 진술은 모두 사실입니다. 그렇습니다. 객체 공간과 월드 공간에서 회전을 수행하면 다른 회전이 발생합니다. 그게 요점이야, 그렇지?
sam hocevar

그 말에 따르면 순서를 변경하면 항상 같은 회전이 발생합니다. 한 주문이 잘못된 회전을 생성하면 다른 주문도 해결되지 않습니다.
Syntac_

1
당신은 오해하고 있습니다. 순서를 변경해도 회전이 동일하지 않습니다. 순서 변경 외부 회전의 본질적인 회전에서 전환 동일한 회전을 초래한다.
sam hocevar

1
나는 당신의 질문을 이해하지 못한다고 생각합니다. GIF는 약 50도 Z(오브젝트 공간), 50도 X(오브젝트 공간), 45도 Y(오브젝트 공간) 의 회전을 보여줍니다 . 이것은 45도 Y( 세계 공간 ), 50도 X( 세계 공간 ), 50도 Z( 세계 공간 ) 의 회전과 동일 합니다.
sam hocevar

1

누군가 왜 이것이 효과가 있는지 설명 할 때까지 솔루션을 답변으로 제공 할 것입니다.

모든 렌더링은 회전 벡터에 저장된 각도를 사용하여 쿼터니언을 재구성 한 다음 쿼터니언을 최종 변환에 적용했습니다.

그러나 월드 축 주위에 유지하려면 모든 프레임에서 쿼터니언을 유지하고 각도 차이를 사용하여 객체를 회전해야했습니다.

// To rotate an angle around X - note this is an additional rotation.
// If currently rotated 90, apply this function with angle of 90, total rotation = 180.
D3DXQUATERNION q;
D3DXQuaternionRotation(&q, D3DXVECTOR3(1.0f, 0.0f, 0.0f), fAngle);
m_qRotation *= q; 

//...

// When rendering rebuild world matrix
D3DXMATRIX mTemp;
D3DXMatrixIdentity(&m_mWorld);

// Scale
D3DXMatrixScaling(&mTemp, m_vScale.x, m_vScale.y, m_vScale.z);
m_mWorld *= mTemp;

// Rotate
D3DXMatrixRotationQuaternion(&mTemp, m_qRotation);
m_mWorld *= mTemp;

// Translation
D3DXMatrixTranslation(&mTemp, m_vPosition.x, m_vPosition.y, m_vPosition.z);
m_mWorld *= mTemp;

(준비를위한 자세한 내용)

dsilva.vinicius 가이 시점에 도달하려고했다고 생각합니다.


1

회전 순서를 저장해야합니다.

Rotating around x 90 then rotate around z 90 !=
Rotating around z 90 then rotate around x 90.

현재 회전 행렬을 저장하고 회전 할 때마다 미리 곱하십시오.


0

@ concept3d answer 외에도 3 개의 외부 회전 행렬을 사용하여 세계 좌표에서 축을 중심으로 회전 할 수 있습니다. Wikipedia 에서 인용 :

외부 회전은 고정 좌표계 xyz의 축에 대해 발생하는 요소 회전입니다. xyz가 고정 된 동안 XYZ 시스템이 회전합니다. XYZ 중첩 xyz로 시작하여 3 개의 외부 회전 구성을 사용하여 XYZ의 모든 대상 방향에 도달 할 수 있습니다. 오일러 또는 테이트 브라이언 각 (α, β, γ)은 이러한 원소 회전의 진폭입니다. 예를 들어 다음과 같이 대상 방향에 도달 할 수 있습니다.

XYZ 시스템은 z 축을 중심으로 α만큼 회전합니다. X 축은 이제 x 축에 대해 각도 α에있다.

XYZ 시스템은 x 축을 기준으로 β만큼 다시 회전합니다. Z 축은 이제 z 축에 대해 각도 β에있다.

XYZ 시스템은 z 축에 대해 세 번째로 γ만큼 회전합니다.

회전 행렬을 사용하여 일련의 외부 회전을 나타낼 수 있습니다. 예를 들어

R = Z (γ) Y (β) X (α)

는 열 벡터를 미리 곱하는 데 사용되는 경우 xyz 축에 대한 외부 회전의 구성을 나타냅니다.

R = X (α) Y (β) Z (γ)

는 행 벡터를 후행 곱하기 위해 사용될 때 정확히 동일한 구성을 나타냅니다.

따라서 필요한 것은 고유 회전 (또는 로컬 공간) 회전을 사용하여 수행 할 작업과 관련하여 회전 순서를 반전시키는 것입니다. @Syntac은 zxy 회전을 요청 했으므로 동일한 결과를 얻으려면 yxz 외부 회전을 수행해야합니다. 코드는 다음과 같습니다.

매트릭스 값에 대한 설명은 여기를 참조하십시오 .

// Init things.
D3DXMATRIX *rotationMatrixX = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixY = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixZ = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix0 = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix1 = new D3DXMATRIX();

D3DXMatrixRotationX(rotationMatrixX, angleX);
D3DXMatrixRotationY(rotationMatrixY, angleY);
D3DXMatrixRotationZ(rotationMatrixZ, angleZ);

// yx extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix0, rotationMatrixY, rotationMatrixX);
// yxz extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix1, resultRotationMatrix0, rotationMatrixZ);

D3DXVECTOR4* originalVector = // Original value to be transformed;
D3DXVECTOR4* transformedVector = new D3DXVECTOR4();

// Applying matrix to the vector.
D3DXVec4Transform(transformedVector, originalVector, resultRotationMatrix1);

// Don't forget to clean memory!

이 코드는 여러 가지 D3DXMATRIX 매트릭스를 재사용 할 수 있으므로 최적이 아닌 교훈적입니다.


1
죄송합니다이 사람이 올바르지 않습니다. 행렬 / 벡터 곱셈은 연관 적입니다. 이것은 결합 행렬 곱셈과 정확히 같습니다.
concept3d

네 말이 맞아 나는 외적 회전과 내적 회전의 개념을 혼합했습니다.
dsilva.vinicius

이 답변을 수정하겠습니다.
dsilva.vinicius

이제 답변이 수정되었습니다.
dsilva.vinicius
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.