'프로그래밍/DirectX'에 해당되는 글 4건
'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 |
DirectX에서 SwapChain을 생성할때 후면버퍼의 Format을 설정하는 부분이 있다.
1
2
3
4
5
6
7
8
9
|
// Swap chain
DXGI_SWAP_CHAIN_DESC sd;
sd.BufferDesc.Width = m_width;
sd.BufferDesc.Height = m_height;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
cs |
책에서나 다른 예제에서는 대충 "DXGI_FORMAT_R8G8B8A8_UNORM 을 자주 쓴다." 라는 말만 적혀있지, 왜 그걸 자주 쓰며 다른 Format에는 어떤 것이 있는지는 잘 나와있지 않다.
호기심에 DXGI_FORMAT의 다른 값을 넣어봤다.
DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_UINT 등등...
결과는 SwapChain 생성에 실패했다.
구글링을 해보았지만, 대부분 "DXGI_FORMAT_R8G8B8A8_UNORM을 기본으로 사용한다" 라는 튜토리얼 형식의 똑같은 설명 뿐이고 다른 Format을 사용하는 예제는 보이지 않았다.
내가 중간에 잘못 쓴 코드가 있는 것인지, 컴퓨터가 문제인지 알 수 없어서 한참을 찾아본 끝에서야 MSDN에서 관련 내용을 찾을 수 있었다.
This structure is used by the GetDisplayModeList and FindClosestMatchingMode methods. The following format values are valid for display modes and when you create a bit-block transfer (bitblt) model swap chain. The valid values depend on the feature level that you are working with.
|
즉, SwapChain의 후면버퍼와 같이 디스플레이에 관련된 DXGI_FORMAT은 위에 나열된 형식밖에 되지 않는다는 것.
DirectX의 버전이 올라가면서 표현 가능한 색상의 비트수만 커질뿐, 본질적인 형태는 크게 변하지 않은 듯 하다.
그래서 보통 "대부분의 경우에는 DXGI_FORMAT_R8G8B8A8_UNORM을 사용한다" 라고 설명하고 사용한 것 같다.
DXGI_FORMAT_R8G8B8A8_SNORM나 DXGI_FORMAT_R8G8B8A8_UINT와 같은 Format은 아예 지원하지 않는 형식이기 때문에 SwapChain을 만들지 못하고 오류가 발생한 것으로 보인다.
https://docs.microsoft.com/ko-kr/previous-versions/windows/desktop/legacy/bb173064(v=vs.85)
'프로그래밍 > DirectX' 카테고리의 다른 글
DirectX와 HLSL간의 행렬순서와 연산 (0) | 2020.03.06 |
---|---|
DXGI_MODE_SCANLINE_ORDER, DXGI_MODE_SCALING의 Flags 종류 (0) | 2020.02.26 |
게임을 위한 Windows와 DirectX SDK 블로그 (0) | 2019.07.21 |
DXGI_MODE_SCANLINE_ORDER
1
2
3
4
5
6
|
typedef enum DXGI_MODE_SCANLINE_ORDER {
DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED = 0,
DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE = 1,
DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST = 2,
DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST = 3
} DXGI_MODE_SCANLINE_ORDER;
|
cs |
-
DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED
Scanline order is unspecified. -
DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE
The image is created from the first scanline to the last without skipping any. -
DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST
The image is created beginning with the upper field. -
DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST
The image is created beginning with the lower field.
디스플레이에 화면을 그릴 때, 스캔라인 순서를 지정한다.
스캔라인 순서로 화면을 그릴 때 프로그레시브(Progressive)로 그리는가, 인터레이스(Interlace)로 그리는가를 설정할 수 있다.
DXGI_MODE_SCANLINE_ORDER_PROGRESSSIVE를 선택하면 프로그레시브(Progressive)로 그리게 된다.
DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST를 선택하면 인터레이스(Interlace)로 그리면서 홀수번째 줄에서,
DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST를 선택하면 짝수번째 줄에서부터 시작한다.
DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED를 선택하면 아무런 스캔라인 순서를 설정하지 않게 되는데, 이게 결과적으로 디스플레이에 맞춰서 자동적으로 선택을 하는건지 어떻게 되는건지 전혀 모르겠다. 정보가 안보인다.
프로그레시브(Progressive)와 인터레이스(Interlace)에 관한 내용은 아래의 링크를 참조.
https://m.cafe.daum.net/korea-man/7v20/84?
https://hruj.tistory.com/entry/m3
DXGI_MODE_SCALING
1
2
3
4
5
|
typedef enum DXGI_MODE_SCALING {
DXGI_MODE_SCALING_UNSPECIFIED = 0,
DXGI_MODE_SCALING_CENTERED = 1,
DXGI_MODE_SCALING_STRETCHED = 2
} DXGI_MODE_SCALING;
|
cs |
-
DXGI_MODE_SCALING_UNSPECIFIED
Unspecified scaling. -
DXGI_MODE_SCALING_CENTERED
Specifies no scaling. The image is centered on the display. This flag is typically used for a fixed-dot-pitch display (such as an LED display). -
DXGI_MODE_SCALING_STRETCHED
Specifies stretched scaling.
디스플레이의 비례에 따른 처리를 지정한다.
화면을 늘리거나 줄이거나, 전체화면을 하는 등 후면버퍼와의 비례차가 생길 때 어떻게 하는가에 대한 옵션이다.
DXGI_MODE_SCALING_UNSPECIFIED를 선택하면 아무런 설정도 하지 않는다.
DXGI_MODE_SCALING_CENTERED를 선택하면 스케일링을 하지 않고, 이미지가 디스플레이의 정 중앙에 위치하게 된다. 그리고 비례에 맞춰서 화면의 좌우/상단을 잘라내서 검은색 패딩으로 채운다.
DXGI_MODE_SCALING_STRETCHED를 선택하면 확장 스케일링을 지정한다.
DXGI_MODE_SCALING_CENTERED를 선택한 경우는 다른 두개의 옵션과는 명확하게 다른 결과가 나왔다. 하지만, UNSPECIFIED와 STRETCHED의 차이는 아직 잘 모르겠다. 추후 이미지를 띄워보고 살펴봐야 할 것 같다.
추가로, Alt+Enter 를 눌러서 전체화면을 할 경우 UNSPECIFIED는 바로 화면이 뜨는 반면 CENTERED/STRETCHED는 화면이 뜨기까지의 잠시 텀이 있는 등 스케일링 옵션을 처리하기 위해서인지 반응이 조금 느리다.
'프로그래밍 > DirectX' 카테고리의 다른 글
DirectX와 HLSL간의 행렬순서와 연산 (0) | 2020.03.06 |
---|---|
SwapChain의 DXGI_FORMAT 종류 (3) | 2020.03.03 |
게임을 위한 Windows와 DirectX SDK 블로그 (0) | 2019.07.21 |
DirectX 11을 공부하다가 찾은 블로그다. 특히 눈여겨 볼만한 게시글은 Living without D3DX 이다.
DirectX를 튜토리얼이나 책으로 처음 시작하게 되면 대부분 D3DX를 사용해서 구현하게 된다. 유용하고 편의성을 위한 기능들이 많기는 하지만, Windows SDK가 나오면서 DirectX SDK가 Windows SDK 쪽으로 흡수되고 D3DX를 비롯한 여러 라이브러리의 지원도 끊겼다.
그때 당시에는 어쩔 수 없이 썼을지 몰라도, 2019년이나 된 지금에 와서도 이걸 쓰기엔 좀... 여러 가지 문제로 어떻게 사용하지 않고 개발하는 방법이 없을까 하다가 찾게 되었다.
D3DX를 사용하지 않고 다른 라이브러리와 함수로 대체가능한 리스트들을 보여준다. HLSL의 경우에는 D3DCompile, 수학 계산의 경우에는 DirectXMath로 대체가 가능하다.
다만, 모든 기능을 대처할 수는 없었는지 일부 기능들은 DirectX Tool Kit과 같은 새로운 라이브러리를 만들어서 새로이 구현되어있다.
지원이 끊겨서 더 이상의 업데이트가 없는 D3DX와는 달리, 현재까지 계속적으로 업데이트가 되고 있으므로 충분히 믿을만하다.
'프로그래밍 > DirectX' 카테고리의 다른 글
DirectX와 HLSL간의 행렬순서와 연산 (0) | 2020.03.06 |
---|---|
SwapChain의 DXGI_FORMAT 종류 (3) | 2020.03.03 |
DXGI_MODE_SCANLINE_ORDER, DXGI_MODE_SCALING의 Flags 종류 (0) | 2020.02.26 |