DirectX Graphics 프로그래밍 가이드 프로그래밍 가능한 파이프라인 정점 셰이더 조명을 사용한 텍스처 맵 [목차열람] [주소복사] [슬롯비우기] |
Microsoft DirectX 9.0 |
이 예에서는, 정점 셰이더를 사용해, 텍스처 맵을 적용해, 장면(scene)에 조명을 추가한다. 사용하는 개체는 구체이다. 샘플 코드는, 지구의 텍스처 맵을 구체에 적용해, 디퓨즈 라이트를 적용해 밤과 낮을 시뮬레이트 한다.
샘플 코드는, Shader3 의 예에의 추가이며, 텍스처를 맵핑 한 개체에 조명을 추가한다. 텍스처 맵의 로드와 텍스처 스테이지 스테이트의 설정에 대해서는, Shader3 를 참조할것.
샘플 코드의 프레임워크(framework)에 대해서는, 「샘플 프레임워크(framework)」로 상세하게 설명한다. 샘플 코드를 샘플 프레임워크(framework)에 컷 앤드 페이스트 하는 것만으로, 동작하는 샘플을 간단하게 생성 할 수 있다.
정점 데이터는, Shader3 샘플로부터, 정점의 법선을 포함하도록(듯이) 변경되고 있다. 조명이 나타나도록(듯이) 하려면 , 개체에 정점의 법선이 필요하다. 정점 데이터의 데이터 구조를 다음에 나타낸다.
struct CUSTOMVERTEX_POS_NORM_COLOR1_TEX1 { float x, y, z; // position float nx, ny, nz; // normal DWORD color1; // diffuse color float tu1, tv1; // texture coordinates };
셰이더 선언은, 입력 정점 레지스터와 그것들에 관련된 데이터를 정의한다.
// Create the shader declaration. D3DVERTEXELEMENT9 decl[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, { 0, 28, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
이 선언은, 정점의 위치·법선·디퓨즈색·텍스처 좌표를 포함한 1 스트림의 데이터를 선언한다.
다음에, 셰이더를 생성 한다. 셰이더는, ASCII 텍스트 캐릭터 라인으로부터 생성 하는지, 같은 명령을 저장 한 셰이더 파일로부터 로드한다. 이 예에서는, 셰이더 파일을 사용한다.
// v7 vertex diffuse color used for the light color // v8 texture // c4 view projection matrix // c12 light direction vs_1_1 // version instruction dcl_position v0 // declare register data dcl_normal v4 // v0 is position, v4 is normal dcl_color0 v7 // v7 is diffuse color dcl_texcoord0 v8 // v8 is texture coordinates m4x4 oPos, v0, c4 // transform vertices using view projection transform dp3 r0, v4, c12 // perform lighting N dot L calculation in world mul oD0, r0.x , v7 // calculate final pixel color from light intensity and // interpolated diffuse vertex color mov oT0.xy , v8 // copy texture coordinates to output
최초로 버전 번호를 반드시 지정한다. 마지막 명령은, 텍스처 데이터를 출력 레지스터 oT0 로 이동한다. 셰이더 명령을 기입한 다음에, 그것들을 사용해 셰이더를 생성 할 수 있다.
LPDIRECT3DPIXELSHADER9 m_pVertexShader; TCHAR strShaderPath[512]; LPD3DXBUFFER pCode; // buffer with the assembled shader code LPD3DXBUFFER pErrorMsgs; // buffer with error messages DXUtil_FindMediaFileCb( strShaderPath, sizeof(strShaderPath), _T("VertexShader3.vsh") ); D3DXAssembleShaderFromFile( strPixelShaderPath, NULL, NULL, 0, &pCode, &pErrorMsgs, NULL ); m_pd3dDevice->CreateVertexShader((DWORD*) pCode->GetBufferPointer(), &m_pVertexShader) pCode->Release(); pErrorMsgs->Release();
Microsoft® Direct3D® 는, 이 파일을 찾아내면 정점 셰이더를 생성 해 셰이더 개체를 돌려준다. 이 샘플에서는, 셰이더를 생성 하도록(듯이) 수정한 셰이더 파일을 사용한다. 셰이더 명령을 나타내는 ASCII 텍스트 캐릭터 라인을 생성 하는 방법도 있다.
정점 셰이더 정수는, 다음과 같이 셰이더 파일의 밖에서 정의할 수 있다. 여기에서는, 뷰/투영 행렬, 디퓨즈 라이트의 색, RGBA, 및 라이트의 방향 벡터를 셰이더에 건네주기 위해서(때문에), 정수를 사용한다.
float constants[4] = {0, 0.5f, 1.0f, 2.0f}; m_pd3dDevice->SetVertexShaderConstantF( 0, (float*) &constants, 1 ); D3DXMATRIX mat; D3DXMatrixMultiply( &mat, &m_matView, &m_matProj ); D3DXMatrixTranspose( &mat, &mat ); m_pd3dDevice->SetVertexShaderConstantF( 4, (float*) &mat, 4 ); float color[4] = {1,1,1,1}; m_pd3dDevice->SetVertexShaderConstantF( 8, (float*) &color, 1 ); float lightDir[4] = {-1, 0,1,0}; // fatter slice m_pd3dDevice->SetVertexShaderConstantF( 12, (float*) &lightDir, 1 );
def 명령을 사용해, 셰이더내에서 정수를 정의할 수도 있다.
셰이더 명령을 쓰기, 정점 데이터를 적절한 정점 레지스터에 접속해, 정수를 초기화한 다음에, 출력을 렌더링 해야 한다. 렌더링 코드에서는, 정점 버퍼 데이터 스트림을 검색하는 장소를 Direct3D 에 알려 Direct3D 에 셰이더 핸들을 건네준다. 텍스처를 사용하기 위해(때문에), 텍스처 스테이지를 설정해 텍스처 데이터의 사용법을 Direct3D 에 알릴 필요가 있다.
// Identify the vertex buffer data source. m_pd3dDevice->SetStreamSource(0, m_pVB, sizeof(CUSTOMVERTEX_POS_NORM_COLOR1_TEX1)); // Identify the shader. m_pd3dDevice->SetVertexShader( m_pVertexShader ); // Define the texture stage(s) and set the texture(s) used m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); m_pd3dDevice->SetTexture( 0, m_pTexture0 ); // Draw the object. DWORD dwNumSphereVerts = 2 * m_dwNumSphereRings*(m_dwNumSphereSegments + 1); m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, dwNumSphereVerts - 2);
출력 이미지는 다음과 같이 된다.
텍스처 맵을 적용 하면, 구가 지구처럼 보인다. 조명에 의해, 지구의 표면에 명암의 그라데이션이 생긴다.