DirectX SDK February 2010  버전까지는 'EnhancedMesh' 라는 샘플이 있었습니다.
아쉽게도 2010 June 버전에서 이 샘플은 사라졌습니다.
메시의 퀄리티를 향상시키는 샘플인데, 실제로는 폴리곤 갯수를 증가시키고 있습니다.
굳이 실행을 실켜보실 이유는 없습니다. ^^

ID3DXMesh 인터페이스에는 멤버함수로 CloneMeshFVF() 를 가지고 있습니다.
이 멤버함수의 옵션으로 D3DXMESH_NPATCHES 을 사용하게 되면,
하드웨어 가속을 받아서 폴리곤을 증가시킬 수 있습니다.
물론 내부적으로는 많은 연산을 수행할 것입니다.



만약 테셀레이션 작업이 그래픽카드에서 지원을 해주지 않는다면,
이는 CPU 기반으로 작업을 수행해야 합니다.
바로 이를 도와주는 API 가 D3DXTessellateNPatches() 입니다.



이렇듯 DirectX9 세대에도 테셀레이션을 위해서 API들을 지원해 주고 있었습니다.
물론 정식으로 그래픽카드에서 지원을 하지 않았기 때문에,
성능에 많은 문제점을 가지고 있었습니다.
테셀레이션 자체가 근본적으로 많은 연산을 수반하기 때문입니다.

다음 시간에는, 마지막으로 ATI의 DirectX9 기반의 테셀레이션 작업에 대해서 살펴보도록 하겠습니다.^^

신고


앞선 시간을 통해서 ID3DXPatchMesh 를 이용하면
간단하게 테셀레이션이 적용된 메시를 만들 수 있음을 언급했었습니다.
실제로 D3DX 유틸리티 클래스들이 테셀레이션을 손쉽게 적용할 수 있도록 구비가 되어있습니다.
그렇다는 것은 실제로는 DirectX 내부적으로 코어한 API가 있다는 얘기입니다.

테셀레이션과 관련한 DirectX 에서 코어한 API가 바로
IDirect3DDevice9::DrawTriPatch() 와 IDirect3DDevice9::DrawRectPatch() 입니다.
API 이름에서 쉽게 이해할 수 있듯이 전자는 삼각형과 관련한 것이고 후자는 사각형과 관련한 것입니다.
두 함수의 원형은 다음과 같습니다.

HRESULT DrawTriPatch
(
  [in]  UINT Handle,
  [in]  const float *pNumSegs,
  [in]  const D3DTRIPATCH_INFO *pTriPatchInfo
);


HRESULT DrawRectPatch(
  [in]  UINT Handle,
  [in]  const float *pNumSegs,
  [in]  const D3DRECTPATCH_INFO *pRectPatchInfo
);


그런데 조금 생소한 구조체 정보를 함수 인자로 받습니다.
이 두 API들은 함수 이름에서도 알 수 있듯이 실제로 렌더링을 수행하는 API 입니다.
테셀레이션을 위해서는 테셀레이션을 위한 정보들이 존재해야 합니다.
이들에 대한 설정 작업이 이루어져야 하는데,
이를 위한 구조체가 세번째 인자인 D3DTRIPATCH_INFO와 D3DRECTPATCH_INFO 입니다.
사각형과 관련한 작업은 삼각형과 유사하기 때문에 지금부터는 삼각형에 국한에서 글을 진행하겠습니다.


D3DTRIPATCH 구조체의 원형은 다음과 같습니다.

typedef struct D3DTRIPATCH_INFO
{
  UINT          StartVertexOffset;
  UINT          NumVertices;
  D3DBASISTYPE  Basis;
  D3DDEGREETYPE Degree;
} D3DTRIPATCH_INFO, *LPD3DTRIPATCH_INFO;


이 구조체는 버텍스 버퍼처럼 오프셋과 버텍스 갯수를 먼저 설정합니다.
D3DBASISTYPE 은 고차원 패치( high-order patch )의 기본 타입을 설정합니다.
삼각형의 경우에는 D3DBASIS_BEZIER 만 설정할 수 있습니다.

D3DDEGREETYPE 는 고차원 패치의 차수 정도를 설정하게 됩니다.
즉, 곡선을 표현하는 방정식의 차수를 표현하는데,
높은 차수를 선택할 수록 당연히 연산량이 많아질 것입니다.

이들에 대한 종류는 다음과 같습니다.

종류

버텍스 갯수
D3DDEGREE_CUBIC 10 ( 3차 방정식 )
D3DDEGREE_LINEAR 3   ( 1차 방정식 )
D3DDEGREE_QUADRATIC N/A ( 지원되지 않음 ) ( 2차 방정식 )
D3DDEGREE_QUINTIC 21 ( 4차 방정식 )


아래의 그림은 Cubic Bézier 방식의 삼각형 패치를 보여주고 있습니다.


Diagram of a triangular high-order patch with nine vertices


중간 중간에 생성된 정점을 기준으로 테셀레이션 작업이 수행될 것입니다.^^
이런 테셀레이션과 관련한 API들이 DirectX9 에 있었지만, 사실 거의 사용되지는 못했습니다.
왜냐하면, 정말이지 많은 연산을 필요로 하기 때문이겠죠? ^^
즉, DirectX9의 테셀레이션 작업은 소프트웨어적으로 에뮬레이션 되는 테셀레이션입니다.
신고


DirectX11 을 통해서 가장 많은 관심을 가지고 있는 부분 중 하나인 테셀레이션( Tessellation )은
갑자기 등장한 새로운 기능이 아닙니다.


< DirectX9에서의 테셀레이션의 등장 >

DirectX9 이 처음 세상에 등장할 때, 아래와 같은 특징들을 나열했었습니다.

- 2-D support
blt, copy, fill operations, GDI dialogs
- Adaptive tessellation
- Displacement mapping
- Two-sided stencil operations
- Scissor test rect
- Vertex stream offset
- Asynchronous notifications
- VS / PS 2.0
Flow control, float pixels
- Multiple render targets
- Gamma correction


Adaptive tessellation 이 보이시죠?
저도 그냥 무심코 지났던 DirectX9 소개 자료에서 우연히 찾았습니다.^^


< Adaptive tessellation >

테셀레이션에는 몇 가지 방법이 있는데,
그 중에 가장 유명한 것이 Adaptive 형식과 Uniform 형식입니다.
아래의 이미지를 보시기 바랍니다.


< 이미지 출처 : GPU Gems 2권 >


좌측의 경우가 Adaptive 한 방식입니다.
Adaptive 한 방식을 간단히 설명드리면,
시점의 위치에 근거에서 얼마나 많은 면을 생성할 지를 판단해서,
테셀레이션 작업
을 하는 것입니다.

반면에 Uniform 한 방식은,
모두 균일한 면의 갯수로 테셀레이션 작업을 수행하는 방법
입니다.
Uniform 한 방식이 더 연산 수가 많은 것이 일반적이기 때문에,
Adaptive 한 방식이 게임 분야에서 주로 사용됩니다.



< 테셀레이션을 위해 필요한 정보 >

테셀레이션 작업을 위해서는 두 가지가 필요합니다.
그것은 제어점들( Control Points )과 테셀레이션 팩터들( Tessellation Factors ) 입니다.
제어점들은 파이프라인에 입력으로 들어감으로써 패치( Patch ) 형태로 변환되어서
최종적으로 렌더링
되게 됩니다.
이 과정에 대한 자세한 설명은 앞으로도 꾸준히 언급될 것입니다.
지금은 간단하게 이 정도로만 설명하고 넘어가겠습니다.^^



< ID3DXPatchMesh >

그러면 DirectX9 은 어떤 방식으로 테셀레이션 작업을 지원했을까요?
그것은 ID3DXPatchMesh 라는 인터페이스를 통해서 간접적으로 지원했습니다.

참고적으로 얘기드리면, DirectX 에서는 D3DX 라는 유틸리티를 통해서
메시를 관리할 수 있는 클래스를 제공했습니다.
ID3DXBaseMesh, ID3DXMesh, ID3DXSPMesh, ID3DXPMesh,
그리고 마지막으로 언급드렸던 ID3DXPatchMesh 입니다.

ID3DXPatchMesh 인터페이스는 다른 메시들을 지원하는 클래스와 다릅니다. 
일반적인 메시 인터페이스들은 ID3DXBaseMesh와 계층 관계를 이루는 반면에,
ID3DXPatchMesh 는 완전히 별도로 구성된 클래스입니다.
즉, ID3DXPatchMesh 클래스는 IUnknown 인테페이스를 상속받습니다.


ID3DXPatchMesh는 테셀레이션 작업을 위해서 각종 멤버 함수를 가지고 있습니다.
실제로 테셀레이션 작업을 하는 함수는 ID3DXPatchMesh::Tessellate() 와
ID3DXPatchMesh::TessellateAdaptive()
입니다.
이들 함수에 대한 형태는 다음과 같습니다.

HRESULT Tessellate
(
  [in]  FLOAT fTessLevel,
  [in]  LPD3DXMESH pMesh
);

HRESULT TessellateAdaptive
(
  [in]  const D3DXVECTOR4 *pTrans,
  [in]  DWORD dwMaxTessLevel,
  [in]  DWORD dwMinTessLevel,
  [in]  LPD3DXMESH pMesh
);

두 멤버함수 모두 LPD3DXMESH 형태의 테셀레이션 작업이 끝난 메시를 리턴합니다.

이들에 대한 모든 작업은 CPU 가 담당합니다.
또한 연산량도 많기 때문에 Adaptive Tessellation을 처리하기는 상당한 무리가 있습니다.
왜냐하면 Adaptive Tessellation은 시점에 근거해서 매번 폴리곤을 생성해야하기 때문입니다.
ID3DXPatchMesh::Optimize() 라는 최적화 함수를 미리 호출해 줄수도 있지만,
그래도 이는 분명 매우 부담스러운 연산입니다.

< 마치면서... >
이상으로 ID3DXPatchMesh 를 활용한 DirectX9 의 테셀레이션 작업에 대해서 살펴보았습니다.
DirectX9 에서의 테셀레이션 작업의 불편함과 성능 문제를 이해한다면,
DirectX11 에서의 테셀레이션 작업의 우수성을 알 수 있을 것이라 생각됩니다.
다음 시간에도 계속 DirectX9 에서의 테셀레이션 작업에 대해서 살펴보겠습니다.^^
신고


한주만 쉰다는 것이, 죄송스럽게도 긴 휴식을 가지고 다시 등장습니다.
지난 시간까지 DirectX11 의 기본 API 를 간단히 언급했었습니다.
쉬는 사이에 안승근님께서 DirectX11과 관련된 기본적인 API 에 대한 글을 작성하기 시작하셨기 때문에
앞으로 기본적인 API 위주로 내용을 언급하지 않습니다.


< DirectX9 까지의 특징 >

DirectX는 Windows95 운영체제와 함께 처음 공개된 후에, 
어느덧 현세대까지 발전을 거듭했습니다.( 세월 참 빠르죠? ^^ )

너무 오랜 시간 전은 저도 잘 몰라서 DirectX7 버전부터의 가장 큰 변화를 하나씩 언급해 보겠습니다.
DirectX7 버전부터 변환과 라이팅(T&L) 을 위한 GPU가 활용되기 시작했고,
DirectX8 버전부터는 'Shader' 라는 GPU 를 활용한 프로그래밍이 도입되어서
현재 가장 개발자에게 주목받는 영역이 되었습니다.
개인적인 견해차이가 있겠지만, 저는 DirectX9 까지의 발전 과정 중에
가장 큰 변화로 바로 이 'GPU 의 활용'
이라고 생각하고 있습니다.

그러면 DirectX9 까지의 발전에서 변심(?)하지 않고,
저희를 언제나 반갑게(?) 맞이해 주었던 부분은 어떤 것이 있을까요? ^^
그것은 바로 API 를 설계할 때 항상 싱글 코어를 고려하고 만들었다는 것입니다.

또 다른 부분은 API 자체가 GPU 의 정점 처리 기능을 규정하고 있다는 것입니다.
언제나 '정점입력-->래스터라이즈-->픽셀처리-->디스플레이' 라는 큰 단계를
API 레벨에서 정의하고 있었습니다.
그 동안 우리는 이것은 Fixed pipeline 이라고 불렀습니다.
아래 이미지는 DirectX8 & 9 의 파이프라인입니다.



이미지 출처 : http://pc.watch.impress.co.jp/docs/column/kaigai/20090804_306876.html

사실 DirectX8 & 9 는 크게 차이가 없습니다.
파이프라인상에서 굳이 찾아야 한다면, 텍스쳐 메모리를 버텍스 쉐이더 단계에서도
참조할 수 있다는 정도일 뿐입니다.

간단히 제가 하고 싶은 말을 정리해 보자면,
'싱글코어 기반의 DirectX 의 시대는 이제 역사의 뒤로 사라지게 될 것이며,
GPU 는 더욱 복잡한 기능을 요구하게 될 것이다'
정도로 정리하겠습니다.
( 예언은 아니고, 이미 이렇게 되고 있는 상황이죠..^^ )


< 새로운 시대를 여는 DirectX11 >

아래는 DirectX11 의 파이프라인입니다.
잘 보시라고 그냥 크게 띄웁니다..^^


이미지 출처 : http://pc.watch.impress.co.jp/docs/column/kaigai/20090804_306876.html


DirectX11 의 가장 큰 특징을 저는 크게 3가지로 나누어 보았습니다.
  • GPU Tessellation.
  • Compute Shader.
  • Multi-threaded rendering.

사실 DirectX11 의 많은 부분은 X-Box360 에서 이미 사용되고 있습니다.
X-Box360 의 ComputeShader 지원은 모르겠으나, 나머지 두가지는 지원하고 있습니다.
X-360을 언급한 이유는 이들 기능이 이미 어느 정도 검증을 받은 기능이라는 점을 강조하고 싶어서 입니다.
( 물론 최신 버전이기 때문에 더 빨라지고, 더 좋아진 부분이 많습니다.^^ )

DirectX11 의 큰 패러다임은 '놀지마' 입니다.
이제는 멀티코어(CPU)와 GPU에게 최대한 많은 일을 시킬 수 있는 구조로
하드웨어를 구성했고, 그것을 기반으로 해서 런타임과 API 를 설계
하고 만들었습니다.

DirectX9 까지는 API 가 변화를 주도했다면,
이제는 DirectX API 변화를 하드웨어가 주도하고 있다고 볼 수 있습니다.
그러다보니 자연스럽게 API 도 더욱 하드웨어에 가깝게 설계되었습니다.
대표적으로 OutputMerge 를 지칭하는 OMxxxx 계열과
InputAssembler 를 지칭하는 IAxxxx 계열 등이 있습니다.

혹시 DirectX8-->9 로 포팅 작업을 하셨던 분들이 이 글을 읽으시는지 모르겠습니다만,
8-->9 의 변화는 API 차원에서 변화가 컸기 때문에 매우 단순했습니다.
하지만 이제는 하드웨어가 크게 변했기 때문에,
단순 포팅 작업 정도로 생각하시면 큰 오산입니다.
물론 단순히 API 만 교체해도 성능 향상을 얻을 수 있습니다.
DirectX11 은 하드웨어 오버헤드를 줄이기 위해 많은 최적화 작업을 수행했다고 합니다.

새로운 DirectX 의 시대가 왔다는 느낌이 드시나요? ^^

신고

'DirectX 11' 카테고리의 다른 글

[DX11_#4]텍스트, 버튼 출력  (0) 2009.11.10
[JumpToDX11-6] 커맨드(Command)...  (0) 2009.11.09
[JumpToDX11-5] 새로운 시대를 여는 DirectX11...  (6) 2009.11.02
[DX11_#3]기본적인 설정  (0) 2009.10.22
[DX11_#2]D3D Buffer( 2 / 2 )  (0) 2009.10.13
[DX11_#1]D3D Buffer( 1 / 2 )  (0) 2009.09.22