C ++ 및 OpenGL 행렬 순서 간의 혼동 (행 주요 대 열 주요)
매트릭스 정의에 대해 완전히 혼란스러워하고 있습니다. float[16]
다음 관찰을 기반으로 행 중심이라고 가정 한 행렬 클래스가 있습니다 .
float matrixA[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
float matrixB[4][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 } };
matrixA
그리고 matrixB
모두 메모리에 같은 선형 레이아웃을 (즉, 모든 숫자는 순서대로)이있다. http://en.wikipedia.org/wiki/Row-major_order 에 따르면 이것은 행 중심 레이아웃을 나타냅니다.
matrixA[0] == matrixB[0][0];
matrixA[3] == matrixB[0][3];
matrixA[4] == matrixB[1][0];
matrixA[7] == matrixB[1][3];
따라서 matrixB[0]
= 행 0, matrixB[1]
= 행 1 등입니다. 다시 말하지만 이것은 행 중심 레이아웃을 나타냅니다.
내 문제 / 혼란은 다음과 같은 번역 매트릭스를 만들 때 발생합니다.
1, 0, 0, transX
0, 1, 0, transY
0, 0, 1, transZ
0, 0, 0, 1
메모리에 { 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }
.
그런 다음 glUniformMatrix4fv를 호출 할 때 transpose 플래그를 GL_FALSE로 설정하여 열이 중요 함을 나타내야합니다 . 그렇지 않으면 변환 / 크기 조정 등의 변환이 올바르게 적용되지 않습니다.
전치가 GL_FALSE이면 각 행렬은 열 주요 순서로 제공되는 것으로 간주됩니다. 전치가 GL_TRUE이면 각 행렬은 행 주 순서로 제공되는 것으로 간주됩니다.
행 중심으로 보이는 매트릭스를 OpenGL에 열 중심으로 전달해야하는 이유는 무엇입니까?
OpenGL 문서에 사용 된 매트릭스 표기법은 OpenGL 매트릭스의 메모리 내 레이아웃을 설명하지 않습니다.
전체 "행 / 열 주요"항목을 삭제 / 잊는 것이 더 쉬울 것이라고 생각한다면. 이는 행 / 열 전공 외에도 프로그래머가 표기법 외에도 메모리에 행렬을 배치하는 방법 (인접한 요소가 행 또는 열을 형성하는지 여부)을 결정할 수 있기 때문에 혼란을 더합니다.
OpenGL 행렬은 directx 행렬과 동일한 메모리 레이아웃을 갖습니다 .
x.x x.y x.z 0
y.x y.y y.z 0
z.x z.y z.z 0
p.x p.y p.z 1
또는
{ x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 }
x, y, z는 행렬 좌표계 (전역 좌표계에 상대적인 로컬 좌표계)를 설명하는 3 성분 벡터입니다.
p는 행렬 좌표계의 원점을 설명하는 3 성분 벡터입니다.
이는 번역 매트릭스가 다음과 같이 메모리에 배치되어야 함을 의미합니다.
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }.
그대로두면 나머지는 쉬울 것입니다.
--- 오래된 OpenGL FAQ에서 인용-
9.005 OpenGL 행렬은 열 중심입니까, 행 중심입니까?
프로그래밍 목적으로 OpenGL 행렬은 기본 벡터가 메모리에 연속적으로 배치 된 16 값 배열입니다. 번역 구성 요소는 16 개 요소 행렬의 13 번째, 14 번째 및 15 번째 요소를 차지합니다. 여기서 인덱스는 OpenGL 2.1 사양의 섹션 2.11.2에 설명 된대로 1에서 16까지 번호가 지정됩니다.
열 주요 대 행 주요는 순전히 표기 규칙입니다. 열 주요 행렬을 사용한 사후 곱셈은 행 주요 행렬을 사용한 사전 곱셈과 동일한 결과를 생성합니다. OpenGL 사양과 OpenGL 참조 설명서는 모두 열 주요 표기법을 사용합니다. 명확하게 언급 된 한 모든 표기법을 사용할 수 있습니다.
안타깝게도 사양 및 청서에서 열 주요 형식을 사용하면 OpenGL 프로그래밍 커뮤니티에서 끝없는 혼란을 초래했습니다. Column-major 표기법은 프로그래머가 예상하는 것처럼 행렬이 메모리에 배치되지 않음을 나타냅니다.
SigTerm 및 dsharlet의 답변을 요약하려면 : GLSL에서 벡터를 변환하는 일반적인 방법은 벡터에 변환 행렬을 왼쪽 곱하는 것입니다.
mat4 T; vec4 v; vec4 v_transformed;
v_transformed = T*v;
이것이 작동하기 위해 OpenGL T
은 SigTerm에서 설명한대로 메모리 레이아웃이 다음 과 같을 것으로 예상합니다 .
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }
'열 전공'이라고도합니다. 그러나 셰이더 코드 (주석에 표시된대로)에서 벡터에 변환 행렬을 오른쪽 곱했습니다.
v_transformed = v*T;
T
조옮김 된 경우에만 올바른 결과를 생성합니다 . 즉, 레이아웃이 있습니다.
{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }
(i.e. 'row major'). Since you already provided the correct layout to your shader, namely row major, it was not necessary to set the transpose
flag of glUniform4v
.
You are dealing with two separate issues.
First, your examples are dealing with the memory layout. Your [4][4] array is row major because you've used the convention established by C multi-dimensional arrays to match your linear array.
The second issue is a matter of convention for how you interpret matrices in your program. glUniformMatrix4fv is used to set a shader parameter. Whether your transform is computed for a row vector or column vector transform is a matter of how you use the matrix in your shader code. Because you say you need to use column vectors, I assume your shader code is using the matrix A and a column vector x to compute x' = A x.
I would argue that the documentation of glUniformMatrix is confusing. The description of the transpose parameter is a really roundabout way of just saying that the matrix is transposed or it isn't. OpenGL itself is just transporting that data to your shader, whether you want to transpose it or not is a matter of convention you should establish for your program.
This link has some good further discussion: http://steve.hollasch.net/cgindex/math/matrix/column-vec.html
'Nice programing' 카테고리의 다른 글
node-request- "SSL23_GET_SERVER_HELLO : unknown protocol"오류가 발생합니다. (0) | 2020.11.04 |
---|---|
Yeoman 발전기를 업데이트하는 데 선호되는 방법은 무엇입니까? (0) | 2020.11.04 |
Docker-Compose를 사용할 때 Django 데이터베이스 마이그레이션을 어떻게 수행합니까? (0) | 2020.11.04 |
다변량 하스켈 함수를 만드는 방법은 무엇입니까? (0) | 2020.11.04 |
#pragma 경고 푸시 / 팝을 사용하여 일시적으로 경고 수준을 변경하는 것이 올바른 방법입니까? (0) | 2020.11.04 |