카테고리 Archives: 학습

[DX9] 4.라이트의 작성과 사용 2 – 매터리얼과 라이트 설정

Direct3D 에서 라이팅을 사용하려면 1개 또는 여러개의 라이트를 작성해야합니다. 어떤 색이 지오메트리 오브젝트를 조사할 것인가를 결정하려면 지오메트리 오브젝트를 렌더링할 매터리얼을 작성할 필요가 있습니다. 신을 렌더링하기 전에 Lights 샘플 오브젝트는 1개의 매터리얼과 1개의 디렉셔널 라이트를 설정하는 애플리케이션 정의 함수인 SetupLights 를 호출합니다.

매터리얼 작성

매터리얼은 라이트가 조사될 때에 지오메트리 오브젝트의 서피스에 반사할 색을 정의합니다. 다음 코드는 D3DMATERIAL9  구조체를 사용해 황색의 매터리얼을 작성합니다.

D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(mtrl) );
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 );

매터리얼의 디퓨즈 색과 앰비엔트 색이 황색으로 설정됩니다. IDirect3DDevice9::SetMaterial 메소드를 호출해서 매터리얼을 신의 렌더링에 사용되는 Direct3D 디바이스에 적용합니다. IDirect3DDevice9::SetMaterial 가 받아들이는 유일한 파라메터는 설정된 매터리얼의 어드레스 입니다. 이 호출이 행해진 뒤 다른 매터리얼을 지정하는 IDirect3DDevice9::SetMaterial 가 호출될 때까지 이 매터리얼을 사용해 모든 프리머티브가 렌더링 됩니다.

이것으로 매터리얼이 신에 적용되었습니다. 다음으로 라이트를 작성합니다.

라이트 작성

Direct3D 에서 사용할 수 있는 라이트에는 다음 3종류가 있습니다.

  • 화이트 라이트
  • 디렉셔널 라이트
  • 스팟 라이트

샘플 코드에서는 한쪽 방향으로 라이트를 조사하는 디렉셔널 라이트를 작성합니다. 또, 코드를 사용해 라이트의 방향을 좌우로 움직입니다.

다음 코드는 D3DLIGHT9 구조체를 사용해 디렉셔널 라이트를 작성합니다.

D3DXVECTOR3 vecDir;
D3DLight9 light;
ZeroMemory( &light, sizeof(light) );
light.Type = D3DLIGHT_DIRECTIONAL;

다음 코드는 이 라이트의 디퓨즈 색을 흰색으로 설정합니다.

light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;

다음 코드는 라이트의 방향을 원형으로 회전시킵니다.

vecDir = D3DXVECTOR3(cosf(timeGetTime()/360.0f),
                     0.0f,
                     sinf(timeGetTime()/360.0f) );
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );

D3DXVec3Normalize 을 호출해서 라이트의 방향을 결정하려고 사용되는 방향 백터를 정규화합니다.

범위로는 Direct3D 에 라이트의 이펙트가 미치는 범위를 지정합니다. 이 멤버는 디렉셔널 라이트에는 영향주지 않습니다. 다음 코드는 이 라이트에 1000단위의 범위를 할당합니다.

light.Range = 1000.0f;

다음 코드는 IDirect3DDevice9::SetLight 를 호출해 Direct3D 디바이스에 라이트를 할당합니다.

g_pd3dDevice->SetLight( 0, &light );

IDirect3DDevice9::SetLight 가 받아들인 최초의 파라메터는 라이트가 할당된 인덱스 입니다. 이미 라이트가 그 장소에 있는 경우는 새로운 라이트로 덮어씁니다. 2번째의 파라메터는 라이트를 정의하는 구조체로의 포인터입니다. Lights 샘플프로젝트는 이 라이트를 인덱스 0으로 둡니다.

다음 코드는 IDirect3DDevice9::LightEnable 를 호출해 라이트를 유효화 합니다.

g_pd3dDevice->LightEnable( 0, TRUE);

IDirect3DDevice9::LightEnable 가 받아들이는 최초의 파라메터는 유효하 라이트의 인덱스입니다. 부울 값인 두번째 파라메터는 라이트를 온(TRUE)할지 오프(FALSE)할지 결정합니다. 위 샘플 코드에서는 인덱스 0인 라이트는 온으로 되어있습니다.

다음 코드는 IDirect3DDevice9::SetRenderState 를 호출해 Direct3D 에 라이트를 렌더링 시킵니다.

g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );

IDirect3DDevice9::SetRenderState 가 받아들이는 최초 두개의 파라메터는 변경할 디바이스 스테이트 변수와 그것에 설정할 값입니다. 이 코드 샘플은 D3DRS_LIGHTING 디바이스 변수를 TRUE 로 설정합니다. 이것에는 라이트의 렌더링을 유효화 하는 이펙트가 있습니니다.

이 코드 샘플의 마지막 순서는 다시 IDirect3DDevice9::SetRenderState 를 호출해 앰비언트 라이팅을 온으로 합니다.

g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );

위의 코드에서는 D3DRS_AMBIENT 디바이스 변수는 라이트 그레이 (0x00202020) 로 설정되어있습니다. 앰비언트 라이팅은 지정된 색으로 모든 오브젝트를 비춥니다.

라이팅과 매터리얼에 대해 자세한 것은「라이팅과 매터리얼 (Direct3D 9)」을 참조해 주세요.

이 튜토리얼에서는 라이팅과 매터리얼을 사용하는 방법을 나타냈습니다.「튜토리얼 5:텍스쳐 맵의 사용」에서 텍스쳐를 서페이스에 추가하는 방법을 다룹니다.

[DX9] 4.라이트의 작성과 사용 1 – 신 지오메트리 초기화

Direct3D 라이트로 3D 오브젝트가 보다 리얼하게 보일 수 있게 되었습니다. 신의 각 지오메트리 오브젝트는 사용된 장소와 라이트의 종류를 베이스로 해서 라이트가 조사됩니다. 이 튜토리얼의 샘플 코드에서는 라이트와 매터리얼에 대해서 설명합니다.

[DX9] 4.라이트의 작성과 사용 1 – 신 지오메트리 초기화

라이트를 사용하는 요건의 하나로 각 서피스에 법선이 포함되도록 할 필요가 있습니다. Lights 샘플 프로젝트에서는 새로운 커스텀 정점 타입을 사용합니다. 새로운 커스텀 정점형식에는 3D 위치와 서피스 법선을 포함합니다. 서피스 법선은 내부에서 Direct3D가 라이트의 계산을 하는데 사용됩니다.

struct CUSTOMVERTEX
{
    D3DXVECTOR3 position; // The 3D position for the vertex.
    D3DXVECTOR3 normal;   // The surface normal for the vertex.
};
// Custom flexible vertex format (FVF).
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)

이것으로 바른 벡터 형식이 정의 되었습니다. Light 샘플 프로젝트에서는 원기둥을 작성하는 애플리케이션 정의 함수인 InitGeometry 를 호출합니다. 처음에는 원기둥의 포인트를 격남한 정점 버퍼를 작성합니다. 다음 샘플 코드에 그것을 표시했습니다.

// Create the vertex buffer.
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),
                                           0 /*Usage*/, 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) );
}

http://ko.wikipedia.org/wiki/%EC%82%BC%EA%B0%81%ED%95%A8%EC%88%98

앞의 샘플코드를 사용해 정점 버퍼를 원기둥의 정점으로 묻으면 정점 버퍼는 렌더링 할 수 있게 됩니다.
다만, 이 신의 매터리얼과 라이트는 원기둥을 렌더링하기 전에 미리 설정해둘 필요가 있습니다.
이것에 대해서는「2 - 매터리얼과 라이트 설정」에서 설명합니다.