DirectX와 HLSL간의 행렬순서와 연산

프로그래밍/DirectX

 

'DirectX 11을 이용한 3D 게임 프로그래밍 입문' 책을 참고하며 예제를 따라하고 있었는데 셰이더 부분에서 난관에 봉착했다.

 

예제 프로그램의 셰이더 코드에서는 'World * View * Projection' 순으로 행렬연산을 수행하는게, 내 프로그램에서는 'Project * View * World' 순으로 연산해야 정상적인 결과가 나왔기 때문이다.

 

도대체 무엇이 문제인지 계속 신경이 쓰여서 원인을 찾아보았다.

 

 

 

컴퓨터에서 다차원 배열로 행렬을 구성할 때, 행렬을 어떤 순서로 접근할 것인지에 대한 순서가 있다.

 

DirectX에서는 행렬 순서가 row-major(행우선)이고, HLSL에서는 column-major(열우선)이다.

 

 

위와 같이 행렬을 접근하는 순서가 다르기 때문에, 사용하는 라이브러리에 명시된 순서를 확인하고 그에 맞게 연산을 하지 않으면 제대로 된 결과가 나오지 않는다.

 

서로간의 행렬 순서가 달랐기 때문에, DirectX에서는 'World * View * Projection' 순으로 연산하는것을

셰이더(HLSL)에서는 'Projection * View * World'로 연산해야 제대로 된 결과값이 나왔던 것이다.

 

행렬이 DirectX에서 셰이더 상수로 넘어갈때 자동적으로 row-major에서 column-major로 변환된다.

따라서, 셰이더 코드에서도 DirectX와 똑같은 순서로 연산을 하려면, 상수버퍼의 행렬을 전치행렬로 변환하여 갱신해야 한다.

 

1
2
3
4
m_view = DirectX::XMMatrixTranspose(m_view);
m_projection = DirectX::XMMatrixTranspose(m_projection);
 
d3dDevice->CreateBuffer(&cbd, nullptr, &m_constantBuffer);
cs

 

예제에서는 Effect Interface를 사용하는데, 아마 내부에서 자동적으로 전치행렬로 변환하는 듯 하다.

내가 짠 코드에서는 Effect Interface를 사용하지도 않고, 전치행렬을 사용하지도 않아서 연산 순서가 뒤바뀌었던 것.

 

위와 같이 전치행렬로 변환하면, 셰이더 코드에서도 row-major 기준으로 연산을 할 수 있다.

 

1
2
3
Output.Pos = mul(float4(Input.Pos, 1.0f), matrixWorld);
Output.Pos = mul(Output.Pos, matrixView);
Output.Pos = mul(Output.Pos, matrixProj);
cs

row-major

 

1
2
3
Output.Pos = mul(matrixWorld, float4(Input.Pos, 1.0f));
Output.Pos = mul(matrixView, Output.Pos);
Output.Pos = mul(matrixProj, Output.Pos);
cs

column-major

 

 

참고

 

https://en.wikipedia.org/wiki/Row-_and_column-major_order

 

Row- and column-major order - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Illustration of difference between row- and column-major ordering In computing, row-major order and column-major order are methods for storing multidimensional arrays in linear storage

en.wikipedia.org

http://dolphin.ivyro.net/file/hlsl/tutorial06.html

 

HLSL mul

mul은 벡터와 행렬의 순서에 따라 결과가 다르다. mul(x, y) x값이 vector이면 row-vector로 처리하고 y값이 vector이면 column-vector로 처리한다. mul( vector, matrix ) ===>  row vector  (row-major matrix system) mul(matrix, vector ) ===> column vector  (column-major matrix system) DirectX API에서는 4차

dolphin.ivyro.net

https://www.gpgstudy.com/forum/viewtopic.php?p=108628

 

wvp 와 wv 계산후 proj - GpgStudy 포럼

2D, 3D, 다각형, 픽셀 등 게임의 그래픽 프로그래밍에 관한 포럼입니다. 운영자: 류광 심 형근 전체글: 526 가입일: 2002-08-19 23:30 전체글 글쓴이: 심 형근 » 2008-09-23 10:45 고정폭을 경계선을 가지는 카툰렌더링을 구현중 약간 이상한 증상을 발견하였는데, 왜 그런지를 모르겠습니다. 보통 입력된 버텍스 버퍼를 WorldViewProj 전환을 위해서 wvp = World * View * Proj 를 할당하며 쉐이더에서는

www.gpgstudy.com