버텍스셰이더 9 기초

다이렉트 9.0으로 오면서 8.0과 사용법이 다르다.
내가 사용한 버전은 9.0C 버전으로 컴파일한 버전으로 Shader8.0의 tutorial01과 비교해보자.
주황색으로 있는게 9.0C 버전이고 위에 있는 코드가 8.0 버전이다.

다이렉트 X 고정파이프 부분을 비교한후 셰이더의 다른점을 알아보자.

1. 헤더파일과 라이브러리 교체

#include <d3d8.h>
#include <d3dx8.h>
#pragma comment (lib, "dxguid.lib")
#pragma comment (lib, "d3d8.lib")
#pragma comment (lib, "d3dx8.lib") 

#include <d3d9.h>
#include <d3dx9.h>
#pragma comment (lib, "dxguid.lib")
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

헤더파일과 라이브러리를 9로 교체한다.


2. 인터페이스 교체

LPDIRECT3D8                            g_d3d        = NULL; // our main d3d8 interface
LPDIRECT3DDEVICE8                  g_d3d_Device = NULL; // our d3d8 device
LPDIRECT3DVERTEXBUFFER8      g_VertexBuffer = NULL; // our VertexBuffer
D3DPRESENT_PARAMETERS       g_d3dpp;

DWORD                                   g_hVShader = 0;  //버텍스 셰이더의 핸들

LPDIRECT3D9                                 g_d3d        = NULL; // our main d3d8 interface
LPDIRECT3DDEVICE9                       g_d3d_Device = NULL; // our d3d8 device
LPDIRECT3DVERTEXBUFFER9           g_VertexBuffer = NULL; // our VertexBuffer
D3DPRESENT_PARAMETERS            g_d3dpp;

LPDIRECT3DVERTEXSHADER9          g_hVShader = 0;  //버텍스 셰이더의 핸들
LPDIRECT3DVERTEXDECLARATION9  g_pVertexDeclaration = 0;

다이렉트 X  인터페이스, 디바이스, 버텍스 버퍼가 9로 바뀌었고, 버텍스 셰이더의 핸들을 8.0에서는 DWORD로 사용 했으나 9.0에서는 셰이더 선언 LPDIRECT3DVERTEXSHADER9를 사용하여 버텍스 셰이더의 핸들을 선언한다.

버텍스 셰이더용 변수가 하나 더 추가되었다.
g_pVertexDeclaration 셰이더 선언핸들이 하나 더 필요하다. 8에서는 CreateVertexShader()에서 버텍스 선언 배열을 넘겨주지만 9에서는 SetVertexDeclaration(g_pVertexDeclaration) 처럼 버텍스 선언핸들을 넘겨준다. 뒤에 가면 나올 것이다.


3. 다이렉트 X 인터페이스 생성

if( NULL == ( g_d3d = Direct3DCreate8( D3D_SDK_VERSION ) ) )

if( NULL == ( g_d3d = Direct3DCreate9( D3D_SDK_VERSION ) ) )


4. D3DPRESENT 구조체 교체

g_d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;

g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;


5. CreateVertexBuffer 변화

g_d3d_Device->CreateVertexBuffer(7*sizeof(CUSTOMVERTEX),   
                          0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_VertexBuffer)

g_d3d_Device->CreateVertexBuffer(7*sizeof(CUSTOMVERTEX),
                          0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_VertexBuffer, NULL)

마지막 인자 pSharedhandle이 추가 되었는데, 이용되지 않으며 NULL로 채운다.


6. SetStreamSource, SetVertexShader 변화

        g_d3d_Device->SetStreamSource( 0,  g_VertexBuffer, sizeof(CUSTOMVERTEX) );
        g_d3d_Device->SetVertexShader( D3DFVF_CUSTOMVERTEX );

        g_d3d_Device->SetStreamSource( 0,  g_VertexBuffer, 0, sizeof(CUSTOMVERTEX) );
        g_d3d_Device->SetFVF( D3DFVF_CUSTOMVERTEX );

SetStreamSource()도 바뀌었다. 9.0버전에 세 번째 파라메터가 추가 되었다. 뭐하는지는 9.0문서가 없어서 그냥 넘어간다.
8에서 사용하던 SetVertexShader()는 9에서는 셰이더를 설정할 때만 사용된다.
9에서 고정파이프라인의 버텍스 타입은 어떻게 셋팅하냐면 SetFVF를 사용한다.

 

하하하 ~~~ 언제 끝나!

 이제 셰이더 설명으로 넘어 갈련다. 지겨워서 넘어갈련다..휘리릭 ~~~

 1) 셰이더 변수 선언

LPDIRECT3DVERTEXSHADER9	g_hVShader = 0;  //버텍스 셰이더의 핸들
LPDIRECT3DVERTEXDECLARATION9  g_pVertexDeclaration = 0;

9.0 버텍스 셰이더에서는 LPDIRECT3DVERTEXDECLARATION9 선언을 셰이더 핸들과 함께 전역변수를 만든다.
이유는 셰이더 생성에서 알아 본다.

2) 셰이더 생성

HRESULT CreateShader()
{
	const char szVertextShader[] =
	"vs.1.1                \n"
	"dcl_position v0       \n"
	"dcl_color   v5        \n"
	"dp4 oPos.x, v0, c0    \n"
	"dp4 oPos.y, v0, c1    \n"
	"dp4 oPos.z, v0, c2    \n"
	"dp4 oPos.w, v0, c3    \n"
	"mov oD0,  v5          \n";

	D3DVERTEXELEMENT9 Declaration[] =
	{
		{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
		D3DDECL_END()
	};

    if( FAILED(g_d3d_Device->CreateVertexDeclaration( Declaration, &g_pVertexDeclaration )))
    {
		_RELEASE_(g_pVertexDeclaration);
		return E_FAIL;
    }

	ID3DXBuffer* pShaderBuffer;
	ID3DXBuffer* pShaderErrors;

	if (FAILED(D3DXAssembleShader(szVertextShader, sizeof(szVertextShader) - 1, 0, NULL, 
					DXSHADER_DEBUG, &pShaderBuffer, &pShaderErrors)))
		return E_FAIL;

	if (FAILED(g_d3d_Device->CreateVertexShader((DWORD *)pShaderBuffer->GetBufferPointer(), &g_hVShader)))
		return E_FAIL;
	_RELEASE_(pShaderBuffer);
	return S_OK;
}

 9.0 버텍스 셰이더에는 아래의 2가지 명령으로 입력 레지스트를 선언한다.

dcl_position v0
dcl_color   v5  

8.0 버텍스 셰이더에서는 정해진 입력값을 디폴트로 사용했지만, 9.0에서는 선언하여 사용한다.(확실한지 아닌지 잘모름).

버텍스 선언도 약간 바뀌었다. Declaration을 보자.

0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0

0 : 스트림 번호 0 이 예제는 단일 스트림이다.

0 : 버텍스의 시작점 오프셋 지정. 바이트 단위로 하는데, Diffuse Color가 나올 때는 12바이트부터 시작이다.

D3DDECLTYPE_FLOAT3  : 데이터 타입 지정. 이 상수는 3개의 부동소수점(x, y, z)을 의미한다.

D3DDECLMETHOD_DEFAULT : 테셀레이션 명령. 기본값은 테셀레이션없이 데이터가 파이프라인을 통과한다.

D3DDECLUSAGE_POSITION : 데이터의 사용되는 용도로 여기서는 위치 데이터를 의미한다.

0 : 용법 인덱스. D3DDECLUSAGE_TEXCOORD0, D3DDECLUSAGE_TEXCOORD1 등과 같은 유사한 데이터 성분을 사용하는 버텍스 버퍼에서 성분을 식별한다. 각 용법 인덱스 조합은 시멘틱(semantic)으로 불린다. 시멘틱은 버텍스 버퍼  성분을 버텍스 셰이더 레지스터에 링크한다.

마지막 줄은 D3DDECL_END()매크로이다.

CreateVertexDeclaration( Declaration, &g_pVertexDeclaration )

8.0에서는 버텍스 선언자를 CreateVertexShader()시에 전달했지만 9.0에서는 SetVertexDeclaration()실행시에 설정한다.

D3DXAssembleShader()에서는 DXSHADER_DEBUG가 추가 되었다.

CreateVertexShader((DWORD *)pShaderBuffer->GetBufferPointer(), &g_hVShader)

앞에서도 설명했다시키 버텍스 선언자 셋팅이 별도로 분리 되었다.

3) 렌드링
void MoveShip(float fx, float fy)
{
	D3DXMATRIX	mScale1, mRot1, mTran1, mResult1;
	D3DXMATRIX	mScale2, mRot2, mTran2, mResult2;
	D3DXMATRIX	mScale3, mRot3, mTran3, mResult3;

	//본체
	//SRT
	D3DXMatrixScaling( &mScale1, 1.1f, 1.1f, 1.1f );
	D3DXMatrixRotationZ(&mRot1, D3DXToRadian(g_fDegree));
	D3DXMatrixTranslation( &mTran1, fx, fy, 0.0f);

	mResult1 = mScale1 * mRot1 * mTran1;
#if  0
	g_d3d_Device->SetTransform( D3DTS_WORLD, &mResult1);
	g_d3d_Device->DrawPrimitive( D3DPT_TRIANGLESTRIP, 3, 2 );
#else
	D3DXMATRIX ShaderMatrix = mResult1 * g_matCameraView * g_matProj;

	//Get the transpose
	D3DXMatrixTranspose(&ShaderMatrix, &ShaderMatrix);

	//Pass the transposed matrix to the shader
	g_d3d_Device->SetVertexShaderConstantF(0, (float*)&ShaderMatrix, 4);
	g_d3d_Device->SetVertexDeclaration( g_pVertexDeclaration);
	g_d3d_Device->SetVertexShader( g_hVShader);
	g_d3d_Device->DrawPrimitive( D3DPT_TRIANGLESTRIP, 3, 2 );

	g_d3d_Device->SetVertexShader(NULL);
	g_d3d_Device->SetFVF(D3DFVF_CUSTOMVERTEX);
#endif

	//포탑
	D3DXMatrixScaling( &mScale2, 1.0f, 1.0f, 1.0f );
	D3DXMatrixRotationZ(&mRot2, D3DXToRadian(g_fTurretDegree));
	D3DXMatrixTranslation( &mTran2, 0.0f, -0.7f, 0.0f );
	
    mResult2 = mScale2 * mRot2 * mTran2 * mResult1;
	g_d3d_Device->SetTransform( D3DTS_WORLD, &mResult2 );
	g_d3d_Device->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );

	//포
	D3DXMatrixScaling( &mScale3, 0.1f, 0.3f, 1.0f );
	D3DXMatrixRotationZ(&mRot3, 0.0f);
	D3DXMatrixTranslation( &mTran3, 0.0f, -0.1f, -0.5f);

	mResult3 = mScale3 * mRot3 * mTran3 * mResult2;
	g_d3d_Device->SetTransform( D3DTS_WORLD, &mResult3 );
	g_d3d_Device->DrawPrimitive( D3DPT_TRIANGLESTRIP, 3, 2 );

g_d3d_Device->SetVertexDeclaration( g_pVertexDeclaration) 버텍스 선언자를 별도로 선언한다.

4) 소멸

	    
    _RELEASE_(g_hVShader);
    _RELEASE_(g_pVertexDeclaration);
DeleteVertexShader() 같은 셰이더 소멸자는 더 이상 사용하지 않는다.
버텍스 선언자도 소멸 시켜야 한다.
 
[펌]
Microsoft DirectX 9 Programmable Graphics Pipeline - 정보문화사
DirectX 실시간 렌더링 실전 테크닉 - 정보 문화사
http://www.t-pot.com