11장 메쉬 파트II 2009-1학기 컴퓨터게임(DirectX).

Slides:



Advertisements
Similar presentations
6 장. printf 와 scanf 함수에 대한 고찰 printf 함수 이야기 printf 는 문자열을 출력하는 함수이다. – 예제 printf1.c 참조 printf 는 특수 문자 출력이 가능하다. 특수 문자의 미 \a 경고음 소리 발생 \b 백스페이스 (backspace)
Advertisements

ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
Entity Relationship Diagram
제12장 유연한 카메라 클래스 만들기 학기 컴퓨터게임(DirectX).
제13장 기본적인 지형 렌더링 학기 컴퓨터게임(DirectX).
연결리스트(linked list).
제 9 장 구조체와 공용체.
Report #2 - Solution 문제 #1: 다음과 같이 프로그램을 작성하라.
컴퓨터 프로그래밍 기초 [Final] 기말고사
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 12. 포인터의 이해.
제 6장. 생성자와 소멸자 학기 프로그래밍언어및실습 (C++).
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express Slide 1 (of 13)
9장 글꼴.
제 15 장 픽킹.
9장 글꼴.
제 3장. C보다 나은 C++ II.
제6장 텍스처링 학기 컴퓨터게임(DirectX).
제8장 스텐실.
제 14 장 파티클 시스템.
제 18 장 픽셀 셰이더의 소개.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
SqlParameter 클래스 선문 비트 18기 발표자 : 박성한.
Error Detection and Correction
멀티미디어 시스템 (아날로그 이미지,신호를 디지털로 변환 방법) 이름 : 김대진 학번 :
23장. 구조체와 사용자 정의 자료형 2.
제4장 컬 러(COLOR) 컬러 표현 Direct3D는 RGB 세 성분을 이용해 컬러 표현
제5장 조명 학기 컴퓨터게임(DIrectX).
프로그래밍 랩 – 7주 리스트.
11장. 1차원 배열.
제 16 장 고수준 셰이딩 언어 소개.
CHAP 12. 리소스와 보안.
C#.
10강. JSP 본격적으로 살펴보기-II 스크립트릿, 선언, 표현식 지시자 주석 Lecturer Kim Myoung-Ho
JA A V W. 03.
어서와 C언어는 처음이지 제14장.
Chapter03 캔버스(1) HTML5 Programming.
13. 포인터와 배열! 함께 이해하기 IT응용시스템공학과 김 형 진 교수.
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
HTTP 프로토콜의 요청과 응답 동작을 이해한다. 서블릿 및 JSP 를 알아보고 역할을 이해한다.
24장. 파일 입출력.
10장 메쉬 파트 I.
Lesson 2. 기본 데이터형.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
15장 컬렉션 프레임워크 Section 1 컬렉션 프레임워크의 개요 Section 2 리스트 Section 3 셋
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
Clipping 이진학.
5강. 배열 배열이란? 배열의 문법 변수와 같이 이해하는 배열의 메모리 구조의 이해 레퍼런스의 이해 다차원 배열
Choi Seong Yun 컴퓨터 프로그래밍 기초 #03 : 변수와 자료형 Choi Seong Yun
제 15 강 문자와 코드 shcho.pe.kr.
4장. 데이터 표현 방식의 이해. 4장. 데이터 표현 방식의 이해 4-1 컴퓨터의 데이터 표현 진법에 대한 이해 n 진수 표현 방식 : n개의 문자를 이용해서 데이터를 표현 그림 4-1.
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
11장 배열 1. 배열이란? 1.1 배열의 개요 1.2 배열의 선언과 사용.
구조체(struct)와 공용체(union)
Summary of Pointers and Arrays
9 브라우저 객체 모델.
Android -Data Base 윤수진 GyeongSang Univ. IT 1.
우선 각 평면도에서 점선으로 강조한 직육면체 형상의 피처를 생성한다. 여기서 컴퓨터응용가공산업기사 준비를
Numerical Analysis Programming using NRs
컴퓨터공학과 손민정 Computer Graphics Lab 이승용 교수님
동적메모리와 연결 리스트 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
제 4 장 Record.
29장. 템플릿과 STL 01_ 템플릿 02_ STL.
어서와 C언어는 처음이지 제21장.
개정판 누구나 즐기는 C언어 콘서트 제13장 동적 메모리 출처: pixabay.
13. 포인터와 배열! 함께 이해하기.
7 생성자 함수.
6 객체.
BoardGame 보드게임 따라가기.
20 XMLHttpRequest.
2019 2학기 9장 배열과 포인터 1. 주소, 주소연산자(&) 2. 포인터, 역참조연산자(*) 3. 배열과 포인터.
Presentation transcript:

11장 메쉬 파트II 2009-1학기 컴퓨터게임(DirectX)

11장 내용 D3DX 라이브러리가 제공하는 메쉬 관련 인터페이스, 구조체, 함수들 Xfile 데이터를 ID3DXMesh 객체로 읽어들이는 방법 프로그레시브 메쉬를 이용하여 얻을 수 있는 이점 및 프로그레시브 메쉬 인터페이스 ID3DXPMesh 이용 방법 경계볼륨의 정체와 용도 및 D3DX 함수 2009-1학기 컴퓨터게임(DirectX)

ID3DXBuffer ID3DXBuffer 인터페이스는 D3DX가 연속적인 메모리 블록에 데이터를 저장하기 위해 이용하는 범용 데이터 구조체로, 다음과 같은 두 개의 메서드를 가짐 LPVOID GetBufferPointer(); - 데이터의 시작을 가리키는 포인터를 리턴 DWORD GetBufferSize(); - 버퍼 크기를 바이트 수로 리턴 구조체의 범용성을 유지하기 위해 포인터를 한다는 것은 저장되는 데이터의 형을 우리가 관리해야 함을 의미 예를 들어, D3DXLoadMeshFromX는 메쉬의 인접 정보를 리턴하기 위해 ID3DXBuffer를 이용하는데, 인접 정보는 DWORD 배열이므로 버퍼의 인접 정보를 이용하기 위해서는 우선 버퍼를 DWORD 배열로 형 변환해야 함 2009-1학기 컴퓨터게임(DirectX)

DWORD* info = (DWORD*)adjacencyInfo->GetBufferPointer(); 예: DWORD* info = (DWORD*)adjacencyInfo->GetBufferPointer(); D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); ID3DXBuffer는 COM객체이므로 이용이 끝난 뒤에는 메모리 누출을 막기 위해 반드시 객체를 풀어주어야 함 adjacencyInfo->Release(); mtrlBuffer->Release(); 다음과 같은 함수를 이용하면 빈 ID3DXBuffer를 만들 수 있음 HRESULT D3DXCreateBuffer( DWORD NumBytes, //버퍼의 크기, 바이트 단위 LPD3DXBUFFER *ppBuffer //생성된 버퍼를 리턴 ); 2009-1학기 컴퓨터게임(DirectX)

D3DXCreateBuffer(4*sizeof(int),&buffer); 다음의 예는 네 개의 정수를 보관할 수 있는 버퍼를 만드는 것 ID3DXBuffer* buffer=0; D3DXCreateBuffer(4*sizeof(int),&buffer); 2009-1학기 컴퓨터게임(DirectX)

Xfile 3D 물체 데이터를 구성하는 지루한 작업을 도와주기 위해 3D 모델러라 불리는 특수한 애플리케이션들이 개발되었는데, 이 모델러들은 다양한 툴셋과 시각적이고 인터랙티브한 환경을 통해 더욱 쉽고 빠르게 모델링을 수행할 수 있도록 해줌 게임 개발에 자주 이용되는 모델러로는 3DS MAX나 LightWave 3D, Maya 등이 있음 이 모델러들은 만들어진 메쉬 데이터는 파일로 저장할 수 있으며,따라서 메쉬 데이터를 추출하는 파일 리더를 만든다면 이 데이터를 우리의 3D 애플리케이션에서 이용할 수 있음 2009-1학기 컴퓨터게임(DirectX)

Xfile 포맷이라 불리는 특수한 메쉬파일 포맷은 대부분의 3D 모델러들이 이 포맷으로 저장하는 기능을 가지고 있으며, 기존의 메쉬 파일 포맷을 .X로 변환하는 변환기도 만들어져 있음 Xfile의 장점은 DirectX가 이 파일 포맷을 정의하고 있다는 것. 이 때문에 Xfile은 별다른 준비 과정 없이 D3DX 라이브러리에서 이용이 가능하며, 라이브러리 자체에서 Xfile을 읽고 저장하는 함수들을 제공 2009-1학기 컴퓨터게임(DirectX)

Xfile 읽어들이기 다음의 함수를 이용해 Xfile에 보관된 메쉬 데이터를 읽어들 일 수 있음 이 메서드는 ID3DXMesh 객체를 만들고 여기에 Xfile의 기하정보 데이터를 읽음 HRESULT D3DXLoadMeshFromX( LPCSTR pFilename, DWORD Options, LPDIRECT3DDEVICE9 pDevice, LPD3DXBUFFER *ppAdjacency, LPD3DXBUFFER *ppMaterials, LPD3DXBUFFER *ppEffectInstances, PDWORD pNumMaterials, LPD3DXMESH *ppMesh); 2009-1학기 컴퓨터게임(DirectX)

D3DXMESH_32BIT – 메쉬는 32비트 인덱스를 이용하게 됨 pFilename – 읽어들이고자 하는 Xfile의 파일명 Options – 메쉬를 만드는 데 이용될 하나 이상의 생성 플래그 D3DXMESH_32BIT – 메쉬는 32비트 인덱스를 이용하게 됨 D3DXMESH_MANAGED – 메쉬는 관리 메모리 풀 내에 보관 D3DXMESH_WRITEONLY – 메쉬 데이터에는 쓰기만 허용 D3DXMESH_DYNAMIC – 메쉬 버퍼는 동적으로 만들어짐 2009-1학기 컴퓨터게임(DirectX)

ppAdjacency – 메쉬 접근 정보를 위한 DWORD 배열을 포함하는 ID3DXBuffer를 리턴 pDevice – 메쉬와 연계될 장치 ppAdjacency – 메쉬 접근 정보를 위한 DWORD 배열을 포함하는 ID3DXBuffer를 리턴 ppMaterials – 메쉬 재질 정보를 위한 D3DXMATERIAL 구조체 배열을 포함하는 ID3DXBuffer를 리턴 ppEffectInstances – D3DXEFFECTINSTANCE 구조체 배열을 포함하는 ID3DXBuffer를 리턴. 현재로서는 0을 지정하여 이 인자를 무시 pNumMaterials – 메쉬의 재질 수를 리턴 ppMesh – Xfile 기하정보로 채워진 ID3DXMesh 객체를 리턴 2009-1학기 컴퓨터게임(DirectX)

Xfile 재질 D3DXLoadMeshFromX 함수의 일곱 번째 인자는 메쉬가 포함하는 재질의 수를 리턴하며 다섯 번째 인자는 재질 데이터를 포함하는 D3DXMATERIAL 구조체 배열을 리턴 D3DXMATERIAL 구조체는 다음과 같이 정의 typedef struct D3DXMATERIAL { D3DMATERIAL9 MatD3D; LPSTR pTextureFilename; } D3DXMATERIAL; 이는 비교적 단순한 구조체로, 기본적인 D3DMATERIAL9 구조체와 연결된 텍스처 파일명을 지정하는 null-종료 문자열로의 포인터를 포함 2009-1학기 컴퓨터게임(DirectX)

Xfile은 텍스처 데이터를 직접 포함하지 않으며 실제 텍스처 데이터를 포함하는 이미지 파일로의 파일명을 포함 Xfile은 텍스처 데이터를 직접 포함하지 않으며 실제 텍스처 데이터를 포함하는 이미지 파일로의 파일명을 포함. 즉, D3DXLoadMeshFromX를 이용해 Xfile을 일어들인 다음에는 알아낸 텍스처 파일명으로 텍스처 데이터를 읽어들여야 함 D3DXLoadMeshFromX함수는 리턴된 D3DXMATERIAL 배열의 i번째 항목이 i번째 서브셋과 대응되도록 Xfile 데이터를 읽어들임 2009-1학기 컴퓨터게임(DirectX)

예제 애플리케이션: Xfile 이 예제는 다음과 같은 전역 변수를 이용 ID3DXMesh* Mesh = 0; std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); 첫 번째 변수인 ID3DXMesh 객체는 Xfile에서 읽어들인 메쉬 데이터를 보관하는데 이용. 두 번째와 세 번째 변수는 각각 재질과 텍스처의 벡터이며, 메쉬의 재질과 텍스처를 보관하는데 이용 2009-1학기 컴퓨터게임(DirectX)

예제는 먼저 표준인 Setup 함수를 구현하였는데 여기서 Xfile을 읽어들이는 작업이 이루어짐 HRESULT hr = 0; // Load the XFile data. ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; hr = D3DXLoadMeshFromX( "bigship1.x", D3DXMESH_MANAGED, Device, &adjBuffer, &mtrlBuffer, 0, &numMtrls, 2009-1학기 컴퓨터게임(DirectX)

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } if(FAILED(hr)) { ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } 이어 Xfile의 실제 데이터를 읽어 들임. 여기에서는 D3DXMATERIAL 배열을 대상으로 반복하여 메쉬가 참조하는 텍스처를 읽어들여야 함 // Extract the materials, and load textures. if( mtrlBuffer != 0 && numMtrls != 0 ) 2009-1학기 컴퓨터게임(DirectX)

for(int i = 0; i < numMtrls; i++) { D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(int i = 0; i < numMtrls; i++) { // the MatD3D property doesn't have an ambient value set // when its loaded, so set it now: mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse; // save the ith material Mtrls.push_back( mtrls[i].MatD3D ); // check if the ith material has an associative texture if( mtrls[i].pTextureFilename != 0 ) // yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; 2009-1학기 컴퓨터게임(DirectX)

D3DXCreateTextureFromFile( Device, mtrls[i].pTextureFilename, &tex); // save the loaded texture Textures.push_back( tex ); } else { // no texture for the ith subset Textures.push_back( 0 ); d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer 2009-1학기 컴퓨터게임(DirectX)

bool Display(float timeDelta) { if( Device ) static float y = 0.0f; .//단원과 관련이 없는 코드는 생략 return 0; }//Setup() 종료 Display 함수에서는 매 프레임마다 메쉬를 조금씩 회전하도록 함. 메쉬 내의 서브셋 들은 0, 1, 2, …, n-1 형식으로 번호가 매겨져 있으므로 매우 간단한 루프를 이용해 전체 메쉬를 렌더링할 수 있음 bool Display(float timeDelta) { if( Device ) static float y = 0.0f; D3DXMATRIX yRot; 2009-1학기 컴퓨터게임(DirectX)

D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) D3DXMATRIX World = yRot; Device->SetTransform(D3DTS_WORLD, &World); // Render Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); 2009-1학기 컴퓨터게임(DirectX)

for(int i = 0; i < Mtrls.size(); i++) { Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]); Mesh->DrawSubset(i); } Device->EndScene(); Device->Present(0, 0, 0, 0); return true; 2009-1학기 컴퓨터게임(DirectX)

2009-1학기 컴퓨터게임(DirectX)

#include <vector> IDirect3DDevice9* Device = 0; #include "d3dUtility.h" #include <vector> IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Mesh = 0; std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); bool Setup() { HRESULT hr = 0; ID3DXBuffer* adjBuffer = 0; 2009-1학기 컴퓨터게임(DirectX)

ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; hr = D3DXLoadMeshFromX( "bigship1.x", D3DXMESH_MANAGED, Device, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &Mesh); if(FAILED(hr)) { ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } 2009-1학기 컴퓨터게임(DirectX)

if( mtrlBuffer != 0 && numMtrls != 0 ) { D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(int i = 0; i < numMtrls; i++) // the MatD3D property doesn't have an ambient value set // when its loaded, so set it now: mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse; // save the ith material Mtrls.push_back( mtrls[i].MatD3D ); // check if the ith material has an associative texture if( mtrls[i].pTextureFilename != 0 ) 2009-1학기 컴퓨터게임(DirectX)

// yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; D3DXCreateTextureFromFile( Device, mtrls[i].pTextureFilename, &tex); // save the loaded texture Textures.push_back( tex ); } else { // no texture for the ith subset Textures.push_back( 0 ); d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer 2009-1학기 컴퓨터게임(DirectX)

hr = Mesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0); d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer if(FAILED(hr)) { ::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0); return false; } 2009-1학기 컴퓨터게임(DirectX)

Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); // // Set Lights. D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f); D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f); D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col); 2009-1학기 컴퓨터게임(DirectX)

Device->SetLight(0, &light); Device->LightEnable(0, true); Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); Device->SetRenderState(D3DRS_SPECULARENABLE, true); // // Set camera. D3DXVECTOR3 pos(4.0f, 4.0f, -13.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); 2009-1학기 컴퓨터게임(DirectX)

Device->SetTransform(D3DTS_VIEW, &V); D3DXMATRIX proj; D3DXMATRIX V; D3DXMatrixLookAtLH( &V, &pos, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); 2009-1학기 컴퓨터게임(DirectX)

d3d::Release<ID3DXMesh*>(Mesh); return true; } void Cleanup() { d3d::Release<ID3DXMesh*>(Mesh); for(int i = 0; i < Textures.size(); i++) d3d::Release<IDirect3DTexture9*>( Textures[i] ); bool Display(float timeDelta) if( Device ) static float y = 0.0f; D3DXMATRIX yRot; 2009-1학기 컴퓨터게임(DirectX)

D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) D3DXMATRIX World = yRot; Device->SetTransform(D3DTS_WORLD, &World); Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); for(int i = 0; i < Mtrls.size(); i++) { Device->SetMaterial( &Mtrls[i] ); 2009-1학기 컴퓨터게임(DirectX)

Device->SetTexture(0, Textures[i]); Mesh->DrawSubset(i); } Device->EndScene(); Device->Present(0, 0, 0, 0); return true; LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) case WM_DESTROY: ::PostQuitMessage(0); break; 2009-1학기 컴퓨터게임(DirectX)

if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) ::MessageBox(0, "InitD3D() - FAILED", 0, 0); 2009-1학기 컴퓨터게임(DirectX)

::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); 2009-1학기 컴퓨터게임(DirectX)

버텍스 법선 생성하기 Xfile에 만약 법선 데이터가 없다면 조명을 위해 직접 버텍스 법선 데이터를 계산해내야 함. 다음과 같은 함수를 이용해 메쉬의 버텍스 법선을 만들어낼 수 있음 HRESULT D3DXComputeNormals( LPD3DXBASEMESH pMesh, //법선을 계산하려는 메쉬 const DWORD *pAdjacency //입력 인접 정보 ); 이 함수는 법선 평균을 이용해 버텍스 법선을 계산해냄. 만약 제공된 인접 정보가 있다면 중복된 버텍스를 제거하며, 인접 정보가 제공되지 않는다면 중복된 버텍스도 참조한 면의 평균으로 법선을 가짐 2009-1학기 컴퓨터게임(DirectX)

pMesh로 전달할 메쉬는 D3DFVF_NORMAL 플래그를 포함하는 버텍스 포맷을 가져야 함 만약 Xfile이 버텍스 법선 데이터를 포함하지 않는다면 D3DXLoadMeshFromX으로 만든 ID3DXMesh객체도 버텍스 포맷 내에 정의된D3DFVF_NORMAL을 가지지 않는다는데 주의. 따라서 D3DXComputeNormals를 이용하기 전에 먼저 메쉬를 복제하고 복제한 메쉬의 버텍스 포맷을 지정. 다음의 코드는 이 같은 작업 과정을 보여줌 2009-1학기 컴퓨터게임(DirectX)

//메쉬가 버텍스 포맷으로 Dd3dfvf_normal를 가지고 있는가? if(!(pMesh->GetFVF() & D3DFVF_NORMAL)) { //아니다. 따라서 새 메쉬를 복제하고 포맷으로 D3DFVF_NORMAL를 추가 ID3DXMesh* pTempMesh = 0; pMesh->CloneMeshFVF( D3DXMESH_MANAGED, pMesh->GetFVF()|D3DFVF_NORMAL,//이곳에 추가 Device, &pTempMesh); //법선을 계산 D3DXComputeNormals(pTempMesh,0); pMesh->Release(); //기존의 메쉬를 제거 pMesh=pTempMesh; //새로운 메쉬를 법선과 함께 저장 } 2009-1학기 컴퓨터게임(DirectX)

프로그레시브 메쉬 ID3DXPMesh 인터페이스에 의해 표현되는 프로그레시브 메쉬는 경계 상실 변환(ECT: edge collapse transformation) 시퀀스를 적용하여 메쉬를 단순화할 수 있도록 함 각각의 ECT는 하나의 버텍스와 하나 혹은 두 개의 면을 제거하는데, 각각의 ECT를 되돌릴 수가 있으므로(되돌리는 과정은 버텍스 분할이라 부름) 단순화 과정을 되돌려 원래 상태의 메쉬로 돌아갈 수 있음 프로그레시브 메쉬의 작동 원리는 텍스처에서 밉맵을 이용하는 것과 유사. 텍스처링을 수행할 때, 작고 먼 기본형에 복잡한 고해상도의 텍스처를 이용하는 것이 낭비가 된다는 것을 잘 알고 있는데, 메쉬에 있어서도 마찬가지 개념이 적용 작고 먼 메쉬는 크고 가까운 메쉬만큼 많은 삼각형이 필요치 않음 작은 메쉬에서는 부가적인 삼각형에 의한 세부적인 면이 유실될 것임 프로그레시브 메쉬를 이용하는 한 가지 방법은 카메라와의 거리에 따라 메쉬의 LOD를 조정하는 방법이 있는데, 다시 말해서 카메라와의 거리가 감소하면 메쉬의 세부(삼각형)를 더하고 거리가 증가하면 세부를 감소시킴 2009-1학기 컴퓨터게임(DirectX)

프로그레시브 메쉬 생성하기 다음과 같은 함수를 이용하면 ID3DXPMesh 객체를 만들 수 있음 HRESULT D3DXGeneratePMesh( LPD3DXMESH pMesh, CONST DWORD *pAdjacency, CONST LPD3DXATTRIBUTEWEIGHTS pVertexAttributeWeights, CONST FLOAT *pVertexWeights, DWORD MinValue, DWORD Options, LPD3DXPMESH *ppPMesh ); 2009-1학기 컴퓨터게임(DirectX)

pMesh – 프로그레시브 메쉬를 생성하고자 하는 입력 원본 메쉬 pAdjacency – pMesh의 인접 정보를 포함하는 DWORD 배열로의 포인터 pVertexAttributeWeights – i번째 배열이 pMesh 내의 i번째 버텍스와 대응되며 속성의 영향력을 지정하는 D3DXATTRIBUTEWEIGHTS 배열(Pmesh->GetNumVertices() 크기)로의 포인터 pVertexWeight – i번째 항목이 pMesh 내의 i번째 버텍스와 대응되며 pMesh->GetNumVertices() 크기를 가지는 float 배열 MinValue – 단순화의 결과로 얻어질 최소한의 버텍스나 면 Options – D3DXMESHSIMP 열거형 중 하나를 사용 D3DXMESHSIMP_VERTEX – 앞서의 MinValue 인자가 버텍스에 적용됨을 지정 2009-1학기 컴퓨터게임(DirectX)

D3DXMESHSIMP_FACE - 앞서의 MinValue 인자가 면에 적용됨을 지정 ppMesh – 생성된 프로그레시브 메쉬를 리턴 2009-1학기 컴퓨터게임(DirectX)

버텍스 속성 영향력 typedef struct _D3DXATTRIBUTEWEIGHTS { FLOAT Position; FLOAT Boundary; FLOAT Normal; FLOAT Diffuse; FLOAT Specular; FLOAT Texcoord[8]; FLOAT Tangent; FLOAT Binormal; } D3DXATTRIBUTEWEIGHTS; 버텍스 영향력 구조체는 버텍스 각 요소의 영향력을 지정할 수 있도록 해줌. 0.0값은 요소가 전혀 영향력을 가지고 있지 않음을 지정하며, 값이 높을 수록 버텍스의 영향력이 높아져 단순화 과정에서 제거될 가능성이 낮아짐 2009-1학기 컴퓨터게임(DirectX)

D3DXATRIBUTEWIGHTS AttributeWeights; AttributeWeights.Position = 1.0; 디폴트 영향력은 다음과 같음 D3DXATRIBUTEWIGHTS AttributeWeights; AttributeWeights.Position = 1.0; AttributeWeights.Boundary = 1.0; AttributeWeights.Normal = 1.0; AttributeWeights.Diffuse = 0.0; AttributeWeights.Specular = 0.0; AttributeWeights.Tex[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; 2009-1학기 컴퓨터게임(DirectX)

ID3DXPMesh 메서드 ID3DXPMesh 인터페이스는 ID3DXBaseMesh 인터페이스를 상속받음. 따라서 앞서 공부한 ID3DXMesh의 모든 기능을 가지고 있으며, 다음과 같은 추가 메서드들을 포함 DWORD GetMaxFaces(VOID); - 프로그레시브 메쉬가 가질 수 있는 최대 면 수를 리턴 DWORD GetMaxVertices(VOID); - 프로그레시브 메쉬가 가질 수 있는 최대 면 수를 리턴 DWORD GetMinFaces(VOID); - 프로그레시브 메쉬가 가질 수 있는 최소 면 수를 리턴 DWORD GetMinVertices(VOID); - 프로그레시브 메쉬가 가질 수 있는 최소 버텍스 수를 리턴 HRESULT SetNumFaces(DWORD faces); - 이 메서드는 단순화/복잡화 하려는 메쉬의 면 수를 지정할 수 있게 해줌. 예를 들어 현재 50면을 가진 메쉬가 있다고 할 때 이를 30면으로 줄이고자 한다면 다음과 같은 코드 라인을 이용 pmesh->SetNumFaces(30); 2009-1학기 컴퓨터게임(DirectX)

pmesh->SetNumVertices(40); HRESULT SetNumVertices(DWORD Vertices); - 이 메서드는 단순화/복잡화하려는 메쉬의 버텍스 수를 지정할 수 있게 해줌. 예를 들어 현재 20개의 버텍스를 가진 메쉬가 있고 버텍스의 수를 40개로 늘리고자 한다면 다음과 같은 코드 라인을 이용 pmesh->SetNumVertices(40); HRESULT TrimByFaces(DWORD NewFacesMin, DWORD NewFaceMax, DWORD *rgiFaceRemap, DWORD *rgiVertexRemap); - 이 메서드는 NewFacesMin과 NewFacesMax 인자를 통해 새로운 최소 면 수와 최대 면 수를 지정할 수 있도록 해줌. 새로운 최소/최대 값은 반드시 현재의 최소/최대 면 수 범위에 있어야 함 2009-1학기 컴퓨터게임(DirectX)

HRESULT TrimByVertices(DWORD NewVerticesMin, DWORD NewVerticesMax, DWORD *rgiFaceRemap, DWORD *rgiVertRemap); - 이 메서드는 NewVerticesMin과 NewVerticesMax 인자를 통해 새로운 최소 버텍스 수와 최대 버텍스 수를 지정할 수 있도록 해줌. 새로운 최소/최대 값은 반드시 현재의 최소/최대 버텍스 수 범위에 있어야 함 가장 중요한 메서드는 메서드의 LOD를 직접 지정할 수 있도록 해주는 SetNumFaces와 SetNumVertices 두 가지임 2009-1학기 컴퓨터게임(DirectX)

예제 애플리케이션: 프로그레시브 메쉬 프로그레시브 메쉬를 이용해 메쉬를 만들고 렌더링하므로 ID3DXPMesh 인터페이스를 이용해 메쉬를 표현 예제에 이용된 전역 변수는 Xfile 예제에 이용된 것과 거의 동일하지만 프로그레시브 메쉬를 보관하기 위한 부가적인 변수를 추가했다는 점이 다름 ID3DXMesh* SourceMesh = 0; ID3DXPMesh* PMesh = 0; // progressive mesh std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); 2009-1학기 컴퓨터게임(DirectX)

프로그레시브 메쉬를 만들기 위해서는 프로그레시브 메쉬를 생성할 원본 메쉬 데이터를 전달해야 하는데, 먼저 Xfile 데이터를 ID3DXMesh객체인 SourceMesh에 로드하고 이를 프로그레시브 메쉬 데이터를 생성해야 함 2009-1학기 컴퓨터게임(DirectX)

원본 메쉬를 얻은 뒤에는 다음과 같은 코드를 이용해 프로그레시브 메쉬를 만들어낼 수 있음 //프로그레시브 메쉬를 생성 hr = D3DXGeneratePMesh( SourceMesh, (DWORD*)adjBuffer->GetBufferPointer(), // 인접 0, // 디폴트 버텍스 속성 영향력 0, // 디폴트 버텍스 영향력 1, // 최대한 단순화 D3DXMESHSIMP_FACE, // 면의 수로 단순화 &PMesh); d3d::Release<ID3DXMesh*>(SourceMesh);//원본메쉬정리 d3d::Release<ID3DXBuffer*>(adjBuffer); //버퍼정리 2009-1학기 컴퓨터게임(DirectX)

::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0); return false; } if(FAILED(hr)) { ::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0); return false; } 이 코드는 하나의 면으로 메쉬를 단순화하도록 요청하고 있지만, 버텍스/속성 영향력에 의해 실제로 하나의 면만 남는 일은 일어나지 않음. 이제 프로그레시브 메쉬가 만들어졌지만 현재 시점에서 이를 렌더링하면 가장 낮은 해상도로 렌더링 됨. 최대 해상도로 메쉬를 렌더링할 것이므로 다음과 같은 코드를 이용해 해상도를 지정 // 원본 (최대)으로 지정 DWORD maxFaces = PMesh->GetMaxFaces(); PMesh->SetNumFaces(maxFaces); 2009-1학기 컴퓨터게임(DirectX)

Display 함수에서는 A키와 S키가 눌렸는지를 확인하고 적절하게 대응 bool Display(float timeDelta) { if( Device ) // 갱신:메쉬 해상도 // Pmesh의 현재 면수를 구함 int numFaces = PMesh->GetNumFaces(); // 면을 추가, 지정된 값이 경계를 넘는 경우 // SetNumFaces()는 자동으로 최대 값으로 고정 if( ::GetAsyncKeyState('A') & 0x8000f ) 2009-1학기 컴퓨터게임(DirectX)

//면의 수를 확실하게 늘리기 위해서는 두 개의 면을 //한번에 추가해야 할 수도 있음 PMesh->SetNumFaces( numFaces + 1 ); if( PMesh->GetNumFaces() == numFaces ) PMesh->SetNumFaces( numFaces + 2 ); } // 면을 감소시킴. 지정된 값이 경계보다 작은 경우 // SetNumFaces()는 자동으로 최소값으로 고정 if( ::GetAsyncKeyState('S') & 0x8000f ) PMesh->SetNumFaces( numFaces - 1 ); 코드는 상당히 간단하지만, 경계 상실 변환의 결과를 바꾸기 위해서는 때로 두 개의 면을 추가해야 한다는 점을 주의 2009-1학기 컴퓨터게임(DirectX)

ID3DXPMesh 객체를 렌더링하는 과정은 ID3DXMesh 객체를 렌더링할 때와 동일함. 부가적으로 노란색 재질을 이용해 메쉬의 삼각형을 노란색 외곽선으로 그려낼 수도 있음. 여기에서는 프로그레시브 메쉬의 각 삼각형이 어떻게 추가/감소되는지를 확실하게 확인할 수 있도록 이러한 와이어 프레임 모드를 이용 Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); for(int i = 0; i < Mtrls.size(); i++) { // draw pmesh Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]); PMesh->DrawSubset(i); 2009-1학기 컴퓨터게임(DirectX)

// draw wireframe outline Device->SetMaterial(&d3d::YELLOW_MTRL); Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); PMesh->DrawSubset(i); Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); } Device->EndScene(); Device->Present(0, 0, 0, 0); return true; 2009-1학기 컴퓨터게임(DirectX)

2009-1학기 컴퓨터게임(DirectX)

#include <vector> IDirect3DDevice9* Device = 0; #include "d3dUtility.h" #include <vector> IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* SourceMesh = 0; ID3DXPMesh* PMesh = 0; // progressive mesh std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); bool Setup() { HRESULT hr = 0; 2009-1학기 컴퓨터게임(DirectX)

ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; hr = D3DXLoadMeshFromX( "bigship1.x", D3DXMESH_MANAGED, Device, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &SourceMesh); if(FAILED(hr)) { 2009-1학기 컴퓨터게임(DirectX)

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } if( mtrlBuffer != 0 && numMtrls != 0 ) { D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(int i = 0; i < numMtrls; i++) // the MatD3D property doesn't have an ambient value set // when its loaded, so set it now: mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse; // save the ith material Mtrls.push_back( mtrls[i].MatD3D ); 2009-1학기 컴퓨터게임(DirectX)

// check if the ith material has an associative texture if( mtrls[i].pTextureFilename != 0 ) { // yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; D3DXCreateTextureFromFile( Device, mtrls[i].pTextureFilename, &tex); // save the loaded texture Textures.push_back( tex ); } else // no texture for the ith subset Textures.push_back( 0 ); 2009-1학기 컴퓨터게임(DirectX)

d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer } d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer hr = SourceMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), (DWORD*)adjBuffer->GetBufferPointer(), // new adjacency info 0, 0); if(FAILED(hr)) { ::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0); d3d::Release<ID3DXBuffer*>(adjBuffer); // free return false; 2009-1학기 컴퓨터게임(DirectX)

hr = D3DXGeneratePMesh( SourceMesh, (DWORD*)adjBuffer->GetBufferPointer(), // adjacency 0, // default vertex attribute weights 0, // default vertex weights 1, // simplify as low as possible D3DXMESHSIMP_FACE, // simplify by face count &PMesh); d3d::Release<ID3DXMesh*>(SourceMesh); // done w/ source mesh d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer if(FAILED(hr)) { ::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0); return false; } 2009-1학기 컴퓨터게임(DirectX)

// set to original detail DWORD maxFaces = PMesh->GetMaxFaces(); PMesh->SetNumFaces(maxFaces); // Set texture filters. Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); // Set Lights. D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f); D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f); D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col); Device->SetLight(0, &light); Device->LightEnable(0, true); 2009-1학기 컴퓨터게임(DirectX)

Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); Device->SetRenderState(D3DRS_SPECULARENABLE, true); // Set camera. D3DXVECTOR3 pos(-8.0f, 4.0f, -12.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH( &V, &pos, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); 2009-1학기 컴퓨터게임(DirectX)

// Set projection matrix. D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { d3d::Release<ID3DXPMesh*>(PMesh); 2009-1학기 컴퓨터게임(DirectX)

for(int i = 0; i < Textures.size(); i++) d3d::Release<IDirect3DTexture9*>( Textures[i] ); } bool Display(float timeDelta) { if( Device ) // Update: Mesh resolution. // Get the current number of faces the pmesh has. int numFaces = PMesh->GetNumFaces(); // Add a face, note the SetNumFaces() will automatically // clamp the specified value if it goes out of bounds. if( ::GetAsyncKeyState('A') & 0x8000f ) 2009-1학기 컴퓨터게임(DirectX)

// Sometimes we must add more than one face to invert // an edge collapse transformation PMesh->SetNumFaces( numFaces + 1 ); if( PMesh->GetNumFaces() == numFaces ) PMesh->SetNumFaces( numFaces + 2 ); } // Remove a face, note the SetNumFaces() will automatically // clamp the specified value if it goes out of bounds. if( ::GetAsyncKeyState('S') & 0x8000f ) PMesh->SetNumFaces( numFaces - 1 ); // Render Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); 2009-1학기 컴퓨터게임(DirectX)

for(int i = 0; i < Mtrls.size(); i++) { // draw pmesh Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]); PMesh->DrawSubset(i); // draw wireframe outline Device->SetMaterial(&d3d::YELLOW_MTRL); Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); } Device->EndScene(); Device->Present(0, 0, 0, 0); 2009-1학기 컴퓨터게임(DirectX)

::PostQuitMessage(0); break; case WM_KEYDOWN: return true; } LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); return ::DefWindowProc(hwnd, msg, wParam, lParam); 2009-1학기 컴퓨터게임(DirectX)

::PostQuitMessage(0); break; case WM_KEYDOWN: return true; } LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); return ::DefWindowProc(hwnd, msg, wParam, lParam); 2009-1학기 컴퓨터게임(DirectX)

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) ::MessageBox(0, "Setup() - FAILED", 0, 0); 2009-1학기 컴퓨터게임(DirectX)

d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; } 2009-1학기 컴퓨터게임(DirectX)

경계 볼륨 메쉬의 경계 볼륨을 계산할 필요가 있음. 가장 자주 이용되는 경계 볼륨의 예로는 구체와 상자를 들 수 있지만, 원기둥이나 타원면, 마름모꼴, 캡슐형 등과 같은 경계 볼륨도 존재 경계 상자/구체의 응용 분야는 다양하지만 그 중에서도 가시성 테스트와 충돌 테스트를 빼놓을 수 없음 예를 들어, 메쉬의 경계 상자/구체가 보이지 않는다면 메쉬 역시 보이지 않는다고 말할 수 있음. 상자/구체 가시성 테스트는 메쉬 내의 각 삼각형들의 가시성 테스트에 비해 훨씬 간단함 충돌 테스트의 예를 들면 장면 내에 발사된 미사일이 물체를 맞추었는지 확인하는 예를 생각해보면, 물체는 삼각형들로 구성되므로 물체를 이루는 각각의 삼각형들을 대상으로 미사일과 충돌했는지 확인해야 함 2009-1학기 컴퓨터게임(DirectX)

이 방법은 하나의 물체에 대해서 상당히 많은 광선/삼각형 교차 테스트를 필요로 함 만약 각 메쉬의 경계 상자/구체를 계산하고 각 물체에 대해 한 번씩만 광선/상자 혹은 광선/구체 교차 테스트만을 수행한다면 훨씬 높은 효율을 얻을 수 있음 D3DX 라이브러리는 메쉬의 경계 상자와 경계 구체를 계산하는 함수를 제공. 이 함수들은 버텍스의 배열을 입력 인자로 받고 경계 볼륨을 계산해냄 2009-1학기 컴퓨터게임(DirectX)

이들 함수는 높은 유연성을 가지도록 디자인되었으며 다양한 버텍스 포맷을 이용할 수 있음 HRESULT D3DXComputeBoundingSphere( LPD3DXVECTOR3 pFirstPosition, DWORD NumVertices, DWORD dwStride, D3DXVECTOR3* pCenter, FLOAT* pRadius); pFirstPosition – 버텍스들의 위치를 나타내는 버텍스 배열의 첫번째 버텍스 벡터를 가리키는 포인터 NumVertices – 버텍스 배열 내 버텍스의 수 dwStride – 바이트 단위의 버텍스 크기. 버텍스 구조에는 법선 벡터나 텍스처 좌표와 같이 경계 구체 계산에 불필요한 부가 정보가 포함될 수 있으므로 다음 버텍스 위치로 이동하기 위해 건너뛸 데이터의 양을 결정하는데 이 정보가 이용됨 pRadius – 경계 구체의 반지름을 리턴 2009-1학기 컴퓨터게임(DirectX)

HRESULT D3DXComputeBoundingBox( LPD3DXVECTOR3 pFirstPosition, DWORD NumVertices, DWORD dwStride, D3DXVECTOR3* pMin, D3DXVECTOR3* pMax, ); 처음의 세 인자는 D3DXComputeBoundingSphere의 세 인자와 완전히 동일하며, 뒷부분의 두 인자는 경계 상자의 최소점과 최대점을 리턴 2009-1학기 컴퓨터게임(DirectX)

몇 가지 새로운 특수 상수 namespace d3d { … const float INFINITY = FLT_MAX; const float EPSILON = 0.001f; 2009-1학기 컴퓨터게임(DirectX)

INFINITY 상수는 float에 저장할 수 있는 가장 큰 수를 나타냄. FLT_MAX보다 큰 float은 존재할 수 없으므로 이를 무한이라는 개념으로 정의. 이로서 좀 더 이해하기 쉬운 코드가 만들어지며 무한이라는 개념을 확실하게 표현 할 수 있게 됨 EPSILON 상수는 매우 작아서 0과 같은 것으로 취급할 수 있는 값을 의미. 이와 같은 의미가 필요한 이유는 부동 소수점의 부정확성 때문으로, 0이 되어야 할 값이 조금 벗어난 값이 될 수 있기 때문에 직접 0과 비교하면 의도와는 다른 결과를 얻으므로 0과 비교하는 대신 EPSILON보다 작은지를 검사하는 방법이 이용 다음의 함수는 두 부동 소수점 값이 같은지를 검사하는 데 EPSILON을 이용하는 예를 보여줌 2009-1학기 컴퓨터게임(DirectX)

bool Equals(float lhs, float rhs) { // 만약 lhs == rhs라면 두 값의 차이는 0이어야 함 return fabs(lhs-rhs) < EPSILON ? true : false; } 2009-1학기 컴퓨터게임(DirectX)

경계 볼륨 형 경계 구체와 경계 볼륨을 이용하는 작업을 원활히 하기 위해서는 이들을 클래스로 구현하는 것이 자연스러움 이들 클래스를 d3d 네임스페이스 내에 구현하는 방법은 다음과 같음 struct BoundingBox { BoundingBox(); bool isPointInside(D3DXVECTOR3& p); D3DXVECTOR3 _min; D3DXVECTOR3 _max; }; 2009-1학기 컴퓨터게임(DirectX)

struct BoundingSphere { BoundingSphere(); D3DXVECTOR3 _center; float _radius; }; d3d::BoundingBox::BoundingBox() // infinite small _min.x = d3d::INFINITY; _min.y = d3d::INFINITY; _min.z = d3d::INFINITY; 2009-1학기 컴퓨터게임(DirectX)

_max.x = -d3d::INFINITY; _max.y = -d3d::INFINITY; _max.z = -d3d::INFINITY; } bool d3d::BoundingBox::isPointInside(D3DXVECTOR3& p) { if( p.x >= _min.x && p.y >= _min.y && p.z >= _min.z && p.x <= _max.x && p.y <= _max.y && p.z <= _max.z ) return true; else return false; 2009-1학기 컴퓨터게임(DirectX)

d3d::BoundingSphere::BoundingSphere() { _radius = 0.0f; } d3d::BoundingSphere::BoundingSphere() { _radius = 0.0f; 2009-1학기 컴퓨터게임(DirectX)

예제 애플리케이션: 경계 볼륨 D3DXComputeBoundingSphere와 D3DXComputeBoundingBox 이용 방법을 보여주는 바운딩 볼륨 예제는 단원 예제 폴더에 포함되어 있음 이 프로그램은 Xfile을 로드하고 메쉬와 경계 구체를 계산하여, 이어 경계 구체와 경계 상자를 위한 두 개의 ID3DXMesh 객체를 만든다 읽어들인 Xfile의 메쉬와 대응되는 경계 구체나 경계 상자가 출력되며 사용자는 스페이스 키를 이용해 경계 구체와 경계 상자 사이를 전환할 수 있음 다음은 메쉬의 경계 구체와 경계 상자를 계산해내는 두 함수의 소스 코드임 2009-1학기 컴퓨터게임(DirectX)

mesh->LockVertexBuffer(0, (void**)&v); bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere) { HRESULT hr = 0; BYTE* v = 0; mesh->LockVertexBuffer(0, (void**)&v); hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)v, mesh->GetNumVertices(), D3DXGetFVFVertexSize(mesh->GetFVF()), &sphere->_center, &sphere->_radius); mesh->UnlockVertexBuffer(); 2009-1학기 컴퓨터게임(DirectX)

bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box) { if( FAILED(hr) ) return false; return true; } bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box) { HRESULT hr = 0; BYTE* v = 0; mesh->LockVertexBuffer(0, (void**)&v); hr = D3DXComputeBoundingBox( (D3DXVECTOR3*)v, mesh->GetNumVertices(), 2009-1학기 컴퓨터게임(DirectX)

D3DXGetFVFVertexSize(mesh->GetFVF()), &box->_min, &box->_max); mesh->UnlockVertexBuffer(); if( FAILED(hr) ) return false; return true; } 이 코드에서 (D3DXVECTOR3*) v는 우리가 이용하는 버텍스 구조체의 시작에 버텍스 위치 속성이 보관되어 있다고 가정하고 있음. 주어진 버텍스 포맷 정보에서 버텍스 구조체의 크기를 얻으려면 D3DXGetFVFVertexSize 함수를 이용 2009-1학기 컴퓨터게임(DirectX)

2009-1학기 컴퓨터게임(DirectX)

#include <vector> IDirect3DDevice9* Device = 0; #include "d3dUtility.h" #include <vector> IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Mesh = 0; std::vector<D3DMATERIAL9> Mtrls(0); std::vector<IDirect3DTexture9*> Textures(0); ID3DXMesh* SphereMesh = 0; ID3DXMesh* BoxMesh = 0; bool RenderBoundingSphere = true; 2009-1학기 컴퓨터게임(DirectX)

bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box); bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere); bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box); bool Setup() { HRESULT hr = 0; // // Load the XFile data. ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; hr = D3DXLoadMeshFromX( "bigship1.x", 2009-1학기 컴퓨터게임(DirectX)

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } D3DXMESH_MANAGED, Device, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &Mesh); if(FAILED(hr)) { ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0); return false; } if( mtrlBuffer != 0 && numMtrls != 0 ) D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); 2009-1학기 컴퓨터게임(DirectX)

for(int i = 0; i < numMtrls; i++) { // the MatD3D property doesn't have an ambient value set // when its loaded, so set it now: mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse; // save the ith material Mtrls.push_back( mtrls[i].MatD3D ); // check if the ith material has an associative texture if( mtrls[i].pTextureFilename != 0 ) // yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; D3DXCreateTextureFromFile( Device, mtrls[i].pTextureFilename, &tex); 2009-1학기 컴퓨터게임(DirectX)

// save the loaded texture Textures.push_back( tex ); } else { // no texture for the ith subset Textures.push_back( 0 ); d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer hr = Mesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0); 2009-1학기 컴퓨터게임(DirectX)

d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer if(FAILED(hr)) { ::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0); return false; } // Compute Bounding Sphere and Bounding Box. d3d::BoundingSphere boundingSphere; d3d::BoundingBox boundingBox; ComputeBoundingSphere(Mesh, &boundingSphere); ComputeBoundingBox(Mesh, &boundingBox); D3DXCreateSphere( Device, 2009-1학기 컴퓨터게임(DirectX)

boundingSphere._radius, 20, &SphereMesh, 0); D3DXCreateBox( Device, boundingBox._max.x - boundingBox._min.x, boundingBox._max.y - boundingBox._min.y, boundingBox._max.z - boundingBox._min.z, &BoxMesh, Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 2009-1학기 컴퓨터게임(DirectX)

Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f); D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f); D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col); Device->SetLight(0, &light); Device->LightEnable(0, true); Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); Device->SetRenderState(D3DRS_SPECULARENABLE, true); D3DXVECTOR3 pos(4.0f, 12.0f, -20.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); 2009-1학기 컴퓨터게임(DirectX)

Device->SetTransform(D3DTS_VIEW, &V); D3DXMATRIX proj; D3DXMATRIX V; D3DXMatrixLookAtLH( &V, &pos, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); 2009-1학기 컴퓨터게임(DirectX)

d3d::Release<ID3DXMesh*>(Mesh); return true; } void Cleanup() { d3d::Release<ID3DXMesh*>(Mesh); for(int i = 0; i < Textures.size(); i++) d3d::Release<IDirect3DTexture9*>( Textures[i] ); d3d::Release<ID3DXMesh*>(SphereMesh); d3d::Release<ID3DXMesh*>(BoxMesh); bool Display(float timeDelta) if( Device ) 2009-1학기 컴퓨터게임(DirectX)

D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) static float y = 0.0f; D3DXMATRIX yRot; D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) y = 0.0f; D3DXMATRIX World = yRot; Device->SetTransform(D3DTS_WORLD, &World); // Render Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); 2009-1학기 컴퓨터게임(DirectX)

for(int i = 0; i < Mtrls.size(); i++) { // draw the mesh for(int i = 0; i < Mtrls.size(); i++) { Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]); Mesh->DrawSubset(i); } // Draw bounding volume in blue and at 10% opacity D3DMATERIAL9 blue = d3d::BLUE_MTRL; blue.Diffuse.a = 0.10f; // 10% opacity Device->SetMaterial(&blue); Device->SetTexture(0, 0); // disable texture Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 2009-1학기 컴퓨터게임(DirectX)

Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); if( RenderBoundingSphere ) SphereMesh->DrawSubset(0); else BoxMesh->DrawSubset(0); Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 2009-1학기 컴퓨터게임(DirectX)

::PostQuitMessage(0); break; case WM_KEYDOWN: { switch( msg ) case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); if( wParam == VK_SPACE ) RenderBoundingSphere = !RenderBoundingSphere; } return ::DefWindowProc(hwnd, msg, wParam, lParam); 2009-1학기 컴퓨터게임(DirectX)

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) ::MessageBox(0, "Setup() - FAILED", 0, 0); 2009-1학기 컴퓨터게임(DirectX)

d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; } bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere) { HRESULT hr = 0; BYTE* v = 0; mesh->LockVertexBuffer(0, (void**)&v); 2009-1학기 컴퓨터게임(DirectX)

hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)v, mesh->GetNumVertices(), D3DXGetFVFVertexSize(mesh->GetFVF()), &sphere->_center, &sphere->_radius); mesh->UnlockVertexBuffer(); if( FAILED(hr) ) return false; return true; } bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box) { 2009-1학기 컴퓨터게임(DirectX)

mesh->LockVertexBuffer(0, (void**)&v); hr = D3DXComputeBoundingBox( HRESULT hr = 0; BYTE* v = 0; mesh->LockVertexBuffer(0, (void**)&v); hr = D3DXComputeBoundingBox( (D3DXVECTOR3*)v, mesh->GetNumVertices(), D3DXGetFVFVertexSize(mesh->GetFVF()), &box->_min, &box->_max); mesh->UnlockVertexBuffer(); if( FAILED(hr) ) return false; return true; } 2009-1학기 컴퓨터게임(DirectX)