2008. 2. 12. 03:34
프로그래밍/DirectX
1. Understanding the Problem At Hand
앞의 예제에서 한가지 빠진 부분이 바로 깊이다. 아래 두개의 그림처럼 원래 물리학적 원리를 따른다면 6-2와 같이 작은 삼각형이 가려져야 하지만 현재의 코드에서는 그렇지 않다는 것이 문제다.
Image 6.1 - Defying the Laws of Physics
왜 이런 현상이 나타나는가에 대한 해설이 나와 있는데 제법 좋은 설명인것 같다. 한번 정독 해보자.
모델이 렌더링 될때 몇가지 일들이 일어나는데 우선 Direct3D는 우리가 만들어 놓은 pipeline을 호출하게 된다. 그 pipeline은 이미 메모리 상에 압축되어 정리되어 있다. Direct3D는 각각의 모델에 대해서 pipeline을 적용하게 되는데 이때 3차원 이미지가 2차원 이미지로 저장된다.
한개의 모델에 대해서 2차원 이미지가 만들어지는 즉시 그 이미지는 back buffer에 저장된다. 첫번째 모델이 저렇게 저장되고 난 뒤에는 바로 다음 모델에 대해서 같은 동작을 하게 되는데 두번째 모델이 공간의 어떤 지점에 있든지 간에(첫번째 물체보다 앞에 있는 뒤에 있든) 그 위에 그려지게 되는데 바로 그 부분이 문제가 된다.
2. Z-Buffers
Image 6.3 - The Z-Buffer (Or Depth Buffer)
OpenGL에서도 있는 Depth buffer가 여기서도 역시나 존재하는데 바로 깊이 버퍼이고 이 깊이 버퍼는 각 픽셀에대한 깊이 정보를 가지는 것이다. 내가 생각하기에는 우선 Z-Buffer는 그려진 물체들 중에서 가장 가까운 물체의 깊이만을 저장할 것이다. 혹은 가장 가까운 물체에 대한 정보만 소유할 것이다. 그래서 어떤 물체가 가장 카메라에서 가까이 있는지를 금방 알수 있게 해준다.
Z-Buffer가 하는 일은 우선 카메라에서 가까운 픽셀을 가져온다음 그것을 back buffer에 그려준다. 동시에 그 위치에 해당하는 곳에다가 깊이 정보를 저장하는데 이렇게 함으로써 Direct3D가 각각의 픽셀이 얼마나 가까이 있는지를 알게 해줌으로써 물체가 그려져야 하는지 아니면 안그려져야 하는지를 알려준단다.
3. Including the Z-Buffer
중요한 3단계를 거쳐야 하는데,
1. 적절한 Presentation Parameters를 세팅한다.
2. Z-Buffering을 켠다
3. Z-Buffer를 지운다.
뭐, 여기서 2, 3번은 OpenGL에서도 했던거라서 알겠는데 1번은 뭐지?
3-1. Setting the Appropriate Presentation Parameters
위에서 보다시피 추가된 두줄의 코드가 있는데 첫번째 코드인 EnableAutoDepthStencil이 바로 Z-buffering의 종류중에 하나를 선택하는 것인데 가장 기본형을 선택했다. 하지만 물론 다른 여러가지의 옵션을 선택가능하다고 하는구나. (아마도 OpenGL의 GLSL과 유사한 기능이 있겠죠?)
두번째 줄에 있는 AutoDepthStencilFormat은 Z-Buffer의 각각의 픽셀의 format을 정의해 주는 것이다. 미리 정의된 pixel format을 사용하는 것이 아니라 여기서는 D3DFMT_D16을 사용하는데 이것은 깊이 버퍼 한 픽셀당 16비트를 소모한다는 의미.
3-2. Turning On Z-Buffering
아, 위에서는 걍 설정만 했을뿐 정말로 켜주는 것은 여기구나.
3-3. Clearing the Z-Buffer
이제는 메모리를 초기화 해줄 단계이죠. 알다시피 이전에 사용했던 명령중에 아래와 같이 back buffer를 지우던 명령이 있는데 바로 이 명령의 인자를 바꾸어서 Z-Buffer도 초기화 한다.
요기서 다음과 같이 요렇게 하자.
4. The Finished Program
Image 6.5 - The Rotating Triangles
앞의 예제에서 한가지 빠진 부분이 바로 깊이다. 아래 두개의 그림처럼 원래 물리학적 원리를 따른다면 6-2와 같이 작은 삼각형이 가려져야 하지만 현재의 코드에서는 그렇지 않다는 것이 문제다.
Image 6.1 - Defying the Laws of Physics
Image 6.2 - Obeying the Law
왜 이런 현상이 나타나는가에 대한 해설이 나와 있는데 제법 좋은 설명인것 같다. 한번 정독 해보자.
모델이 렌더링 될때 몇가지 일들이 일어나는데 우선 Direct3D는 우리가 만들어 놓은 pipeline을 호출하게 된다. 그 pipeline은 이미 메모리 상에 압축되어 정리되어 있다. Direct3D는 각각의 모델에 대해서 pipeline을 적용하게 되는데 이때 3차원 이미지가 2차원 이미지로 저장된다.
한개의 모델에 대해서 2차원 이미지가 만들어지는 즉시 그 이미지는 back buffer에 저장된다. 첫번째 모델이 저렇게 저장되고 난 뒤에는 바로 다음 모델에 대해서 같은 동작을 하게 되는데 두번째 모델이 공간의 어떤 지점에 있든지 간에(첫번째 물체보다 앞에 있는 뒤에 있든) 그 위에 그려지게 되는데 바로 그 부분이 문제가 된다.
2. Z-Buffers
Image 6.3 - The Z-Buffer (Or Depth Buffer)
OpenGL에서도 있는 Depth buffer가 여기서도 역시나 존재하는데 바로 깊이 버퍼이고 이 깊이 버퍼는 각 픽셀에대한 깊이 정보를 가지는 것이다. 내가 생각하기에는 우선 Z-Buffer는 그려진 물체들 중에서 가장 가까운 물체의 깊이만을 저장할 것이다. 혹은 가장 가까운 물체에 대한 정보만 소유할 것이다. 그래서 어떤 물체가 가장 카메라에서 가까이 있는지를 금방 알수 있게 해준다.
Z-Buffer가 하는 일은 우선 카메라에서 가까운 픽셀을 가져온다음 그것을 back buffer에 그려준다. 동시에 그 위치에 해당하는 곳에다가 깊이 정보를 저장하는데 이렇게 함으로써 Direct3D가 각각의 픽셀이 얼마나 가까이 있는지를 알게 해줌으로써 물체가 그려져야 하는지 아니면 안그려져야 하는지를 알려준단다.
3. Including the Z-Buffer
중요한 3단계를 거쳐야 하는데,
1. 적절한 Presentation Parameters를 세팅한다.
2. Z-Buffering을 켠다
3. Z-Buffer를 지운다.
뭐, 여기서 2, 3번은 OpenGL에서도 했던거라서 알겠는데 1번은 뭐지?
3-1. Setting the Appropriate Presentation Parameters
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
위에서 보다시피 추가된 두줄의 코드가 있는데 첫번째 코드인 EnableAutoDepthStencil이 바로 Z-buffering의 종류중에 하나를 선택하는 것인데 가장 기본형을 선택했다. 하지만 물론 다른 여러가지의 옵션을 선택가능하다고 하는구나. (아마도 OpenGL의 GLSL과 유사한 기능이 있겠죠?)
두번째 줄에 있는 AutoDepthStencilFormat은 Z-Buffer의 각각의 픽셀의 format을 정의해 주는 것이다. 미리 정의된 pixel format을 사용하는 것이 아니라 여기서는 D3DFMT_D16을 사용하는데 이것은 깊이 버퍼 한 픽셀당 16비트를 소모한다는 의미.
3-2. Turning On Z-Buffering
아, 위에서는 걍 설정만 했을뿐 정말로 켜주는 것은 여기구나.
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
3-3. Clearing the Z-Buffer
이제는 메모리를 초기화 해줄 단계이죠. 알다시피 이전에 사용했던 명령중에 아래와 같이 back buffer를 지우던 명령이 있는데 바로 이 명령의 인자를 바꾸어서 Z-Buffer도 초기화 한다.
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
요기서 다음과 같이 요렇게 하자.
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
4. The Finished Program
Image 6.5 - The Rotating Triangles
// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
// define the screen resolution and keyboard macros
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// include the Direct3D Library files
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
// global declarations
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 t_buffer = NULL; // the pointer to the vertex buffer
// function prototypes
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void render_frame(void); // renders a single frame
void cleanD3D(void); // closes Direct3D and releases memory
void init_graphics(void); // 3D declarations
struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // not needed any more
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
initD3D(hWnd);
// enter the main loop:
MSG msg;
while(TRUE)
{
DWORD starting_point = GetTickCount();
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render_frame();
// check the 'escape' key
if(KEY_DOWN(VK_ESCAPE))
PostMessage(hWnd, WM_DESTROY, 0, 0);
while ((GetTickCount() - starting_point) < 25);
}
// clean up DirectX and COM
cleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE; // automatically run the z-buffer for us
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16-bit pixel format for the z-buffer
// create a device class using this information and the info from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
init_graphics(); // call the function to initialize the triangle
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
return;
}
// this is the function used to render a single frame
void render_frame(void)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
// select which vertex format we are using
d3ddev->SetFVF(CUSTOMFVF);
// set the view transform
D3DXMATRIX matView; // the view transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0.0f, 0.0f, 15.0f), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
// select the vertex buffer to display
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
D3DXMATRIX matTranslateA; // a matrix to store the translation for triangle A
D3DXMATRIX matTranslateB; // a matrix to store the translation for triangle B
D3DXMATRIX matRotateYA; // a matrix to store the rotation for each triangle
D3DXMATRIX matRotateYB; // a matrix to store the rotation for the reverse sides
static float index = 0.0f; index+=0.05f; // an ever-increasing float value
// build MULTIPLE matrices to rotate and translate the model
D3DXMatrixTranslation(&matTranslateA, 0.0f, 0.0f, 2.0f);
D3DXMatrixTranslation(&matTranslateB, 0.0f, 0.0f, -2.0f);
D3DXMatrixRotationY(&matRotateYA, index); // the front side
D3DXMatrixRotationY(&matRotateYB, index + 3.14159f); // the reverse side
// tell Direct3D about each world transform, and then draw another triangle
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateA * matRotateYA));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateA * matRotateYB));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateB * matRotateYA));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateB * matRotateYB));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
return;
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
t_buffer->Release(); // close and release the vertex buffer
d3ddev->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
return;
}
// this is the function that puts the 3D models into video RAM
void init_graphics(void)
{
// create the vertices using the CUSTOMVERTEX struct
CUSTOMVERTEX t_vert[] =
{
{ 2.5f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -2.5f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock t_buffer and load the vertices into it
t_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, t_vert, sizeof(t_vert));
t_buffer->Unlock();
return;
}
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
// define the screen resolution and keyboard macros
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// include the Direct3D Library files
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
// global declarations
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 t_buffer = NULL; // the pointer to the vertex buffer
// function prototypes
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void render_frame(void); // renders a single frame
void cleanD3D(void); // closes Direct3D and releases memory
void init_graphics(void); // 3D declarations
struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // not needed any more
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
initD3D(hWnd);
// enter the main loop:
MSG msg;
while(TRUE)
{
DWORD starting_point = GetTickCount();
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render_frame();
// check the 'escape' key
if(KEY_DOWN(VK_ESCAPE))
PostMessage(hWnd, WM_DESTROY, 0, 0);
while ((GetTickCount() - starting_point) < 25);
}
// clean up DirectX and COM
cleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE; // automatically run the z-buffer for us
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16-bit pixel format for the z-buffer
// create a device class using this information and the info from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
init_graphics(); // call the function to initialize the triangle
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
return;
}
// this is the function used to render a single frame
void render_frame(void)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
// select which vertex format we are using
d3ddev->SetFVF(CUSTOMFVF);
// set the view transform
D3DXMATRIX matView; // the view transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0.0f, 0.0f, 15.0f), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
// select the vertex buffer to display
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
D3DXMATRIX matTranslateA; // a matrix to store the translation for triangle A
D3DXMATRIX matTranslateB; // a matrix to store the translation for triangle B
D3DXMATRIX matRotateYA; // a matrix to store the rotation for each triangle
D3DXMATRIX matRotateYB; // a matrix to store the rotation for the reverse sides
static float index = 0.0f; index+=0.05f; // an ever-increasing float value
// build MULTIPLE matrices to rotate and translate the model
D3DXMatrixTranslation(&matTranslateA, 0.0f, 0.0f, 2.0f);
D3DXMatrixTranslation(&matTranslateB, 0.0f, 0.0f, -2.0f);
D3DXMatrixRotationY(&matRotateYA, index); // the front side
D3DXMatrixRotationY(&matRotateYB, index + 3.14159f); // the reverse side
// tell Direct3D about each world transform, and then draw another triangle
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateA * matRotateYA));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateA * matRotateYB));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateB * matRotateYA));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->SetTransform(D3DTS_WORLD, &(matTranslateB * matRotateYB));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
return;
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
t_buffer->Release(); // close and release the vertex buffer
d3ddev->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
return;
}
// this is the function that puts the 3D models into video RAM
void init_graphics(void)
{
// create the vertices using the CUSTOMVERTEX struct
CUSTOMVERTEX t_vert[] =
{
{ 2.5f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -2.5f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock t_buffer and load the vertices into it
t_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, t_vert, sizeof(t_vert));
t_buffer->Unlock();
return;
}
'프로그래밍 > DirectX' 카테고리의 다른 글
[DX Tutorial] Lesson 8: Adding Textures (0) | 2008.02.14 |
---|---|
[DX Tutorial] Lesson 7: Simple Modeling (0) | 2008.02.12 |
[DX Tutorial] Lesson 5: Transforming Vertices (0) | 2008.02.07 |
[DX Tutorial] Lesson 4: Drawing a Triangle (0) | 2008.02.06 |
[DX Tutorial] Lesson 3: An Overview of the Third Dimension (0) | 2008.02.06 |