본문 바로가기

Programming/DirectX

색상 입히기

다이렉트x 색상 함수로는 DWORD로 정의된 D3DCOLOR가 있다.

D3DCOLOR은 네개의 8bit 로 나누어 각각의 8bit당 색상의 진하기를 저장한다.

( 알파값 | 빨강값 | 초록값 | 파랑값 ) 으로 구성되어진다.


D3DXCOLOR_ARGB( 255, 255, 0, 0 ); // A R G B

D3DXCOLOR_XRGB( 255, 0, 0 ); // 알파값을 넣을 필요 없다.


이는 16진수로 간단히 표현할 수 있는데 다음과 같이 설정할 수 있다.

0x ff ff ff ff 첫번째 0x는 16진수를 뜻한다. 

첫번째 ff는 알파값, 두번째 ff는 빨강값, 두번째 ff는 초록값, 세번째 ff는 파랑값을 뜻한다.

즉 ARGB이다. 색상별 표현은 아래와 같다.

0xffff0000    =    빨강

0xff00ff00    =    초록

0xff0000ff    =    파랑


이전에 만들었던 소스의 MY_FVF define에 D3DFVF_DIFFUSE를 추가해준다.
#define	MY_FVF D3DFVF_XYZ | D3DFVF_DIFFUSE

D3DFVF_DIFFUSE    분산색상요소를 포함하는 버텍스 포맷


쉐이드모드 설정 ( 쉐이더 코드를 따로 만든게 아니라 파이프라인으로 하고있습니다. )

  - 플랫, 고러드(스무스)를 사용할 수 있다.


플랫 쉐이딩





고러드 쉐이딩


// 플랫 쉐이딩
pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
// 고러드 쉐이딩
pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );


플랫 쉐이딩 사용시엔 보간이 이루어지지 않지만 고러드 쉐이딩 사용시엔 색상간 서로 보간이 이루어진 모습을 모인다.


현재 광원설징이 없으므로 광원을 사용 안함으로 해야 색상이 보인다는것에 주의하자!


소스코드


winmain.cpp


#include 
#include 
#pragma comment ( lib, "d3d9.lib" )
#pragma comment ( lib, "d3dx9.lib" )
#pragma comment ( lib, "winmm.lib" )
 
 
//사용자 추가 전역 변수
int                     ActiveFlage =   TRUE;   // 반복 체크
LPDIRECT3D9             pDX         =   NULL;   // dx객체
LPDIRECT3DDEVICE9       pDevice     =   NULL;   // dx디바이스
D3DPRESENT_PARAMETERS   stParam;                // 파라메터 구조체
float					lastTime	=	(float)timeGetTime();	// 마지막 시간
float					y			=	0.0f;	// y축 회전값
struct Vertex
{
	Vertex(){} // 생성자
	Vertex( float _x, float _y, float _z, D3DCOLOR _color ) // 생성자
	{
		x = _x;	y = _y;	z = _z;	color = _color;
	}
	float x, y, z;
	D3DCOLOR	color;
};

Vertex* Vtx;
WORD* Idx;
IDirect3DVertexBuffer9	*VB = 0;
IDirect3DIndexBuffer9	*IB = 0;
#define	MY_FVF D3DFVF_XYZ | D3DFVF_DIFFUSE
 
// 사용자 추가 핸들
 
// 콜백 함수
LRESULT CALLBACK WndProc ( HWND, UINT, WPARAM, LPARAM );
// 다이렉트x 초기화
VOID    Device_Init( INT , INT , HWND );
// 버텍스 인덱스 설정
VOID	VertexIndex( VOID );// 버텍스와 인덱스를 설정하는 함수
// 회전 함수
VOID RotationCube ( VOID );
int WINAPI  WinMain (   HINSTANCE   hInstance,  HINSTANCE   hPrevInstance,  PSTR    szCmdLine,  int iCmdShow    )
{
    static  TCHAR   szAppName[] =   "My Project";
 
    MSG         msg;
    HWND        hwnd;
    WNDCLASSEX  wndclass;
    //HDC           hdc;
    int         WIDTH   =   800,\
                HEIGHT  =   600;
    int         roop    =   1;
    bool        bWindow =   TRUE;   // 창모드 체크
 
    wndclass.cbSize             =   sizeof( wndclass );
    wndclass.style              =   CS_HREDRAW  |   CS_VREDRAW;
    wndclass.lpfnWndProc        =   WndProc;
    wndclass.cbClsExtra         =   0;
    wndclass.cbWndExtra         =   0;
    wndclass.hInstance          =   hInstance;
    wndclass.hIcon              =   LoadIcon( NULL, MAKEINTRESOURCE( IDI_APPLICATION ) );
    wndclass.hCursor            =   LoadCursor( NULL, IDC_ARROW );
    wndclass.hbrBackground      =   ( HBRUSH )GetStockObject( WHITE_BRUSH );
    wndclass.lpszMenuName       =   NULL;   // 메뉴없음
    wndclass.lpszClassName      =   szAppName;
    wndclass.hIconSm            =   LoadIcon( NULL, IDI_APPLICATION );
 
    RegisterClassEx ( &wndclass );
 
    hwnd    =   CreateWindow( szAppName,
                              szAppName, 
                              WS_SYSMENU, 
                              ( GetSystemMetrics( SM_CXSCREEN ) - WIDTH ) / 2, 
                              ( GetSystemMetrics( SM_CYSCREEN ) - HEIGHT ) / 2, 
                              WIDTH, 
                              HEIGHT, 
                              NULL, 
                              NULL, 
                              hInstance, 
                              NULL );
    ShowWindow( hwnd, iCmdShow );
 
    UpdateWindow ( hwnd );
 
    //다이렉트 X 관련
    Device_Init(WIDTH, HEIGHT, hwnd);
 
    D3DXMATRIX  mWorld;             // 월드 행렬
    D3DXMATRIX  mView;              // 뷰 행렬
    D3DXMATRIX  mProj;              // 투영 행렬
 
    // 투영행렬 셋팅
    D3DXMatrixPerspectiveFovLH  ( &mProj, D3DX_PI * 0.5f, (float)WIDTH / (float)HEIGHT, 1.0f, 1000.0f );
	pDevice->SetTransform( D3DTS_PROJECTION, &mProj ); // 투영행렬 적용

    float fCamera_x = 0.0f;
    float fCamera_y = 0.0f;
    float fCamera_z = -5.0f;
 
	VertexIndex(); // 버텍스와 인덱스를 설정하는 함수

    while( roop )
    {
        while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) != 0 )
        {
            if( GetMessage( &msg, NULL, 0, 0 ) == 0 )
            {
                roop    =   0;
            }
 
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
 
        if ( ActiveFlage    ==  TRUE ) // 실제 게임 코딩영역
        {       
			if ( GetAsyncKeyState(VK_ESCAPE) )
            {
                ActiveFlage =   FALSE;
                roop        =   NULL;
            }
             
            if ( GetAsyncKeyState( 'W' ) )
            {
                fCamera_z-=0.01f;
            }
            if ( GetAsyncKeyState( 'S' ) )
            {
                fCamera_z+=0.01f;
            }
            if ( GetAsyncKeyState( 'A' ) )
            {
                fCamera_x+=0.01f;
            }
            if ( GetAsyncKeyState( 'D' ) )
            {
                fCamera_x-=0.01f;
            }
            if ( GetAsyncKeyState( VK_SPACE ) )
            {
                fCamera_x = 0.0f;
                fCamera_y = 0.0f;
                fCamera_z = -5.0f;
            }
			RotationCube();//회전
            // 카메라 셋팅
            D3DXMatrixLookAtLH  ( &mView, &D3DXVECTOR3(fCamera_x, fCamera_y, fCamera_z),
                &D3DXVECTOR3(0.0f, 0.0f, 0.0f),
                &D3DXVECTOR3(0.0f, 1.0f, 0.0f) );
			pDevice->SetTransform(D3DTS_VIEW, &mView); // 뷰 행렬 적용

            pDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
            // 화면을 흰색으로 지움
			//pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); // 필모드를 와이어 프레임으로 그래야 선이 보임
			// 광원사용 안함
            pDevice->SetRenderState( D3DRS_LIGHTING, false );
			// 플랫 쉐이딩
			//pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
			// 고러드 쉐이딩
			pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );

			pDevice->BeginScene();// 그리기 시작
		
			pDevice->SetStreamSource(0, VB, 0, sizeof(Vertex));
			pDevice->SetIndices(IB);
			pDevice->SetFVF(MY_FVF);
			pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

            pDevice->EndScene();// 그리기 종료
            pDevice->Present( NULL, NULL, NULL, NULL );// 화면에 뿌려줌
			lastTime	=	(float)timeGetTime();
        }
    }
    pDevice->Release();
	// 디바이스 해제
	VB->Release();
	IB->Release();
	// 버퍼 해제
    return msg.wParam;
}
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
 
    switch ( iMsg )
    {
    case WM_ACTIVATE:
        {
            break;
        }
    case WM_CREATE:
        {
            ActiveFlage =   TRUE;
            break;
        }
    case WM_CLOSE:
        {
            ActiveFlage =   FALSE;
            PostQuitMessage(0);
            break;
        }
    case WM_PAINT:
            break;
    default:
        break;
    }
    return DefWindowProc( hwnd, iMsg, wParam, lParam );
}
 
VOID    Device_Init(INT WIDTH, INT HEIGHT, HWND hwnd)
{
    stParam.AutoDepthStencilFormat      =   D3DFMT_D24X8;   // 깊이 버퍼를 24비트로 만듬
    stParam.BackBufferCount             =   1;      // 1개의 백버퍼를 만듬
    stParam.BackBufferFormat            =   D3DFMT_X8R8G8B8;    // 백버퍼 포멧형태
    stParam.BackBufferHeight            =   HEIGHT; // 버퍼 크기
    stParam.BackBufferWidth             =   WIDTH;  // 버퍼 크기
    stParam.EnableAutoDepthStencil      =   TRUE;   // 스텐실 버퍼 자동생성 사용
    stParam.Flags                       =   D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
                                            // 시스템 자체가 백버퍼를 건딜 수 있게 한다 ( 하지만 작동 안함 )
    stParam.Windowed                    =   TRUE;   // 창모드로한다
    stParam.hDeviceWindow               =   hwnd;   // 디바이스가 어느 윈도우랑 연결될지 체크 윈도우 핸들을 넣어준다
    stParam.SwapEffect                  =   D3DSWAPEFFECT_DISCARD; // 백버퍼에서 프론트버퍼로 가져올 방식
    stParam.FullScreen_RefreshRateInHz  =   0;      // 모니터 주사율 창모드는 0
    stParam.PresentationInterval        =   D3DPRESENT_INTERVAL_IMMEDIATE;  // 프레젠트 명령어가 호출되면 바로 프론트 버퍼에 뿌림
    stParam.MultiSampleQuality          =   D3DMULTISAMPLE_NONE;    // 멀티셈플링 옵션으로 안씀(느려서)
 
    pDX =   Direct3DCreate9( D3D_SDK_VERSION );
    pDX->CreateDevice(0, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &stParam, &pDevice );
    // 맨앞 0번은 몇번째 그래픽 카드를 쓸것인지 0번이 현재 모니터에 뿌려주고있는 그래픽카드
}

VOID	VertexIndex( VOID )
{
	pDevice->CreateVertexBuffer( 
		8 * sizeof(Vertex),
		D3DUSAGE_WRITEONLY,
		MY_FVF, D3DPOOL_MANAGED,
		&VB, 0 );

	pDevice->CreateIndexBuffer(
		36 * sizeof(WORD),
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_MANAGED,
		&IB, 0 );

	VB->Lock( 0, 0, (void**)&Vtx, 0 );

	Vtx[0].x = -1.0f; Vtx[0].y = -1.0f; Vtx[0].z = -1.0f; Vtx[0].color = 0xffff0000;
	Vtx[1].x = -1.0f; Vtx[1].y =  1.0f; Vtx[1].z = -1.0f; Vtx[1].color = 0xff00ff00;
	Vtx[2].x =  1.0f; Vtx[2].y =  1.0f; Vtx[2].z = -1.0f; Vtx[2].color = 0xff0000ff;
	Vtx[3].x =  1.0f; Vtx[3].y = -1.0f; Vtx[3].z = -1.0f; Vtx[3].color = 0xffff0000;
	Vtx[4].x = -1.0f; Vtx[4].y = -1.0f; Vtx[4].z =  1.0f; Vtx[4].color = 0xff00ff00;
	Vtx[5].x = -1.0f; Vtx[5].y =  1.0f; Vtx[5].z =  1.0f; Vtx[5].color = 0xff0000ff;
	Vtx[6].x =  1.0f; Vtx[6].y =  1.0f; Vtx[6].z =  1.0f; Vtx[6].color = 0xffff0000;
	Vtx[7].x =  1.0f; Vtx[7].y = -1.0f; Vtx[7].z =  1.0f; Vtx[7].color = 0xff00ff00;//노가다 버전
	/*Vtx[0] = Vertex( -1.0f, -1.0f, -1.0f, 0xffff0000 );
	Vtx[1] = Vertex( -1.0f,  1.0f, -1.0f, 0xff00ff00 );
	Vtx[2] = Vertex(  1.0f,  1.0f, -1.0f, 0xff0000ff );
	Vtx[3] = Vertex(  1.0f, -1.0f, -1.0f, 0xffff0000 );
	Vtx[4] = Vertex( -1.0f, -1.0f,  1.0f, 0xff00ff00 );
	Vtx[5] = Vertex( -1.0f,  1.0f,  1.0f, 0xff0000ff );
	Vtx[6] = Vertex(  1.0f,  1.0f,  1.0f, 0xffff0000 );
	Vtx[7] = Vertex(  1.0f, -1.0f,  1.0f, 0xff00ff00 );// 단순 버전*/

	VB->Unlock();

	IB->Lock(0, 0, (void**)&Idx, 0);

	Idx[0]  = 0; Idx[1]  = 1; Idx[2]  = 2;
	Idx[3]  = 0; Idx[4]  = 2; Idx[5]  = 3;
	Idx[6]  = 4; Idx[7]  = 6; Idx[8]  = 5;
	Idx[9]  = 4; Idx[10] = 7; Idx[11] = 6;
	Idx[12] = 4; Idx[13] = 5; Idx[14] = 1;
	Idx[15] = 4; Idx[16] = 1; Idx[17] = 0;
	Idx[18] = 3; Idx[19] = 2; Idx[20] = 6;
	Idx[21] = 3; Idx[22] = 6; Idx[23] = 7;
	Idx[24] = 1; Idx[25] = 5; Idx[26] = 6;
	Idx[27] = 1; Idx[28] = 6; Idx[29] = 2;
	Idx[30] = 4; Idx[31] = 0; Idx[32] = 3;
	Idx[33] = 4; Idx[34] = 3; Idx[35] = 7;

	IB->Unlock();
}

VOID RotationCube ( VOID )
{
	float currTime  = (float)timeGetTime();
	float fangle = (currTime - lastTime)*0.001f; // 1회 루프 돌은 시간 * 0.001
	D3DXMATRIX Rx, Ry;

	D3DXMatrixRotationX(&Rx, 3.14f / 4.0f); // x축으로 pie/4 만큼 회전

	// 매 프레임마다 y축 회전값 증가	
	y += fangle;
	D3DXMatrixRotationY(&Ry, y); // y축으로 회전 적용

	// 한바퀴를 돌면 y축회전각을 리셋시킨다.
	if( y >= 6.28f )
		y = 0.0f;

	// x와 y의 회전된 행렬을 p에 합쳐준다.
	D3DXMATRIX p = Rx * Ry;
	pDevice->SetTransform(D3DTS_WORLD, &p); // 월드행렬에 p를 대입
}