픽셀 셰이더 HLSL 기초

 

이번장에서는 픽셀 HLSL이다.   shader8.0   2장 shader9.0 2장을 보고 오면 도움이 될것이다.
이장 역시 코드 구현한지 오래 되어서 대충 후닥닥 넘어갈 것 같다.

 1) 셰이더 변수 선언

LPDIRECT3DPIXELSHADER9  g_hPShader = 0;  //픽셀 셰이더의 핸들 
LPD3DXCONSTANTTABLE     g_pPixelConstantTable = 0; //픽셀 상수테이블 접근 핸들

픽셀 셰이더에서는 디바이스 인터페이스의 상수 전달 함수를 통해 상수 값을 전달했지만 HLSL에서는 LPD3DXCONSTANTTABLE 인터페이스를 통해 상수를 전달해야한다.

2) 셰이더 생성

HRESULT CreateShader()
{
	//http://www.fairyengine.com/articles/hlsl2sided_fr.htm  참조

	const char szHlslShader[] =
/*
	"ps.1.1							        \n"
	//"def c2, 0.3333f, 0.59f, 0.11f, 0.0f  \n"
	"tex t0									\n"
	"dp3 r0, t0, c2							\n";
*/
"   sampler   baseTex;                                                              \n"
"   float4    cColor;                                                               \n"
"	                                                                                \n"
"   sampler Sampler = sampler_state                                                 \n"
"   {                                                                               \n"
"       Texture   = (baseTex);                                                      \n"
"       MipFilter = LINEAR;                                                         \n"
"       MinFilter = LINEAR;                                                         \n"
"       MagFilter = LINEAR;                                                         \n"
"   };                                                                              \n"
"                                                                                   \n"
"   struct PS_INPUT                                                                 \n"
"   {                                                                               \n"
"      float4  Color   : COLOR0;                                                    \n"  
"      float2  Tex0    : TEXCOORD0;                                                 \n"
"   };                                                                              \n"
"                                                                                   \n"
"   struct PS_OUTPUT                                                                \n" 
"   {                                                                               \n"
"      float4  Color   : COLOR;                                                     \n"     
"   };                                                                              \n"
"	                                                                                \n"
"   PS_OUTPUT PixelShader_main(PS_INPUT In)                                         \n"
"   {                                                                               \n"
"      PS_OUTPUT Out = (PS_OUTPUT) 0;                                               \n"
"      //float4    cColor = { 0.3333f, 0.59f, 0.11f, 0.0f };                          \n"
"                                                                                   \n"
"      Out.Color = tex2D(Sampler, In.Tex0) * In.Color;                              \n" 
"      Out.Color = dot(Out.Color, cColor);                                          \n"
"      return Out;                                                                  \n"
"   }                                                                               \n"
"";
 
	ID3DXBuffer* pShaderBuffer;
	ID3DXBuffer* pShaderErrors;
	if (FAILED(D3DXCompileShader(szHlslShader, sizeof(szHlslShader), 0, NULL,
"PixelShader_main", "ps_1_1", D3DXSHADER_DEBUG,
&pShaderBuffer, &pShaderErrors, &g_pPixelConstantTable))) { char* str = (char*)pShaderErrors->GetBufferPointer(); return E_FAIL; } if (FAILED(g_pd3dDevice->CreatePixelShader((DWORD *)pShaderBuffer->GetBufferPointer(), &g_hPShader))) return E_FAIL; _RELEASE_(pShaderBuffer); return S_OK; }

HLSL 설명은 마지막에 하겠다.
D3DXAssembleShader 대신 D3DXCompileShader를 사용하여 셰이더를 컴파일한다.
소스 보고 잘이해하기 바란다. (... 소스 작성한지 오래 되어서 역시 구찮음....)

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);


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

	//픽셀 셰이더 설정
	//참조:  http:/www.codesampler.com/dx9src.html
	//sampler를 하나 이상 정의 한다면, 픽셀 셰이더의 상수 테이블을 조사할 필요가 있다.
    //하드웨어에 맵핑 되어 있는 텍스쳐 스테이지의 sampler's ASCII name을 사용한다.
	//여기서 사용하는 픽셀셰이더는 간단하다. 
	//우리는 이미 텍스쳐가 스테이지 0으로 끝난다는 것을 알고 있기 때문에 다음 한줄만 부르면 된다.
    //
	// g_pd3dDevice->SetTexture( 0, g_pTexture );
	//
	// "Sampler"를 선언하지 않고 "baseTex만 선언했다면, GetConstantByName()에 "baseTex"를 적는다.
/*
	D3DXHANDLE  handle = g_pPixelConstantTable->GetConstantByName(NULL, "Sampler");
	if(handle)
	{
		D3DXCONSTANT_DESC constDesc;
		UINT count;

		g_pPixelConstantTable->GetConstantDesc(handle, &constDesc, &count);

		if(constDesc.RegisterSet == D3DXRS_SAMPLER)
			g_pd3dDevice->SetTexture(constDesc.RegisterIndex, g_pTexture);
	}
	else  
*/
		g_pd3dDevice->SetTexture( 0, g_pTexture );


    float fColorConstant[4] = { 0.3333f, 0.59f, 0.11f, 0.0f};
	g_pPixelConstantTable->SetVector(g_pd3dDevice, "cColor", (D3DXVECTOR4 *)fColorConstant);
	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;
}

                g_pd3dDevice->SetTexture( 0, g_pTexture );

다른 HLSL을 참고하면 텍스쳐나 샘플러를 넘겨주기 위해 복잡하게 사용하고 있을 것이다. 우리는 여기서 이렇게 간단하게 사용할까. 그 이유는 다음과 같다.

***픽셀 셰이더 텍스쳐나 셈플러 지정하기

참조: http:/www.codesampler.com/dx9src.html
sampler를 하나 이상 정의 한다면, 픽셀 셰이더의 상수 테이블을 조사할 필요가 있다.
하드웨어에 맵핑 되어 있는 텍스쳐 스테이지의 sampler's ASCII name을 사용한다.
여기서 사용하는 픽셀셰이더는 간단하다.
우리는 이미 텍스쳐가 스테이지 0으로 끝난다는 것을 알고 있기 때문에 다음 한줄만 부르면 된다. g_pd3dDevice->SetTexture( 0, g_pTexture );
"Sampler"를 선언하지 않고 "baseTex만 선언했다면, GetConstantByName()에 "baseTex"를 적는다.

그렇기 때문에 여기서 텍스쳐를 지정하는 두 코드는 똑같은 결과를 가져올것이다.

        g_pd3dDevice->SetTexture( 0, g_pTexture );

        D3DXHANDLE  handle = g_pPixelConstantTable->GetConstantByName(NULL, "Sampler");
        if(handle)
        {
                D3DXCONSTANT_DESC constDesc;
                UINT count;

                g_pPixelConstantTable->GetConstantDesc(handle, &constDesc, &count);
                if(constDesc.RegisterSet == D3DXRS_SAMPLER)
                        g_pd3dDevice->SetTexture(constDesc.RegisterIndex, g_pTexture);
        } 

g_pPixelConstantTable->SetVector(g_pd3dDevice, "cColor", (D3DXVECTOR4 *)fColorConstant)를 통해서 흑백 상수 값을 넘겨준다.

4) 소멸

	    
	_RELEASE_(g_hPShader);
	_RELEASE_(g_pPixelConstantTable);

g_pPixelConstantTable도 소멸 시킨다.
 

5) HLSL 설명

sampler   baseTex;  
float4     cColor;   

sampler Sampler = sampler_state                            
{                                                          
    Texture   = (baseTex);                                 
    MipFilter = LINEAR;                                    
    MinFilter = LINEAR;                                    
    MagFilter = LINEAR;                                    
};                                                         

struct PS_INPUT                                            
{                                                          
   float4  Color   : COLOR0;                               
   float2  Tex0    : TEXCOORD0;                            
};                                                         

struct PS_OUTPUT                                           
{                                                          
   float4  Color   : COLOR;                                
};                                                         

                                                          
PS_OUTPUT PixelShader_main(PS_INPUT In)                    
{                                                          
   PS_OUTPUT Out = (PS_OUTPUT) 0;                          
 
   Out.Color = tex2D(Sampler, In.Tex0) * In.Color;         
   Out.Color = dot(Out.Color, cColor);                     
   return Out;                                             
}
    

baseText, cColor를 선언하여 상수라는 것을 나타낸다
sampler Sampler를 선언하여 샘플러를 만들고 PS_INPUT 구조체로 입력을 PS_OUTPUT으로 출력을 선언한다.
 
Out.Color = tex2D(Sampler, In.Tex0) * In.Color;에 보면 샘플러를 넘겨주고 있다 샘플러가 선언되어 있지 않다면 baseTex를 넘겨주어 텍스쳐를 로딩한다. 셰이더 어셈블리어에서는 dp3로 내적곱을 햇지만 HLSL에서는 dot로 내적곱을 한다...

그럼 흑백그림이 쨘~~~ 하고 나올것이다.

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