변환 행렬에서 방향을 어떻게 추출 할 수 있습니까?


10

나는 4x4 변환 행렬 M을 가지고 있으며 M에 의해 변환 될 때 구의 모양을 찾고 싶습니다. (구는 원점에 있고 반지름은 1입니다.)

M에 (0,0,0,1)을 곱하여 중심을 찾을 수 있다는 것을 알고 있습니다.

그러나 M이 구를 스쿼시하고 회전시킬 수 있으므로 반경이 문제가됩니다. 결과 타원체의 새로운 반지름을 어떻게 알 수 있습니까? 방향을 알아낼 방법이 있습니까?

보다 구체적으로, 변환 된 구체를 둘러싸는 경계 구체의 크기를 알아야합니다. 다시 말해, 최대 값은 | M * V-M * (0,0,0,1) |이며, 여기서 V는 단위 벡터 (원 구의 한 점)입니다.


1
변환 된 축 벡터의 길이 만 계산할 수 없습니까? (행렬 회전 부분의 3 열) 경계 영역의 반지름은 가장 긴 벡터의 길이와 같습니다.
Bart

아니요, 나는 그것이 옳지 않다고 생각합니다. 가장 긴 방향이 축 정렬되지 않을 수 있습니다. (당신은 회전, 다시 숙청, 그것을 회전을 숙청 상상해 경우 좀 더 등)
CaptainCodeman

흠, 확실하지 않습니다. 내가 설득 할 수 있다면 오늘 나중에 답을 쓸 것이다. ;)
Bart

문제는 SCALE 변환을 수행하는 경우 M 행렬의 기본 벡터가 서로 직교를 유지할 필요가 없다는 것입니다.
GPUquant

답변:


6

수학적으로 요구하는 수량을 연산자 norm 이라고합니다 . 불행히도 그것에 대한 간단한 공식은 없습니다. 예를 들어, 회전과 비 균일 스케일의 임의의 조합을 임의 순서로 가질 수있는 경우와 같이 완전히 일반적인 아핀 변환 인 경우 단일 값 분해 를 사용하는 것 외에는 아무것도 없습니다 . SVD를 행렬에 적용하면 가장 큰 특이 값은 결과 타원체의 최대 반경이됩니다. 다른 특이 값도 다른 두 개의 반지름이되며 SVD 프로시 저는 축의 방향을 추출 할 수도 있습니다.

SVD를 구현하는 것은 고유 값을 찾는 것과 관련되어 있기 때문에 마음이 희미하지 않습니다. 원하는 모든 값이 특이 값 자체 인 경우 M ^ T * M의 고유 값의 제곱근입니다. 따라서 3x3 고유 값 솔버가 편리하거나 작성하지 않아도되는 경우 사용할 수 있습니다. 축의 방향도 추출하려면 고유 벡터도 찾아야하기 때문에 더 복잡합니다. Wikipedia 기사에는 SVD를 수행하기위한 라이브러리 링크 목록이 있으며 그중 하나는 프로젝트에서 사용할 수 있습니다.

행렬의 형식이 비 균일 스케일이 최대 한 번 발생하고 첫 번째 변환이 적용되는 방식으로 제한되는 경우 (즉, 열 벡터를 사용할 때 가장 오른쪽에있는 경우)이를 단순화하여 변형 된 축 벡터. 이 경우에만 (즉, 단일 비 균일 스케일 다음에 임의의 회전, 반사 및 균일 스케일이 이어짐) 축 벡터 만 보면 올바른 답을 얻을 수 있습니다.


감사합니다. 자세한 답변에 감사드립니다. 다른 답변에서 제공된 분해가 작동하지 않는 곳은 어디입니까?
CaptainCodeman 2013

2
@CaptainCodeman 다른 대답은 세 번째 단락에서 설명한 것과 같이 변환 된 축 벡터 (예 : 행렬의 열)를 보는 것입니다. 회전 후에 비 균일 스케일이있는 경우 실패합니다. 스케일링은 원래 축을 따라 적용되지 않기 때문입니다.
Nathan Reed

2

행렬에서 스케일 팩터를 추출한 다음 해당 구성 요소의 최대 값을 사용할 수 있습니다. SRT (Scale-Rotation-Translation) 행렬을 사용하면 다음과 같이 할 수 있습니다.

glm::mat4 m = ...;
// Extract col vectors of the matrix
glm::vec3 col1(m[0][0], m[0][1], m[0][2]);
glm::vec3 col2(m[1][0], m[1][1], m[1][2]);
glm::vec3 col3(m[2][0], m[2][1], m[2][2]);
//Extract the scaling factors
glm::vec3 scaling;
scaling.x = glm::length(col1);
scaling.y = glm::length(col2);
scaling.z = glm::length(col3);

float scaleFactor = MAX(scaling.x, MAX(scaling.y, scaling.z));

( http://wklej.org/id/950061/을 기반으로 -OpenGL에서 행렬이 곱해지는 순서대로 이름을 사용하기 때문에 이름이 decomposeTRS이고 decomposeSRT가 아닙니다).

이제 원래 구 반지름에 scaleFactor를 곱하면 경계 구가 생깁니다.

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