410 likes | 430 Views
Part 3 DirectX Graphics Core Programming. Chap 9. Shader Programming using High Level Shader Language DirectX9 에서부터 지원되는 HLSL 을 사용하여 Per-Pixel Lighting 을 구현 Chapter 10. Using Advanced Shader Effect Cube Environment Mapping Effect Realtime Shadowing Effect Chapter 11. X File
E N D
Part 3DirectX Graphics Core Programming Chap 9. Shader Programming using High Level Shader Language DirectX9에서부터 지원되는 HLSL을 사용하여 Per-Pixel Lighting을 구현 Chapter 10. Using Advanced Shader Effect Cube Environment Mapping Effect Realtime Shadowing Effect Chapter 11. X File X 파일에 저장된 기하 정보의 이용 Chapter 12. Handling *.md3 Files HLSL Shader와 *.md3 파일을 이용한 캐릭터 엔진 구현
Chapter 10Using Advanced Shader Effect 숙명여자대학교 이과대학 정보과학부 멀티미디어과학전공 조교수 이종우 bigrain@sookmyung.ac.kr
Contents • Cube Map을 만들고 호출하는 방법 • 동적인 굴절과 반사 매핑 처리 방법 • 그림자와 그림자 부피 효과 제 3 장 DirectX 9 Programming Conventions
Using Cube Map • Reflection Mapping • 빛이 반사된 표면을 처리하는 기법 반사 매핑, 환경 매핑 • 반사 표면을 처리하는 기법 • 방법 1 • 빛의 물리적 성질에 대한 모델링을 한 후 • 물체로부터 반사된 secondary light에 대한 ray tracing을 실시 • 방법 2 • 미리 만들어둔 주위 환경을 물체 표면에 입혀서 • 반사가 일어난 것 같은 효과를 내는 기법 • 여기서 “미리 만들어둔 주위 환경”을 큐브 환경 맵 또는 큐브 맵이라고 함 제 3 장 DirectX 9 Programming Conventions
Using Cube Map (계속) • Cube Map 생성하기 • 큐브 맵을 입힐 물체가 들어갈 자리에 물체 대신 카메라를 놓고 여섯 방향으로 렌더링을 하거나 사진을 찍는다. • 이 6장의 그림들은 시야각 90도의 정사각형 모양 그래야 큐브에 입혔을 때 이음매가 잘 연결될 것임! 제 3 장 DirectX 9 Programming Conventions
Using Cube Map (계속) • Cube Map 사용하기 • R = I – 2 * (I N) * N 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap • 환경 매핑을 이용하여 크롬 재질의 반짝거리는 주전자를 그리는 예 • VS가 각 정점에서의 시선 벡터와 반사 벡터를 계산 • VS가 이를 PS에게 전달 • PS는 이를 이용해 큐브 맵에서 데이터를 꺼내와 결과물로 내보냄 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • CD3DApplication클래스 class CMyD3DApplication : public CD3DApplication { D3DXMATRIXA16 m_matProject; D3DXMATRIXA16 m_matView; D3DXMATRIXA16 m_matWorld; CD3DFont* m_pFont; CD3DMesh* m_pSkyBox; ID3DXMesh* m_pD3DXMesh; // D3DX mesh to store teapot LPD3DXEFFECT m_pEffect; // VS, PS 코드 컴파일 결과로 받을 효과 클래스 인스턴스 LPDIRECT3DCUBETEXTURE9 m_pCubeMap; // 환경 맵을 위한 텍스쳐 클래스 인스턴스 D3DXVECTOR4 m_vEyePos; // 시선 위치와 시선 벡터 protected: HRESULT RenderSceneIntoEnvMap(); HRESULT RenderScene(CONST D3DXMATRIXA16* pView, CONST D3DXMATRIXA16* pProject, BOOL bRenderTeapot ); …… HRESULT LoadXFile(TCHAR*); public: LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); CMyD3DApplication(); }; 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • 생성자 & OneTimeSceneInit() CMyD3DApplication::CMyD3DApplication() { m_strWindowTitle = _T("CubeMap"); m_d3dEnumeration.AppUsesDepthBuffer = TRUE; m_dwCreationWidth = 800; // Width used to create window m_dwCreationHeight = 600; m_pFont = NULL; m_pD3DXMesh = NULL; m_pSkyBox = NULL; m_pEffect = NULL; m_pCubeMap = NULL; } HRESULT CMyD3DApplication::OneTimeSceneInit() { D3DXMatrixIdentity( &m_matWorld ); m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD ); m_pSkyBox = new CD3DMesh(); if(!m_pFont || !m_pSkyBox) return E_OUTOFMEMORY; return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • InitDeviceObjects() HRESULT CMyD3DApplication::InitDeviceObjects() { TCHAR strFile[160]; DXUtil_FindMediaFileCb(strFile, sizeof(strFile),_T("teapot.x")); LoadXFile(strFile); // m_pD3DXMesh for teapot model if (FAILED(m_pSkyBox->Create(m_pd3dDevice, _T("lobby_skybox.x")))) return D3DAPPERR_MEDIANOTFOUND; // Restore the device-dependent objects m_pFont->InitDeviceObjects( m_pd3dDevice ); HRESULT hr; if (FAILED(hr = D3DXCreateEffectFromFile(m_pd3dDevice, "hlsl.fx", NULL, NULL, D3DXSHADER_DEBUG, NULL, &m_pEffect, NULL))) return hr; return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • RestoreDeviceObjects() HRESULT CMyD3DApplication::RestoreDeviceObjects() { m_pSkyBox->RestoreDeviceObjects( m_pd3dDevice ); m_pFont->RestoreDeviceObjects(); if( m_pEffect != NULL ) m_pEffect->OnResetDevice(); //Do all the basic setup FLOAT fAspect = (FLOAT)m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height; D3DXMatrixPerspectiveFovLH(&m_matProject, D3DX_PI/3, fAspect, 0.5f, 100.0f); D3DXMatrixIdentity(&m_matWorld); TCHAR strFile[160]; DXUtil_FindMediaFileCb(strFile, sizeof(strFile),_T("LobbyCube.dds")); if (FAILED(D3DXCreateCubeTextureFromFile(m_pd3dDevice, strFile, &m_pCubeMap))) return S_FALSE; return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • FrameMove() HRESULT CMyD3DApplication::FrameMove() { // Set the eye position so that the eye orbits the object float Time = (float)GetTickCount() / 5000.0f; m_vEyePos = D3DXVECTOR4(3.0 * sin(Time), 0.0, 3.0 * cos(Time), 0.0f); // Make sure that the room isn't spinning... D3DXMatrixIdentity(&m_matWorld); // Set the view matrix based on the position above. D3DXMatrixLookAtLH(&m_matView, &(D3DXVECTOR3)m_vEyePos, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • Render() / RenderScene() HRESULT CMyD3DApplication::Render() { // Begin the scene if (SUCCEEDED(m_pd3dDevice->BeginScene())) { // Render the scene, including the teapot RenderScene(&m_matView, &m_matProject, TRUE); // Output statistics m_pFont->DrawText(2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats); m_pFont->DrawText(2,20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats); // End the scene. m_pd3dDevice->EndScene(); } return S_OK; } HRESULT CMyD3DApplication::RenderScene(CONST D3DXMATRIXA16 *pView, CONST D3DXMATRIXA16 *pProject, BOOL bRenderTeapot) { // Render the Skybox D3DXMATRIXA16 matWorld; D3DXMatrixScaling( &matWorld, 10.0f, 10.0f, 10.0f ); 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) • Render() / RenderScene()(계속) …… D3DXMATRIXA16 matView(*pView); matView._41 = matView._42 = matView._43 = 0.0f; m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, pProject ); // m_pd3dDevice->SetTexture(0, m_pCubeMap); m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); if ((m_d3dCaps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRROR) == D3DPTADDRESSCAPS_MIRROR ) { m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR); m_pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR); } // Always pass Z-test, so we can avoid clearing color and depth buffers m_pd3dDevice->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS ); m_pSkyBox->Render( m_pd3dDevice ); m_pd3dDevice->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL ); 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap (계속) // Render the environment-mapped ShinyTeapot if (bRenderTeapot) { // Rotate the object (just because we can...) D3DXMatrixRotationY(&m_matWorld, (float)GetTickCount() / 1000.0f); D3DXMATRIX mWorldViewProj; D3DXMatrixMultiply(&mWorldViewProj,&m_matWorld, pView); D3DXMatrixMultiply(&mWorldViewProj, &mWorldViewProj, pProject); m_pEffect->SetMatrix( "matWorldViewProj", &mWorldViewProj ); m_pEffect->SetMatrix( "matWorld", &m_matWorld); m_pEffect->SetMatrix( "matView", pView); m_pEffect->SetVector( "vecEye", &m_vEyePos); UINT nPasses, iPass; HRESULT hr; if (m_pEffect != NULL) { hr = m_pEffect->SetTexture("CubeMap", m_pCubeMap); m_pEffect->Begin( &nPasses, 0 ); for( iPass = 0; iPass < nPasses; iPass ++ ) { m_pEffect->Pass( iPass ); m_pD3DXMesh->DrawSubset( 0 ); } m_pEffect->End(); } } return S_OK; } 제 3 장 DirectX 9 Programming Conventions
PS() / VS()코드 Example : CubeMap (계속) float4x4 matWorldViewProj; float4x4 matWorld; float4x4 matView; float4 vecEye; texture CubeMap; samplerCUBE CubeMapSampler = sampler_state { Texture = <CubeMap>; MinFilter = Linear; MagFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; struct VS_OUTPUT { float4 Pos : POSITION; float3 Reflect: TEXCOORD4; }; 제 3 장 DirectX 9 Programming Conventions
PS() / VS()코드 Example : CubeMap (계속) VS_OUTPUT VS(float4 Pos : POSITION, float2 Tex : TEXCOORD, float3 Normal : NORMAL) { VS_OUTPUT Out = (VS_OUTPUT)0; Out.Pos = mul(Pos, matWorldViewProj); // transform Vertices float3 Norm = normalize(mul(Normal, matWorld)); // 법선 벡터 변환 // get a vector toward the camera/eye -> V // 시선 벡터 = 월드 공간에서의 정점 좌표 – 눈의 좌표 float3 PosWorld = normalize(mul(Pos, matWorld)); float3 Incident = normalize(PosWorld - vecEye); // Reflection Vector for cube map: R = I - 2*N * (I.N) Out.Reflect = normalize(reflect(Incident, Norm)); // Out.Reflect = normalize(Incident - 2 * Norm * dot(Incident, Norm)); return Out; } 제 3 장 DirectX 9 Programming Conventions
PS() / VS()코드 Example : CubeMap (계속) float4 PS(float3 Ref : TEXCOORD4) : COLOR { return texCUBE(CubeMapSampler, Ref); } technique Tshader { pass P0 { Sampler[2] = (CubeMapSampler); // compile shaders VertexShader = compile vs_1_1 VS(); PixelShader = compile ps_1_4 PS(); } } 제 3 장 DirectX 9 Programming Conventions
굴절과 반사가 있는 환경 매핑 • 환경 매핑에 굴절 효과 넣기 • 굴절(Refraction) • 서로 다른 매개체를 통과할 때 빛이 꺾이는 현상 • 면이 출렁이면 꺾이는 각도가 달라짐 • 방법 • 반사 계산식과 법선 벡터의 길이를 조작하여 근사적으로 계산 • 법선 벡터의 길이를 일부러 1보다 작은 값으로 줄여 벡터의 방향을 의도적으로 변경했음! • 법선 벡터 길이 0 : 굴절 벡터가 시선 벡터와 같아짐. • 법선 벡터가 길어질수록 굴절 벡터는 경계면 쪽으로 꺾이게 됨 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap2 • VS() / PS()코드 float4x4 matWorldViewProj; float4x4 matWorld; float4x4 matView; float4 vecEye; texture CubeMap; samplerCUBE CubeMapSampler = sampler_state { Texture = <CubeMap>; MinFilter = Linear; MagFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; struct VS_OUTPUT { float4 Pos : POSITION; float3 Reflect: TEXCOORD4; float3 Reflect2: TEXCOORD5; }; 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap2 (계속) • VS() / PS()코드 (계속) VS_OUTPUT VS(float4 Pos : POSITION, float2 Tex : TEXCOORD, float3 Normal : NORMAL) { VS_OUTPUT Out = (VS_OUTPUT)0; Out.Pos = mul(Pos, matWorldViewProj); // transform Position float3 Norm = normalize(mul(Normal, matWorld)); // get a vector toward the camera/eye -> V float3 PosWorld = normalize(mul(Pos, matWorld)); float3 Incident = normalize(PosWorld - vecEye); // Reflection Vector for cube map: R = I - 2*N * (I.N) Out.Reflect = normalize(reflect(Incident, Norm)); float3 ShortNorm = mul(Norm, 0.4); // 굴절 벡터를 구하기 위해 법선 벡터 크기를 줄임 // Reflection Vector for cube map: R = I - 2*N * (I.N) Out.Reflect2 = normalize(reflect(Incident, ShortNorm)); return Out; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap2 (계속) • VS() / PS()코드 (계속) float4 PS(float3 Ref : TEXCOORD4, float3 Ref2 : TEXCOORD5) : COLOR { float4 tex1 = texCUBE(CubeMapSampler, Ref); // 반사 벡터에서 한 번 float4 tex2 = texCUBE(CubeMapSampler, Ref2); // 굴절 벡터에서 한 번 return tex2 * 0.5 + tex1; // 굴절 성분의 밝기를 좀 줄임! } technique TShader { pass P0 { Sampler[2] = (CubeMapSampler); // compile shaders VertexShader = compile vs_1_1 VS(); PixelShader = compile ps_1_4 PS(); } } 제 3 장 DirectX 9 Programming Conventions
동적 굴절 & 동적 반사 환경 매핑 • 동적 큐브 맵 • 미리 만들어 놓은 큐브 맵이 아닌 매 프레임마다 새로 큐브 맵을 생성함. • 코딩 방법 • 주전자 주위를 날아다니는 비행기를 하나 띄우고, • 그 비행기의 모습이 주전자 표면에 반사되게 하여 확인 함! • 큐브 맵 동적 생성 방법 • 주전자는 제외한 채로 • 환경과 비행기가 날아가는 장면을 생성 • 생성된 화면 6개를 큐브 맵에 저장 • 다음 번 render()시에 이 큐브 맵을 사용 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 • CD3DApplication구조체 class CMyD3DApplication : public CD3DApplication { D3DXMATRIXA16 m_matProject; D3DXMATRIXA16 m_matView; D3DXMATRIXA16 m_matWorld; CD3DFont* m_pFont; CD3DMesh* m_pSkyBox; // 환경 매핑을 그리기 위한 프레임워크 CD3DMesh* m_pAirplane; // 동적 환경 매핑을 그리기 위한 프레임워크 D3DXMATRIXA16 m_matAirplane; // 비행기 변환을 위한 행렬 ID3DXMesh* m_pD3DXMesh; // 주전자를 그리기 위한 메쉬 구조체 LPD3DXEFFECT m_pEffect; // 셰이더 코드 컴파일 결과를 넘겨받을 효과 구조체 LPDIRECT3DCUBETEXTURE9 m_pCubeMap; ID3DXRenderToEnvMap* m_pRenderToEnvMap; // 동적 환경 매핑 저장 구조체 D3DXVECTOR4 m_vEyePos; // 시선 벡터 protected: HRESULT RenderSceneIntoEnvMap(); // 환경 장면 그리기 함수 HRESULT RenderScene(CONST D3DXMATRIXA16* pView, CONST D3DXMATRIXA16* pProject, BOOL bRenderTeapot); …… 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • OneTimeSceneInit() HRESULT CMyD3DApplication::OneTimeSceneInit() { D3DXMatrixIdentity( &m_matWorld ); m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD ); m_pSkyBox = new CD3DMesh(); m_pAirplane = new CD3DMesh(); if( !m_pFont || !m_pSkyBox || !m_pAirplane ) return E_OUTOFMEMORY; return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • InitDeviceObjects() HRESULT CMyD3DApplication::InitDeviceObjects() { TCHAR strFile[160]; DXUtil_FindMediaFileCb(strFile, sizeof(strFile),_T("teapot.x")); LoadXFile(strFile); if (FAILED(m_pSkyBox->Create(m_pd3dDevice, _T("lobby_skybox.x")))) return D3DAPPERR_MEDIANOTFOUND; if (FAILED(m_pAirplane->Create(m_pd3dDevice, _T("airplane 2.x")))) return D3DAPPERR_MEDIANOTFOUND; // Set mesh properties m_pAirplane->SetFVF(m_pd3dDevice, D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1); // Restore the device-dependent objects m_pFont->InitDeviceObjects( m_pd3dDevice ); HRESULT hr; if (FAILED(hr = D3DXCreateEffectFromFile(m_pd3dDevice, "hlsl.fx", NULL, NULL, 3DXSHADER_DEBUG, NULL, &m_pEffect, NULL))) return hr; return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • RestoreDeviceObjects() HRESULT CMyD3DApplication::RestoreDeviceObjects() { m_pSkyBox->RestoreDeviceObjects( m_pd3dDevice ); m_pFont->RestoreDeviceObjects(); m_pAirplane->RestoreDeviceObjects( m_pd3dDevice ); if( m_pEffect != NULL ) m_pEffect->OnResetDevice(); // Do all the basic setup FLOAT fAspect = (FLOAT)m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height; D3DXMatrixPerspectiveFovLH(&m_matProject, D3DX_PI/3, fAspect, 0.5f, 100.0f); D3DXMatrixIdentity(&m_matWorld); // Create RenderToEnvMap object if (FAILED(D3DXCreateRenderToEnvMap(m_pd3dDevice, CUBEMAP_RESOLUTION, 1, m_d3dsdBackBuffer.Format, TRUE, D3DFMT_D16, &m_pRenderToEnvMap))) { return E_FAIL; } ……… 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • RestoreDeviceObjects()(계속) ……… // Create the cubemap, with a format that matches the backbuffer if (m_d3dCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) { if (FAILED(D3DXCreateCubeTexture(m_pd3dDevice, CUBEMAP_RESOLUTION, 1, D3DUSAGE_RENDERTARGET, m_d3dsdBackBuffer.Format, D3DPOOL_DEFAULT, &m_pCubeMap))) { if (FAILED(D3DXCreateCubeTexture(m_pd3dDevice, CUBEMAP_RESOLUTION, 1, 0, m_d3dsdBackBuffer.Format, D3DPOOL_DEFAULT, &m_pCubeMap))) { m_pCubeMap = NULL; } } } return S_OK; } 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • FrameMove() HRESULT CMyD3DApplication::FrameMove() { // Animate file object D3DXMATRIXA16 mat; D3DXMatrixScaling( &m_matAirplane, 0.2f, 0.2f, 0.2f ); D3DXMatrixTranslation( &mat, 0.0f, 2.0f, 0.0f ); D3DXMatrixMultiply( &m_matAirplane, &m_matAirplane, &mat ); D3DXMatrixRotationX( &mat, -2.9f * m_fTime ); D3DXMatrixMultiply( &m_matAirplane, &m_matAirplane, &mat ); D3DXMatrixRotationY( &mat, 1.055f * m_fTime ); D3DXMatrixMultiply( &m_matAirplane, &m_matAirplane, &mat ); // Set the eye position so that the eye orbits the object float Time = (float)GetTickCount() / 5000.0f; m_vEyePos = D3DXVECTOR4(3.0f * sin(Time), 0.0f, 3.0f * cos(Time), 0.0f); // Make sure that the room isn't spinning... D3DXMatrixIdentity(&m_matWorld); ……… 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • FrameMove()(계속) • RenderSceneIntoEnvMap() ……… // Set the view matrix based on the position above. D3DXMatrixLookAtLH(&m_matView, &(D3DXVECTOR3)m_vEyePos, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); // Render the scene into the surfaces of the cubemap if (FAILED(RenderSceneIntoEnvMap())) return E_FAIL; return S_OK; } HRESULT CMyD3DApplication::RenderSceneIntoEnvMap() { HRESULT hr; // Set the projection matrix for a field of view of 90 degrees D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI*0.5f, 1.0f, 0.5f, 1000.0f); ……… 제 3 장 DirectX 9 Programming Conventions
Example : CubeMap3 (계속) • RenderSceneIntoEnvMap()(계속) ……… // 큐브 맵 뷰 벡터를 생성(여기서는 현재의 큐 벡터를 사용) D3DXMATRIXA16 matViewDir( m_matView ); matViewDir._41 = 0.0f; matViewDir._42 = 0.0f; matViewDir._43 = 0.0f; // 환경 맵의 6개 방향 장면을 그리기 시작 if (m_pCubeMap) hr = m_pRenderToEnvMap->BeginCube( m_pCubeMap ); if (FAILED(hr)) return hr; for (UINT i = 0; i < 6; i++) { m_pRenderToEnvMap->Face((D3DCUBEMAP_FACES)i, 0); // 면을 지정 // 현재 지정된 환경 큐브 맵 표면에 대해 뷰 변환을 실시 D3DXMATRIXA16 matView; matView = D3DUtil_GetCubeMapViewMatrix( (D3DCUBEMAP_FACES) i ); D3DXMatrixMultiply( &matView, &matViewDir, &matView ); // 장면을 그린다.(주전자는 그리지 않는다.) RenderScene( &matView, &matProj, FALSE ); } m_pRenderToEnvMap->End(0); // 환경 맵에 6개 장면 그리기가 끝났음을 알림! return S_OK; } 제 3 장 DirectX 9 Programming Conventions
동적 굴절 반사 & Bump 매핑 • 범프 매핑과 굴절&반사 매핑을 결합 제 3 장 DirectX 9 Programming Conventions
그림자 생성하기 • 그림자 • 실감나는 영상 효과 • 물체가 놓여 있는 위치에 대한 확실한 공간감을 제공 • 그림자 생성 요소 • 광원(light source) / 그림자 유발 물체(occluder) / 그림자가 드리워질 면(receiver) • DX3D의 그림자 생성 기법 • Stencil Buffer 이용한 그림자 볼륨 기술을 제공 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume • DirectX9에서 제공하는 Two-sided Stencil Buffer 사용 • Shadow Volume • 빛이 차단되는 부분을 어떻게 알아낼 것인가? • 빛 방향에서 바라본 물체의 실루엣 외곽선을 찾아내야 함! • 실루엣 외곽선 : 광원을 바라보고 있는 면과 그렇지 않은 면의 경계를 의미! • 메쉬 구조에서 실루엣 외곽선을 추출하는 PreProcessing과정을 거친 후 그림자를 그림! 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume (계속) • Silhouette Outline 추출하기 • 면 사이의 경계선에 “degenerate quad”들을 삽입한다. • degenerate quad • 면 사이의 경계선을 없애고 그 자리에 끼어 들어가는 형태 • 이 사각형의 양쪽 변은 좌표가 같음. • 그러나 양 변의 법선 벡터는 두 경계선의 법선 벡터로 구성 • by 타카시 이마기레 (http://www.t-pot.com) 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume (계속) • 실루엣 외곽선 추출하기(degenerate quad 삽입) HRESULT CShadowVolume::Create(LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXMESH pSrcMesh) { HRESULT ret = S_OK; struct MESHVERTEX { D3DXVECTOR3 p, n; }; SHADOW_VOLUME_VERTEX *pVertices; WORD *pIndices; DWORD i, j, k, l, face; LPD3DXMESH pMesh; if (FAILED(pSrcMesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM, D3DFVF_XYZ|D3DFVF_NORMAL, pd3dDevice, &pMesh))) return E_FAIL; DWORD dwNumFaces = pMesh->GetNumFaces(); m_dwNumFaces = 4*dwNumFaces; // 면 개수의 4배 만큼 m_pVertices = new SHADOW_VOLUME_VERTEX[3*m_dwNumFaces]; // 정점 개수의 3배 만큼 pMesh->LockVertexBuffer(0L, (LPVOID*)&pVertices ); // 원본 정점 버퍼 포인터 pMesh->LockIndexBuffer (0L, (LPVOID*)&pIndices ); // 원본 인덱스 버퍼 포인터 D3DXVECTOR3 *vNormal = new D3DXVECTOR3[dwNumFaces];// 법선 벡터 저장 공간 할당 if (NULL == vNormal) { // 메모리 부족 시 에러 처리 m_dwNumFaces = 0; ret = E_OUTOFMEMORY; goto end; } 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume (계속) • 실루엣 외곽선 추출하기(degenerate quad 삽입)(계속) ……… // 모든 면에 대해 면 법선 벡터를 계산한다. for (i = 0; i < dwNumFaces; i++) { D3DXVECTOR3 v0 = pVertices[pIndices[3*i+0]].p; D3DXVECTOR3 v1 = pVertices[pIndices[3*i+1]].p; D3DXVECTOR3 v2 = pVertices[pIndices[3*i+2]].p; // 면 법선 벡터를 계산 D3DXVECTOR3 vCross1(v1-v0); D3DXVECTOR3 vCross2(v2-v1); D3DXVec3Cross( &vNormal[i], &vCross1, &vCross2 ); // store a face m_pVertices[3*i+0].p = v0; m_pVertices[3*i+1].p = v1; m_pVertices[3*i+2].p = v2; m_pVertices[3*i+0].n = vNormal[i]; m_pVertices[3*i+1].n = vNormal[i]; m_pVertices[3*i+2].n = vNormal[i]; } ……… 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume (계속) • 실루엣 외곽선 추출하기(degenerate quad 삽입)(계속) ……… // 각 면의 세 변에 대해서 face = dwNumFaces; for ( i=0; i<dwNumFaces; i++ ) { for( j=i+1; j<dwNumFaces; j++ ) { DWORD id[2][2]; // checklist DWORD cnt=0; for (k=0; k < 3; k++) { for (l=0; l < 3; l++) { D3DXVECTOR3 dv; D3DXVec3Subtract( &dv, &pVertices[pIndices[3*i+k]].p, &pVertices[pIndices[3*j+l]].p); // 서로 다른 두 면에 있는 두 정점들이 하나의 변을 형성하면 변 공유이므로 // checklist에 넣고 counter를 1 증가 시킨다. if ( D3DXVec3LengthSq( &dv ) < 0.001f ) { // cnt counts until two? 정점 2개를 공유하면 변을 공유하는 것임! id[cnt][0] = 3*i+k; id[cnt][1] = 3*j+l; cnt++; } } } ……… 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume (계속) • 실루엣 외곽선 추출하기(degenerate quad 삽입)(계속) ……… // if two times two vertices from two faces share one edge ? if (2 == cnt) { // if one face has a different direction than the other face ? if (id[1][0]-id[0][0]!=1) { // adjust direction of face DWORD tmp = id[0][0]; id[0][0] = id[1][0]; id[1][0] = tmp; // swap id[0][0] and id[1][0] tmp = id[0][1]; id[0][1] = id[1][1]; id[1][1] = tmp; // swap id[0][1] and id[1][1] } // insert degenerated quadrilateral // the face normals are used for the vertex normals m_pVertices[3*face+0].p = pVertices[pIndices[id[1][0]]].p; m_pVertices[3*face+2].p = pVertices[pIndices[id[0][1]]].p; m_pVertices[3*face+1].p = pVertices[pIndices[id[0][0]]].p; m_pVertices[3*face+0].n = vNormal[i]; m_pVertices[3*face+2].n = vNormal[j]; m_pVertices[3*face+1].n = vNormal[i]; face++; ……… 제 3 장 DirectX 9 Programming Conventions
예제 : Shadow Volume (계속) • 실루엣 외곽선 추출하기(degenerate quad 삽입)(계속) ……… m_pVertices[3*face+0].p = pVertices[pIndices[id[1][0]]].p; m_pVertices[3*face+2].p = pVertices[pIndices[id[1][1]]].p; m_pVertices[3*face+1].p = pVertices[pIndices[id[0][1]]].p; m_pVertices[3*face+0].n = vNormal[i]; m_pVertices[3*face+2].n = vNormal[j]; m_pVertices[3*face+1].n = vNormal[j]; face++; } } } assert(face == m_dwNumFaces); delete[] vNormal; end: // unlock buffers pMesh->UnlockVertexBuffer(); pMesh->UnlockIndexBuffer(); pMesh->Release(); return ret; } 제 3 장 DirectX 9 Programming Conventions