픽셀 셰이더

DirextX 8.0의 tutorial12에 픽셀 셰이더를 추가하겠다. 칼라로 나오던 화면을 흑백으로 보여주게 된다.

 

입력 벡터 레지스터:
데이터가 들어오는 레지스터로 보간된 정점 색이 들어오는 버퍼로 v0, v1이 있다.(정점 셰이더의 oD0, oD1에서 온 출력이 픽셀 셰이더의 입력으로 들어온다)
보간된 텍스쳐 좌표가 들어오는 t0, t1, t2, t3가 있다.(정점 셰이더의 oT0, oT1...출력에서 입력으로 들어온다)

상수 레지스터:
c0 ~ c7까지 있다.

임시 레지스터:
r0, r1 임시 레지스터로 출력 레지스터로도 사용된다.

픽셀 셰이더 역시 정점 셰이더와 흐름은 크게 다르지 않다
입력레지스터의 값을 상수레지스터의 값으로 연산한 뒤에 출력레지스터로 보내준다는걸 기억하면 된다

출력 레지스터  = 상수 레지스터 (짬뽕) 입력 레지스터

DirextX 8.0의 tutorial 12에 새롭게 추가된것만 설명하겠다.

1) 셰이더 변수 선언

DWORD                 g_hPShader = 0;  //버텍스 셰이더의 핸들                 
HANDLE이 아니라 DWORD로 버텍스 셰이더의 핸들을 선언한다.

2) 셰이더 생성

HRESULT CreateShader()
{
	const char szPixelShader[] =
	"ps.1.1							        \n"
	//"def c2, 0.3333f, 0.59f, 0.11f, 0.0f  \n"
	"tex t0									\n"
	"dp3 r0, t0, c2							\n";
 
	ID3DXBuffer* pShaderBuffer;
	ID3DXBuffer* pShaderErrors;
	if (FAILED(D3DXAssembleShader(szPixelShader, sizeof(szPixelShader) - 1,
	                                            0, NULL, &pShaderBuffer, &pShaderErrors)))
		return E_FAIL;

	if (FAILED(g_pd3dDevice->CreatePixelShader((DWORD *)pShaderBuffer->
	                                            GetBufferPointer(), &g_hPShader)))
		return E_FAIL;
	_RELEASE_(pShaderBuffer);
	return S_OK;
}	
	    

CreateShader()를 RenderInit(), 즉 버텍스 버퍼 생성 이전에 실행한다.

D3DXAssembleShader과 D3DXAssembleShaderFromFile 2가지가 있는데, 셰이더가 간단하기 때문에 D3DXAssembleShader를 사용하여 셰이더 코드의 초소한 에러체크와 이진코드로 만들를 있다.
pShaderBuffer는 더 이상 필요하지 않기 때문에 해제한다.

셰이더 문법은 마지막에 설명하겠다.

D3DXAssembleShader()후에 CreatePixelShader()로 디바이스 상에 실제적으로 셰이더 인스턴스를 생성한다.

3) 렌드링

HRESULT Render3D ()
{
	HRESULT hr;

	D3DXMATRIX	matTranslation;

	// Clear the scene
	g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
		                                D3DCOLOR_XRGB(150,150,255), 1.0f, 0 );
	g_pd3dDevice->BeginScene();

	D3DXMatrixIdentity( &matTranslation );
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &matTranslation);
	
	//Set texture
	g_pd3dDevice->SetTexture( 0, g_pTexture );

	g_pd3dDevice->SetStreamSource(0, g_pVertexBuffer, sizeof(MYVERTEX));
	g_pd3dDevice->SetVertexShader(D3DFVF_MYVERTEX);

	float fColorConstant[][4] = 
	{
        { 0.3333f, 0.59f, 0.11f, 0.0f}
    };
    g_pd3dDevice->SetPixelShaderConstant( 2, (VOID*)fColorConstant ,1); 
	g_pd3dDevice->SetPixelShader(g_hPShader);

	g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

    //Clear texture
	g_pd3dDevice->SetTexture( 0, NULL );
	
	g_pd3dDevice->EndScene();
	hr = g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

	return hr;
}

텍스쳐의 픽셀과 조합될 칼라값을 c0에 벡터값으로 넘겨준다.
c0 레지스터 하나만 사용되기 때문에 3번째 파라메터는 1이다.
g_pd3Device->SetPixelShaderConstant(0, (VOID)fColorConstant, 1);

우리가 프로그래밍한 셰이더로 그리기 위해 픽셀셰이더를 설정한다.
g_pd3Device->SetPixelShader(g_hPShader)

4) 소멸

	if(g_hPShader)
	{
		g_pd3dDevice->DeletePixelShader(g_hPShader);
		g_hPShader = NULL;
	}

5) 셰이더 코드 설명

ps.1.1

셰이더 버전을 설정한다.

tex  t0
dp3  r0, t0, c2

t0 레지스터로 텍스쳐를 로딩한다.
출력 레지스터 r0에 로딩한 텍스쳐와 칼라 상수 c2의 내적으로 단위곱한것들을 넣는다.

그럼... 유우나의 이쁜 얼굴이 흑백으로 출력된다.

다이렉트 X 9.x에서는 셰이더 사용법이 약간 바뀌었다.

[펌]
DirectX 실시간 렌더링 실전 테크닉 - 정보 문화사
http://www.t-pot.com