'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
'프로그래밍 > DirectX' 카테고리의 다른 글
SwapChain의 DXGI_FORMAT 종류 (3) | 2020.03.03 |
---|---|
DXGI_MODE_SCANLINE_ORDER, DXGI_MODE_SCALING의 Flags 종류 (0) | 2020.02.26 |
게임을 위한 Windows와 DirectX SDK 블로그 (0) | 2019.07.21 |