Tutorial4- 조명(Light)-광원,재질
- 프로그래밍/3D그래픽스 & 쉐이더
- 2011. 3. 29. 21:52
조명을 사용하면 보다 깨끗하고 선명한 화질과 뛰어난 연출감을 얻을 수 있다.
이러한 조명을 사용하기 위해서는 광원, 재질을 생성해야한다. 또한 기하정보에 노멀벡터정보를 포함하고 있어야만 한다. 광원은 위치,색깔,방향등의 정보를 바탕으로 생성된다. (여기서 벡터의 개념을 잠시 다시 생각해보자)
소스를 보자.
/// 광원을 사용하기때문에 노멀벡터가 있어야 한다는 사실을 명심하자.
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; /// 정점의 3차원 좌표
D3DXVECTOR3 normal; /// 정점의 노멀 벡터
};
/// 사용자 정점 구조체에 관한 정보를 나타내는 FVF값
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
// 위는 정점 구조체를 정의한 것이다.
// 여기서 기존에 봐왔던 점과 다른 점이라면 nomal이라는 정점의 노멀 법선 벡터를 선언했다는 것이다.
HRESULT InitD3D( HWND hWnd )
{
// 디바이스를 생성하기위한 D3D객체 생성
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// 디바이스를 생성할 구조체
// 복잡한 오브젝트를 그릴것이기때문에, 이번에는 Z버퍼가 필요하다.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// 애플리케이션의 깊이 버퍼를 관리하도록 Direct3D 에 지시한다.
d3dpp.EnableAutoDepthStencil = TRUE;
// 유효한 깊이 버퍼 포맷으로 설정. D3DFMT_D16 플래그는, 16 비트의 깊이 버퍼 사용 지정
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// 디바이스 생성
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
// 컬링기능을 끈다. ( Z버퍼를 위해 컬링기능을 꺼준다. Z버퍼에 깊이를 저장해주기위해 )
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Z버퍼기능을 켠다.
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
return S_OK;
}
VOID SetupLights()
{
// 재질(material)설정
// 재질은 디바이스에 단 하나만 설정될 수 있다.
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial( &mtrl );
// 광원 설정
D3DXVECTOR3 vecDir; // 방향성 광원(directional light)이 향할 빛의 방향
D3DLIGHT9 light; // 광원 구조체
ZeroMemory( &light, sizeof(D3DLIGHT9) ); // 구조체를 0으로 지운다.
light.Type = D3DLIGHT_DIRECTIONAL; // 광원의 종류셋팅(점 광원,방향성 광원,스포트라이트)
light.Diffuse.r = 1.0f; // 광원의 색깔과 밝기
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
vecDir = D3DXVECTOR3(cosf(timeGetTime()/350.0f), // 광원의 방향
1.0f,
sinf(timeGetTime()/350.0f) );
// 광원의 방향을 단위벡터로 만든다.
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
light.Range = 1000.0f; // 광원이 다다를수 있는 최대거리
g_pd3dDevice->SetLight( 0, &light ); // 디바이스에 0번 광원 설치
g_pd3dDevice->LightEnable( 0, TRUE ); // 0번 광원을 켠다
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); // 광원설정을 켠다
// 환경광원(ambient light)의 값 설정
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );
}
=>>>> 전체적인 설명 <<<<=
이 함수에서 중요한것은
1. D3DLIGHT9 구조체에 값을 넣는다
2. SetLight()를 통해 광원을 설치한다.
3. LightEnable()함수로 광원을 켜준다.
4. D3D가 관원 연산을 하도록 전체 메인 스위치도 SetRenderState(D3DRS_LIGHTING, TRUE) 함수도 켜주어야 한다.
InitGeometry()에서 이제까지 그렸던 삼각형에서 벗어야 좀더 복잡한 원통을 생성해보도록 하자.
HRESULT InitGeometry()
{
// 정점버퍼 생성
if( FAILED( g_pd3dDevice->CreateVertexBuffer(
50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
{
return E_FAIL;
}
// 알고리즘을 사용해서 실린더(위 아래가 터진 원통)를 만든다.
CUSTOMVERTEX* pVertices;
if( FAILED( g_pVB->Lock( 0, 0, (void**)&pVertices, 0 ) ) )
return E_FAIL;
//버택스버퍼 셋팅
for( DWORD i=0; i<50; i++ )
{
FLOAT theta = (2*D3DX_PI*i)/(50-1);
pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f,
cosf(theta) ); // 실린더의 아래쪽 원통의 좌표
pVertices[2*i+0].normal = D3DXVECTOR3( sinf(theta), 0.0f,
cosf(theta) ); // 실린더의 아래쪽 원통의 노멀
pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f,
cosf(theta) ); // 실린더의 위쪽 원통의 좌표
pVertices[2*i+1].normal = D3DXVECTOR3( sinf(theta), 0.0f,
cosf(theta) ); // 실린더의 위쪽 원통의 노멀
}
g_pVB->Unlock();
return S_OK;
}
이 함수에서는 삼각함수를 사용하여 아래쪽 원의 정점과 위쪽 원의 정점을 만들고 이를 나중에 Render()함수에서 DrawPrimitive()호출시에 D3DPT_TRIANGLESTRIP으로 연결해주고 있다.
재질은 DrarPrimitive()호출 시에 단 하나밖에 지정할 수 없으므로, 만약 메시가 여러개의 재질로 이루어져 있다면 메시를 재질별로 분리해야함.
색이 칠해지기 전의 라인을 보려면 Render()함수의 g_pd3dDevice->EndScene(); 코드 전에
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);을 추가하여 빌드해보면 와이프레임으로 라인이 그려진 모습을 확인 할 수 있다.
[출처] Lights - 소스분석|작성자 누리블루
ㅇ
ㅁㄴㅇㅁㄴㅇㅁㄴㅇㅁㄴㅇㅁㄴㅇㅁㄴㅇ
이 글을 공유하기