Transcript Shader
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
X 파일에 저장된 기하 정보의 이용
Chapter 12. Handling *.md3 Files
HLSL Shader와 *.md3 파일을 이용한 캐릭터 엔진 구현
Chapter 10
Using Advanced Shader Effect
숙명여자대학교 이과대학
정보과학부 멀티미디어과학전공
조교수 이종우
[email protected]
Contents
• Cube Map을 만들고 호출하는 방법
• 동적인 굴절과 반사 매핑 처리 방법
• 그림자와 그림자 부피 효과
제 3 장 DirectX 9 Programming Conventions
3
Using Cube Map
• Reflection Mapping
– 빛이 반사된 표면을 처리하는 기법 반사 매핑, 환경 매핑
• 반사 표면을 처리하는 기법
– 방법 1
• 빛의 물리적 성질에 대한 모델링을 한 후
• 물체로부터 반사된 secondary light에 대한 ray tracing을 실시
– 방법 2
• 미리 만들어둔 주위 환경을 물체 표면에 입혀서
• 반사가 일어난 것 같은 효과를 내는 기법
• 여기서 “미리 만들어둔 주위 환경”을 큐브 환경 맵 또는 큐브 맵이라고
함
제 3 장 DirectX 9 Programming Conventions
4
Using Cube Map (계속)
• Cube Map 생성하기
– 큐브 맵을 입힐 물체가 들어갈 자리에 물체 대신 카메라를 놓고
여섯 방향으로 렌더링을 하거나 사진을 찍는다.
– 이 6장의 그림들은 시야각 90도의 정사각형 모양 그래야 큐브
에 입혔을 때 이음매가 잘 연결될 것임!
제 3 장 DirectX 9 Programming Conventions
5
Using Cube Map (계속)
• Cube Map 사용하기
– R = I – 2 * (I N) * N
제 3 장 DirectX 9 Programming Conventions
6
Example : CubeMap
• 환경 매핑을 이용하여 크롬 재질의 반짝거리는 주전자를
그리는 예
– VS가 각 정점에서의 시선 벡터와 반사 벡터를 계산
– VS가 이를 PS에게 전달
– PS는 이를 이용해 큐브 맵에서 데이터를 꺼내와 결과물로 내보냄
제 3 장 DirectX 9 Programming Conventions
7
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
8
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
9
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
10
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
11
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
12
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
13
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
14
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
15
Example : CubeMap (계속)
• PS() / VS() 코드
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
16
Example : CubeMap (계속)
• PS() / VS() 코드
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
// 시선
float3
float3
a vector toward the camera/eye
벡터 = 월드 공간에서의 정점 좌표 –
PosWorld = normalize(mul(Pos,
Incident = normalize(PosWorld
-> V
눈의 좌표
matWorld));
- 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
17
Example : CubeMap (계속)
• PS() / VS() 코드
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
18
굴절과 반사가 있는 환경 매핑
• 환경 매핑에 굴절 효과 넣기
– 굴절(Refraction)
• 서로 다른 매개체를 통과할 때 빛
이 꺾이는 현상
• 면이 출렁이면 꺾이는 각도가 달
라짐
– 방법
• 반사 계산식과 법선 벡터의 길이
를 조작하여 근사적으로 계산
• 법선 벡터의 길이를 일부러 1보다
작은 값으로 줄여 벡터의 방향을
의도적으로 변경했음!
• 법선 벡터 길이 0 : 굴절 벡터가 시
선 벡터와 같아짐.
• 법선 벡터가 길어질수록 굴절 벡
터는 경계면 쪽으로 꺾이게 됨
제 3 장 DirectX 9 Programming Conventions
19
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
20
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
21
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
22
동적 굴절 & 동적 반사 환경 매핑
• 동적 큐브 맵
– 미리 만들어 놓은 큐브 맵이 아닌 매
프레임마다 새로 큐브 맵을 생성함.
– 코딩 방법
• 주전자 주위를 날아다니는 비행기를
하나 띄우고,
• 그 비행기의 모습이 주전자 표면에
반사되게 하여 확인 함!
– 큐브 맵 동적 생성 방법
• 주전자는 제외한 채로
• 환경과 비행기가 날아가는 장면을
생성
• 생성된 화면 6개를 큐브 맵에 저장
• 다음 번 render() 시에 이 큐브 맵
을 사용
제 3 장 DirectX 9 Programming Conventions
23
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
24
Example : CubeMap3 (계속)
• OneTimeSceneInit()
HRESULT CMyD3DApplication::OneTimeSceneInit()
{
D3DXMatrixIdentity( &m_matWorld );
m_pFont
m_pSkyBox
m_pAirplane
= new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
= new CD3DMesh();
= new CD3DMesh();
if( !m_pFont || !m_pSkyBox || !m_pAirplane )
return E_OUTOFMEMORY;
return S_OK;
}
제 3 장 DirectX 9 Programming Conventions
25
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
26
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
27
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
28
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,
D3DXMatrixRotationX( &mat, -2.9f * m_fTime );
D3DXMatrixMultiply( &m_matAirplane, &m_matAirplane,
D3DXMatrixRotationY( &mat, 1.055f * m_fTime );
D3DXMatrixMultiply( &m_matAirplane, &m_matAirplane,
);
&mat );
&mat );
&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
29
Example : CubeMap3 (계속)
• FrameMove()(계속)
………
// 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;
}
• RenderSceneIntoEnvMap()
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
30
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
31
동적 굴절 반사 & Bump 매핑
• 범프 매핑과 굴절&반사 매핑을 결합
제 3 장 DirectX 9 Programming Conventions
32
그림자 생성하기
• 그림자
– 실감나는 영상 효과
– 물체가 놓여 있는 위치에 대한 확실한 공간감을 제공
• 그림자 생성 요소
– 광원(light source) / 그림자 유발 물체(occluder) / 그림자가 드리
워질 면(receiver)
• DX3D의 그림자 생성 기법
– Stencil Buffer 이용한 그림자 볼
륨 기술을 제공
제 3 장 DirectX 9 Programming Conventions
33
예제 : Shadow Volume
• DirectX9에서 제공하는
Two-sided Stencil Buffer
사용
• Shadow Volume
– 빛이 차단되는 부분을 어떻게
알아낼 것인가?
– 빛 방향에서 바라본 물체의 실
루엣 외곽선을 찾아내야 함!
– 실루엣 외곽선 : 광원을 바라
보고 있는 면과 그렇지 않은
면의 경계를 의미!
– 메쉬 구조에서 실루엣 외곽선
을 추출하는 PreProcessing
과정을 거친 후 그림자를 그림!
제 3 장 DirectX 9 Programming Conventions
34
예제 : Shadow Volume (계속)
• Silhouette Outline 추출하기
– 면 사이의 경계선에 “degenerate quad”들을 삽입한다.
– degenerate quad
• 면 사이의 경계선을 없애고 그 자리에 끼어 들어가는 형태
• 이 사각형의 양쪽 변은 좌표가 같음.
• 그러나 양 변의 법선 벡터는 두 경계선의 법선 벡터로 구성
• by 타카시 이마기레 (http://www.t-pot.com)
제 3 장 DirectX 9 Programming Conventions
35
예제 : 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;
m_pVertices = new SHADOW_VOLUME_VERTEX[3*m_dwNumFaces];
// 면 개수의 4배 만큼
// 정점 개수의 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
36
예제 : Shadow Volume (계속)
• 실루엣 외곽선 추출하기(degenerate quad 삽입)(계속)
………
// 모든 면에 대해
for (i = 0; i <
D3DXVECTOR3
D3DXVECTOR3
D3DXVECTOR3
면 법선 벡터를 계산한다.
dwNumFaces; i++) {
v0 = pVertices[pIndices[3*i+0]].p;
v1 = pVertices[pIndices[3*i+1]].p;
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
m_pVertices[3*i+1].p
m_pVertices[3*i+2].p
m_pVertices[3*i+0].n
m_pVertices[3*i+1].n
m_pVertices[3*i+2].n
=
=
=
=
=
=
v0;
v1;
v2;
vNormal[i];
vNormal[i];
vNormal[i];
}
………
제 3 장 DirectX 9 Programming Conventions
37
예제 : 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
38
예제 : 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
39
예제 : Shadow Volume (계속)
• 실루엣 외곽선 추출하기(degenerate quad 삽입)(계속)
………
m_pVertices[3*face+0].p
m_pVertices[3*face+2].p
m_pVertices[3*face+1].p
m_pVertices[3*face+0].n
m_pVertices[3*face+2].n
m_pVertices[3*face+1].n
face++;
=
=
=
=
=
=
pVertices[pIndices[id[1][0]]].p;
pVertices[pIndices[id[1][1]]].p;
pVertices[pIndices[id[0][1]]].p;
vNormal[i];
vNormal[j];
vNormal[j];
}
}
}
assert(face == m_dwNumFaces);
delete[] vNormal;
end:
// unlock buffers
pMesh->UnlockVertexBuffer();
pMesh->UnlockIndexBuffer();
pMesh->Release();
return ret;
}
제 3 장 DirectX 9 Programming Conventions
40