픽셀셰이더 HLSL Pixel Shader 305890 2009년봄학기 6/10/2009 박경신 각픽셀의래스터라이즈과정을위해그래픽카드의 GPU 에서실행되는프로그램 Direct3D 는소프트웨어적으로픽셀셰이더기능을에뮬레이트하지않음 픽셀과텍스처좌표에대한직접적인접근, 처리 멀티텍스처링, 픽셀당조명, 필드깊이, 구름시뮬레이션, 불시뮬레이션, 복잡한그림자테크닉 GPU 가지원하는픽셀셰이더의버전체크 // Step 2: Check for hardware vp. D3DCAPS9 caps; d3d9->getdevicecaps(d3dadapter_default, devicetype, &caps); // If the device s supported version is less than version 2.0 if( caps.pixelshaderversion < D3DPS_VERSION(2,0) ) // Then pixel shader version 2.0 is not supported on this device Overview 픽셀셰이더를이용한멀티텍스처링 멀티텍스처링개념에대한기본적인이해 픽셀셰이더의작성법과생성법및사용법 픽셀셰이더를이용한멀티텍스처링의구현방법 * + 기반 (Base) 스포트라이트 (Spot Light) 텍스트 (Text)
픽셀셰이더를이용한멀티텍스처링 멀티텍스처링의개요 텍스처들을블렌딩함 기반 (Base) * + 스포트라이트 (Spot Light) 텍스트 (Text) 고정기능파이프라인 픽셀셰이더 라이트맵 (light maps) 이라는특수한텍스처맵을이용하면얻게되는장점 조명이미리계산됨 전반적인처리속도향상 단, 물체와조명이모두정적이여야함 Direct3D 조명모델보다훨씬정확하고정교한광원모델의이용가능 난반사라이트맵, 정반사라이트맵, 안개맵, 디테일맵 멀티텍스처링결과 멀티텍스처의활성화 텍스처지정함수와샘플러상태지정함수 HRESULT HRESULT SetTexture( SetTexture( DWORD DWORD Stage, Stage, // // specifies specifies the the texture texture stage stage index index IDirect3DBaseTexture9 IDirect3DBaseTexture9 *ptexture *ptexture ); ); HRESULT HRESULT SetSamplerState( SetSamplerState( DWORD DWORD Sampler, Sampler, // // specifies specifies the the texture texture stage stage index index D3DSAMPLERSTATETYPE D3DSAMPLERSTATETYPE Type, Type, DWORD DWORD Value Value ); 예 );) // Set first texture and corresponding sampler states Device->SetTexture( 0, BaseTex); Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // Set second texture and corresponding sampler states Device->SetTexture( 1, SpotLightTex); Device->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // Set third texture and corresponding sampler states Device->SetTexture( 2, StringTex); Device->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); 멀티텍스처좌표 각버텍스는활성화된텍스처개수와같은수의텍스처좌표집합을가져야함 최대 8개의텍스처좌표지원 예 ) struct MultiTexVertex MultiTexVertex(float x, float y, float z, float u0, float v0, float u1, float v1, float u2, float v2) _x = x; _y = y; _z = z; _u0 = u0; _v0 = v0; _u1 = u1; _v1 = v1; _u2 = u2, _v2 = v2; float _x, _y, _z; float _u0, _v0; float _u1, _v1; float _u2, _v2; static const DWORD FVF; ; const DWORD MultiTexVertex::FVF = D3DFVF_XYZ D3DFVF_TEX3;
픽셀셰이더의입출력 입력 픽셀의컬러와텍스처좌표 예 ) struct PS_INPUT vector c0 vector c1 float2 t0 float2 t1 float2 t2 ; 픽셀셰이더의입력 버텍스셰이더의출력 출력 픽셀의하나의컬러 예 ) struct VS_OUTPUT vector finalpixelcolor ; : COLOR0; : COLOR1; : TEXCOORD0; : TEXCOORD1; : TEXCOORD2; : COLOR0; 픽셀셰이더의이용단계 픽셀셰이더를작성하고컴파일 컴파일된셰이더코드에기반한픽셀셰이더를나타내는 IDirect3DPixelShader9 인터페이스를생성 IDirect3DDevice9::SetPixelShader 메서드를이용해픽셀셰이더활성화 이용이끝난뒤, 픽셀셰이더제거 픽셀셰이더의작성과컴파일 HLSL 을이용해픽셀셰이더프로그램작성 ASCII 텍스트파일 ( 텍스트편집기이용 ) 픽셀셰이더컴파일 D3DXCompileShaderFromFile 함수이용 컴파일된셰이더코드를포함하는 ID3DXBuffer 포인터리턴 hr = D3DXCompileShaderFromFile( "ps_multitex.txt", 0, 0, "Main", // entry point function name "ps_1_1", D3DXSHADER_DEBUG, &shader, &errorbuffer, &MultiTexCT); 픽셀셰이더만들기 HRESULT IDirect3DDevice9::CreatePixelShader( const const DWORD *pfunction, IDirect3DPixelShader9** ppshader ); ); 예 ) IDirect3DPixelShader9* MultiTexPS = 0; ID3DXConstantTable* MultiTexCT = 0; ID3DXBuffer* shader = 0; ID3DXBuffer* errorbuffer = 0; hr = D3DXCompileShaderFromFile( "ps_multitex.txt", 0, 0, "Main", // entry point function name "ps_1_1", D3DXSHADER_DEBUG, &shader, &errorbuffer, &MultiTexCT); hr = Device->CreatePixelShader( (DWORD*)shader->GetBufferPointer(), &MultiTexPS);
픽셀셰이더의활성화와제거 픽셀세이더의활성화 HRESULT IDirect3DDevice9::SetPixelShader( IDirect3DPixelShader9* pshader ); ); 예 ) Device->BeginScene(); 이용이끝난뒤에는픽셀셰이더를제거 예 ) Device->SetPixelShader(MultiTexPS); Device->SetFVF(MultiTexVertex::FVF); Device->SetStreamSource(0, QuadVB, 0, sizeof(multitexvertex)); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); Device->EndScene(); d3d::release<idirect3dpixelshader9*>(multitexps); d3d::release<id3dxconstanttable*>(multitexct); HLSL 샘플러객체 (u,v) 텍스처좌표로인덱스하려는텍스처 텍스처와샘플러상태를식별하는객체 (u,v) 인덱스할출력컬러 Sampling 텍스처좌표 + 텍스처 예 ) sampler BaseTex; sampler SpotLightTex; 픽셀셰이더코드 sampler StringTex; IDirect3DTexture9* BaseTex = 0; D3DXHANDLE BaseTexHandle = 0; D3DXCONSTANT_DESC BaseTexDesc; D3DXCreateTextureFromFile(Device, "crate.bmp", &BaseTex); BaseTexHandle = MultiTexCT->GetConstantByName(0, "BaseTex"); MultiTexCT->GetConstantDesc(BaseTexHandle, &BaseTexDesc, &count); Device->SetTexture( BaseTexDesc.RegisterIndex, BaseTex); Device->SetSamplerState(BaseTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(BaseTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(BaseTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Sample: Multitexturing Shader: ps_multitex.txt sampler BaseTex; sampler SpotLightTex; sampler StringTex; struct PS_INPUT float2 base : TEXCOORD0; float2 spotlight : TEXCOORD1; float2 text : TEXCOORD2; ; struct PS_OUTPUT vector diffuse : COLOR0; ; PS_OUTPUT Main(PS_INPUT input) PS_OUTPUT output = (PS_OUTPUT)0; vector b = tex2d(basetex, input.base); vector s = tex2d(spotlighttex, input.spotlight); vector t = tex2d(stringtex, input.text); vector c = b * s + t; c += 0.1f; output.diffuse = c; return output;
Global Variables IDirect3DPixelShader9* MultiTexPS = 0; ID3DXConstantTable* MultiTexCT = 0; IDirect3DVertexBuffer9* QuadVB = 0; IDirect3DTexture9* BaseTex = 0; IDirect3DTexture9* SpotLightTex = 0; IDirect3DTexture9* StringTex = 0; D3DXHANDLE BaseTexHandle = 0; D3DXHANDLE SpotLightTexHandle = 0; D3DXHANDLE StringTexHandle = 0; D3DXCONSTANT_DESC BaseTexDesc; D3DXCONSTANT_DESC SpotLightTexDesc; D3DXCONSTANT_DESC StringTexDesc; struct MultiTexVertex MultiTexVertex(float x, float y, float z, float u0, float v0, float u1, float v1, float u2, float v2) _x = x; _y = y; _z = z; _u0 = u0; _v0 = v0; _u1 = u1; _v1 = v1; _u2 = u2, _v2 = v2; float _x, _y, _z; float _u0, _v0; float _u1, _v1; float _u2, _v2; static const DWORD FVF; ; const DWORD MultiTexVertex::FVF = D3DFVF_XYZ D3DFVF_TEX3; Creating a Vertex Buffer bool Setup() HRESULT hr = 0; Device->CreateVertexBuffer( 6 * sizeof(multitexvertex), D3DUSAGE_WRITEONLY, MultiTexVertex::FVF, D3DPOOL_MANAGED, &QuadVB, 0); MultiTexVertex* v = 0; QuadVB->Lock(0, 0, (void**)&v, 0); v[0] = MultiTexVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); v[1] = MultiTexVertex(-10.0f, 10.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); v[2] = MultiTexVertex( 10.0f, 10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[3] = MultiTexVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); v[4] = MultiTexVertex( 10.0f, 10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[5] = MultiTexVertex( 10.0f, -10.0f, 5.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); QuadVB->Unlock(); Compiling and Creating a PS Obtaining Handles and Initializing PS s Variables ID3DXBuffer* shader = 0; ID3DXBuffer* errorbuffer = 0; hr = D3DXCompileShaderFromFile( "ps_multitex.txt", 0, 0, "Main", // entry point function name "ps_1_1", D3DXSHADER_DEBUG, &shader, &errorbuffer, &MultiTexCT); if( errorbuffer ) ::MessageBox(0, (char*)errorbuffer->getbufferpointer(), 0, 0); d3d::release<id3dxbuffer*>(errorbuffer); if(failed(hr)) ::MessageBox(0, "D3DXCompileShaderFromFile() - FAILED", 0, 0); return false; hr = Device->CreatePixelShader( (DWORD*)shader->GetBufferPointer(), &MultiTexPS); if(failed(hr)) ::MessageBox(0, "CreateVertexShader - FAILED", 0, 0); return false; d3d::release<id3dxbuffer*>(shader); D3DXCreateTextureFromFile(Device, "crate.bmp", &BaseTex); D3DXCreateTextureFromFile(Device, "spotlight.bmp", &SpotLightTex); D3DXCreateTextureFromFile(Device, "text.bmp", &StringTex); D3DXMATRIX P; D3DXMatrixPerspectiveFovLH(&P, D3DX_PI * 0.25f, (float)width / (float)height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &P); Device->SetRenderState(D3DRS_LIGHTING, false); BaseTexHandle = MultiTexCT->GetConstantByName(0, "BaseTex"); SpotLightTexHandle = MultiTexCT->GetConstantByName(0, "SpotLightTex"); StringTexHandle = MultiTexCT->GetConstantByName(0, "StringTex"); UINT count; MultiTexCT->GetConstantDesc(BaseTexHandle, &BaseTexDesc, &count); MultiTexCT->GetConstantDesc(SpotLightTexHandle, &SpotLightTexDesc, &count); MultiTexCT->GetConstantDesc(StringTexHandle, &StringTexDesc, &count); MultiTexCT->SetDefaults(Device); return true;
Display ( ) (1) Display ( ) (2) bool Display(float timedelta) if( Device ) // Update the scene: code snipped... Device->Clear(0, 0, D3DCLEAR_TARGET D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); Device->SetPixelShader(MultiTexPS); Device->SetFVF(MultiTexVertex::FVF); Device->SetStreamSource(0, QuadVB, 0, sizeof(multitexvertex)); Device->SetTexture( BaseTexDesc.RegisterIndex, BaseTex); Device->SetSamplerState(BaseTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(BaseTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(BaseTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetTexture( SpotLightTexDesc.RegisterIndex, SpotLightTex); Device->SetSamplerState(SpotLightTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(SpotLightTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(SpotLightTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetTexture( StringTexDesc.RegisterIndex, StringTex); Device->SetSamplerState(StringTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(StringTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(StringTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); Device->EndScene(); Device->Present(0, 0, 0, 0); return true; Cleanup ( ) 연습문제 Phong Shading void Cleanup() d3d::release<idirect3dvertexbuffer9*>(quadvb); d3d::release<idirect3dtexture9*>(basetex); d3d::release<idirect3dtexture9*>(spotlighttex); d3d::release<idirect3dtexture9*>(stringtex); d3d::release<idirect3dpixelshader9*>(multitexps); d3d::release<id3dxconstanttable*>(multitexct);
Shader: phong.txt struct VS_INPUT vector position : POSITION; vector normal : NORMAL; ; struct VS_OUTPUT vector position : POSITION; vector light : TEXCOORD0; vector normal : TEXCOORD1; vector view : TEXCOORD2; ; Shader: phong.txt VS_OUTPUT VS_Main(VS_INPUT input) VS_OUTPUT output = (VS_OUTPUT)0; output.position = mul(input.position, ViewProjMatrix); LightDirection.w = 0.0f; input.normal.w = 0.0f; output.light = mul(lightdirection, ViewMatrix); output.normal = mul(input.normal, ViewMatrix); output.view = normalize(mul(input.position, ViewMatrix)); struct PS_INPUT vector light : TEXCOORD0; vector normal : TEXCOORD1; vector view : TEXCOORD2; ; struct PS_OUTPUT vector diffuse : COLOR; ; return output; Shader: phong.txt Shader: phong.txt (3) PS_OUTPUT PS_Main(PS_INPUT input) PS_OUTPUT output = (PS_OUTPUT)0; float d = saturate(dot(input.normal, input.light)); input.light.w = 0.0f; input.normal.w = 0.0f; vector r = normalize(reflect(input.light, input.normal)); float s = pow(saturate(dot(input.view, r)), 8); output.diffuse = (AmbientMtrl * AmbientLightIntensity) + (d * (DiffuseLightIntensity * DiffseMtrl)) + (s * (SpecularLightIntensity * SpecularMtrl)); return output;
Global Variables Compiling a Vertex Shader Creating a Vertex Shader Compiling a Pixel Shader
Creating a Pixel Shader Obtaining Handles and Initializing Variables Cleanup ( ) Display ( )
Exercise Bump Mapping 범프매핑 표면이렌더링될때, 법선벡터에잡음을넣어왜곡시키는기법 표면색상에작은변동이생겨울퉁불퉁해보임 텍스처맵 탄젠트좌표계 컬러맵 N U N N U V N U V 범프맵 법선벡터와탄젠트벡터의계산 V U V HRESULT HRESULT D3DXComputeNormals( LPD3DXBASEMESH pmesh, pmesh, CONST CONST DWORD DWORD ** padjacency padjacency ); ); HRESULT HRESULTWINAPI WINAPID3DXComputeTangent( LPD3DXMESH LPD3DXMESHMesh, Mesh, DWORD DWORDTexStageIndex, DWORD DWORDTangentIndex, DWORD DWORDBinormIndex, DWORD DWORDWrap, Wrap, const const DWORD DWORD *padjacency *padjacency););
Global Variables Loading a Mesh from X-File Computing Normal & Tangent Vectors Cleanup & Compiling VS
Creating VS & Compiling PS Creating PS & Getting Handles Getting Handles for Samplers Cleanup ( )
Enabling VS and PS Bump Mapping Shader: bump.txt (1) Shader: bump.txt (2)
Shader: bump.txt (3)