Tutorial4- 조명(Light)-광원,재질






조명을 사용하면 보다 깨끗하고 선명한 화질과 뛰어난 연출감을 얻을 수 있다. 
이러한 조명을 사용하기 위해서는 광원, 재질을 생성해야한다. 또한 기하정보에 노멀벡터정보를 포함하고 있어야만 한다. 광원은 위치,색깔,방향등의 정보를 바탕으로 생성된다. (여기서 벡터의 개념을 잠시 다시 생각해보자)
소스를 보자. 



  

 


/// 광원을 사용하기때문에 노멀벡터가 있어야 한다는 사실을 명심하자.

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);을 추가하여 빌드해보면 와이프레임으로 라인이 그려진 모습을 확인 할 수 있다.



 

이 글을 공유하기

댓글

Designed by JB FACTORY