105
2010-1 2010-1 학학 학학 학학학학학 학학학학학 (DirectX) (DirectX) 1 11 11 학학 학학 학학 학학 II II

11 장 메쉬 파트 II

Embed Size (px)

DESCRIPTION

11 장 메쉬 파트 II. 11 장 내용. D3DX 라이브러리가 제공하는 메쉬 관련 인터페이스 , 구조체 , 함수들 Xfile 데이터를 ID3DXMesh 객체로 읽어들이는 방법 프로그레시브 메쉬를 이용하여 얻을 수 있는 이점 및 프로그레시브 메쉬 인터페이스 ID3DXPMesh 이용 방법 경계볼륨의 정체와 용도 및 D3DX 함수. ID3DXBuffer. - PowerPoint PPT Presentation

Citation preview

Page 1: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 11

1111 장 메쉬 파트장 메쉬 파트 IIII

Page 2: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 22

1111 장 내용장 내용 D3DX D3DX 라이브러리가 제공하는 메쉬 관련 인터페이스라이브러리가 제공하는 메쉬 관련 인터페이스 , , 구조체구조체 , ,

함수들함수들 Xfile Xfile 데이터를 데이터를 ID3DXMesh ID3DXMesh 객체로 읽어들이는 방법객체로 읽어들이는 방법 프로그레시브 메쉬를 이용하여 얻을 수 있는 이점 및 프로그레시브 프로그레시브 메쉬를 이용하여 얻을 수 있는 이점 및 프로그레시브

메쉬 인터페이스 메쉬 인터페이스 ID3DXPMesh ID3DXPMesh 이용 방법이용 방법 경계볼륨의 정체와 용도 및 경계볼륨의 정체와 용도 및 D3DX D3DX 함수함수

Page 3: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 33

ID3DXBufferID3DXBuffer

ID3DXBuffer ID3DXBuffer 인터페이스는 인터페이스는 D3DXD3DX 가 가 연속적인 메모리 블록에 연속적인 메모리 블록에 데이터를 저장하기 위해 이용하는 범용 데이터 구조체로데이터를 저장하기 위해 이용하는 범용 데이터 구조체로 , , 다음과 다음과 같은 두 개의 메서드를 가짐같은 두 개의 메서드를 가짐• LPVOID GetBufferPointer(); - LPVOID GetBufferPointer(); - 데이터의 시작을 가리키는 데이터의 시작을 가리키는

포인터를 리턴포인터를 리턴• DWORD GetBufferSize(); - DWORD GetBufferSize(); - 버퍼 크기를 바이트 수로 리턴버퍼 크기를 바이트 수로 리턴

구조체의 범용성을 유지하기 위해 포인터를 한다는 것은 저장되는 구조체의 범용성을 유지하기 위해 포인터를 한다는 것은 저장되는 데이터의 형을 우리가 관리해야 함을 의미데이터의 형을 우리가 관리해야 함을 의미

예를 들어예를 들어 , D3DXLoadMeshFromX, D3DXLoadMeshFromX 는 는 • 메쉬의 인접 정보를 리턴하기 위해 메쉬의 인접 정보를 리턴하기 위해 ID3DXBufferID3DXBuffer 를 이용하는를 이용하는

데데 , , • 인접 정보는 인접 정보는 DWORD DWORD 배열이므로 버퍼의 인접 정보를 이용하기 배열이므로 버퍼의 인접 정보를 이용하기

위해서는 우선 버퍼를 위해서는 우선 버퍼를 DWORD DWORD 배열로 형 변환해야 함배열로 형 변환해야 함

Page 4: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 44

예예 ::• DWORD* info = (DWORD*)adjacencyInfo->GetBufferPointer();DWORD* info = (DWORD*)adjacencyInfo->GetBufferPointer();

D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer-D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();>GetBufferPointer();

ID3DXBufferID3DXBuffer 는 는 COMCOM 객체이므로 이용이 끝난 뒤에는 메모리 누출을 객체이므로 이용이 끝난 뒤에는 메모리 누출을 막기 위해 반드시 객체를 풀어주어야 함막기 위해 반드시 객체를 풀어주어야 함• adjacencyInfo->Release();adjacencyInfo->Release();

mtrlBuffer->Release();mtrlBuffer->Release();

다음과 같은 함수를 이용하면 빈 다음과 같은 함수를 이용하면 빈 ID3DXBufferID3DXBuffer 를 만들 수 있음를 만들 수 있음• HRESULT D3DXCreateBuffer(HRESULT D3DXCreateBuffer(

DWORD NumBytes, //DWORD NumBytes, // 버퍼의 크기버퍼의 크기 , , 바이트 단위바이트 단위 LPD3DXBUFFER *ppBuffer //LPD3DXBUFFER *ppBuffer // 생성된 버퍼를 리턴생성된 버퍼를 리턴););

Page 5: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 55

다음의 예는 네 개의 정수를 보관할 수 있는 버퍼를 만드는 것다음의 예는 네 개의 정수를 보관할 수 있는 버퍼를 만드는 것

• ID3DXBuffer* buffer=0;ID3DXBuffer* buffer=0;• D3DXCreateBuffer(4*sizeof(int),&buffer);D3DXCreateBuffer(4*sizeof(int),&buffer);

Page 6: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 66

XfileXfile

3D 3D 물체 데이터를 구성하는 지루한 작업을 도와주기 위해 물체 데이터를 구성하는 지루한 작업을 도와주기 위해 3D 3D 모델러라 불리는 특수한 애플리케이션들이 개발되었는데모델러라 불리는 특수한 애플리케이션들이 개발되었는데 , , 이 이 모델러들은 다양한 툴셋과 시각적이고 인터랙티브한 환경을 통해 모델러들은 다양한 툴셋과 시각적이고 인터랙티브한 환경을 통해 더욱 쉽고 빠르게 모델링을 수행할 수 있도록 해줌더욱 쉽고 빠르게 모델링을 수행할 수 있도록 해줌

게임 개발에 자주 이용되는 모델러로는 게임 개발에 자주 이용되는 모델러로는 3DS MAX3DS MAX 나 나 LightWave LightWave 3D, Maya 3D, Maya 등이 있음등이 있음

이 모델러들은 만들어진 메쉬 데이터는 파일로 저장할 수 있으며이 모델러들은 만들어진 메쉬 데이터는 파일로 저장할 수 있으며 ,,따라서 메쉬 데이터를 추출하는 파일 리더를 만든다면 이 데이터를 따라서 메쉬 데이터를 추출하는 파일 리더를 만든다면 이 데이터를 우리의 우리의 3D 3D 애플리케이션에서 이용할 수 있음애플리케이션에서 이용할 수 있음

Page 7: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 77

Xfile Xfile 포맷이라 불리는 특수한 메쉬 파일 포맷은 대부분의 포맷이라 불리는 특수한 메쉬 파일 포맷은 대부분의 3D 3D 모델러들이 이 포맷으로 저장하는 기능을 가지고 있으며모델러들이 이 포맷으로 저장하는 기능을 가지고 있으며 , , 기존의 기존의 메쉬 파일 포맷을 메쉬 파일 포맷을 .X.X 로 변환하는 변환기도 만들어져 있음로 변환하는 변환기도 만들어져 있음

XfileXfile 의 장점은 의 장점은 DirectXDirectX 가 이 파일 포맷을 정의하고 있다는 것가 이 파일 포맷을 정의하고 있다는 것 . . 이 이 때문에 때문에 XfileXfile 은 별다른 준비 과정 없이 은 별다른 준비 과정 없이 D3DX D3DX 라이브러리에서 라이브러리에서 이용이 가능하며이용이 가능하며 , , 라이브러리 자체에서 라이브러리 자체에서 XfileXfile 을 읽고 저장하는 을 읽고 저장하는 함수들을 제공함수들을 제공

Page 8: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 88

Xfile Xfile 읽어들이기읽어들이기 다음의 함수를 이용해 다음의 함수를 이용해 XfileXfile 에 보관된 메쉬 데이터를 읽어들일 수 에 보관된 메쉬 데이터를 읽어들일 수

있음있음 이 메서드는 이 메서드는 ID3DXMesh ID3DXMesh 객체를 만들고 여기에 객체를 만들고 여기에 XfileXfile 의 기하정보 의 기하정보

데이터를 읽음데이터를 읽음 HRESULT D3DXLoadMeshFromX(HRESULT D3DXLoadMeshFromX(

LPCSTR pFilename,LPCSTR pFilename,

DWORD Options,DWORD Options,

LPDIRECT3DDEVICE9 pDevice,LPDIRECT3DDEVICE9 pDevice,

LPD3DXBUFFER *ppAdjacency,LPD3DXBUFFER *ppAdjacency,

LPD3DXBUFFER *ppMaterials,LPD3DXBUFFER *ppMaterials,

LPD3DXBUFFER *ppEffectInstances,LPD3DXBUFFER *ppEffectInstances,

PDWORD pNumMaterials,PDWORD pNumMaterials,

LPD3DXMESH *ppMesh);LPD3DXMESH *ppMesh);

Page 9: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 99

• pFilename pFilename –– 읽어들이고자 하는 읽어들이고자 하는 XfileXfile 의 파일명의 파일명• Options Options –– 메쉬를 만드는 데 이용될 하나 이상의 생성 플래그메쉬를 만드는 데 이용될 하나 이상의 생성 플래그

D3DXMESH_32BIT D3DXMESH_32BIT –– 메쉬는 메쉬는 3232 비트 인덱스를 이용하게 비트 인덱스를 이용하게 됨됨

D3DXMESH_MANAGED D3DXMESH_MANAGED –– 메쉬는 관리 메모리 풀 내에 메쉬는 관리 메모리 풀 내에 보관보관

D3DXMESH_WRITEONLY D3DXMESH_WRITEONLY –– 메쉬 데이터에는 쓰기만 허용메쉬 데이터에는 쓰기만 허용 D3DXMESH_DYNAMIC D3DXMESH_DYNAMIC –– 메쉬 버퍼는 동적으로 만들어짐메쉬 버퍼는 동적으로 만들어짐

Page 10: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1010

• pDevice pDevice –– 메쉬와 연계될 장치메쉬와 연계될 장치• ppAdjacency ppAdjacency –– 메쉬 접근 정보를 위한 메쉬 접근 정보를 위한 DWORD DWORD 배열을 배열을

포함하는 포함하는 ID3DXBufferID3DXBuffer 를 리턴를 리턴• ppMaterials ppMaterials –– 메쉬 재질 정보를 위한 메쉬 재질 정보를 위한 D3DXMATERIAL D3DXMATERIAL

구조체 배열을 포함하는 구조체 배열을 포함하는 ID3DXBufferID3DXBuffer 를 리턴를 리턴• ppEffectInstances ppEffectInstances –– D3DXEFFECTINSTANCE D3DXEFFECTINSTANCE 구조체 배열을 구조체 배열을

포함하는 포함하는 ID3DXBufferID3DXBuffer 를 리턴를 리턴 . . 현재로서는 현재로서는 00 을 지정하여 이 을 지정하여 이 인자를 무시인자를 무시

• pNumMaterials pNumMaterials –– 메쉬의 재질 수를 리턴메쉬의 재질 수를 리턴• ppMesh ppMesh –– Xfile Xfile 기하정보로 채워진 기하정보로 채워진 ID3DXMesh ID3DXMesh 객체를 리턴객체를 리턴

Page 11: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1111

Xfile Xfile 재질재질

D3DXLoadMeshFromX D3DXLoadMeshFromX 함수의 일곱 번째 인자는 메쉬가 포함하는 함수의 일곱 번째 인자는 메쉬가 포함하는 재질의 수를 리턴하며 다섯 번째 인자는 재질 데이터를 포함하는 재질의 수를 리턴하며 다섯 번째 인자는 재질 데이터를 포함하는 D3DXMATERIAL D3DXMATERIAL 구조체 배열을 리턴구조체 배열을 리턴

D3DXMATERIAL D3DXMATERIAL 구조체는 다음과 같이 정의구조체는 다음과 같이 정의typedef struct D3DXMATERIAL {typedef struct D3DXMATERIAL {

D3DMATERIAL9 MatD3D;D3DMATERIAL9 MatD3D;

LPSTR pTextureFilename;LPSTR pTextureFilename;

} D3DXMATERIAL;} D3DXMATERIAL;

이는 비교적 단순한 구조체로이는 비교적 단순한 구조체로 , , 기본적인 기본적인 D3DMATERIAL9 D3DMATERIAL9 구조체와 연결된 텍스처 파일명을 지정하는 구조체와 연결된 텍스처 파일명을 지정하는 null-null- 종료 문자열로의 종료 문자열로의 포인터를 포함포인터를 포함

Page 12: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1212

XfileXfile 은 텍스처 데이터를 직접 포함하지 않으며 실제 텍스처 은 텍스처 데이터를 직접 포함하지 않으며 실제 텍스처 데이터를 포함하는 이미지 파일로의 파일명을 포함데이터를 포함하는 이미지 파일로의 파일명을 포함 . . 즉즉 , , D3DXLoadMeshFromXD3DXLoadMeshFromX 를 이용해 를 이용해 XfileXfile 을 일어들인 다음에는 을 일어들인 다음에는 알아낸 텍스처 파일명으로 텍스처 데이터를 읽어들여야 함알아낸 텍스처 파일명으로 텍스처 데이터를 읽어들여야 함

D3DXLoadMeshFromXD3DXLoadMeshFromX 함수는 리턴된 함수는 리턴된 D3DXMATERIAL D3DXMATERIAL 배열의 배열의 ii 번째 항목이 번째 항목이 ii 번째 서브셋과 대응되도록 번째 서브셋과 대응되도록 Xfile Xfile 데이터를 읽어들임데이터를 읽어들임

Page 13: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1313

예제 애플리케이션예제 애플리케이션 : Xfile: Xfile

이 예제는 다음과 같은 전역 변수를 이용이 예제는 다음과 같은 전역 변수를 이용

• ID3DXMesh* Mesh = 0;ID3DXMesh* Mesh = 0;

std::vector<D3DMATERIAL9> Mtrls(0);std::vector<D3DMATERIAL9> Mtrls(0);

std::vector<IDirect3DTexture9*> Textures(0);std::vector<IDirect3DTexture9*> Textures(0);

• 첫 번째 변수인 첫 번째 변수인 ID3DXMesh ID3DXMesh 객체는 객체는 XfileXfile 에서 읽어들인 메쉬 에서 읽어들인 메쉬 데이터를 보관하는데 이용데이터를 보관하는데 이용 . . 두 번째와 세 번째 변수는 각각 두 번째와 세 번째 변수는 각각 재질과 텍스처의 벡터이며재질과 텍스처의 벡터이며 , , 메쉬의 재질과 텍스처를 보관하는데 메쉬의 재질과 텍스처를 보관하는데 이용이용

Page 14: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1414

예제는 먼저 표준인 예제는 먼저 표준인 Setup Setup 함수를 구현하였는데 여기서 함수를 구현하였는데 여기서 XfileXfile 을 을 읽어들이는 작업이 이루어짐읽어들이는 작업이 이루어짐

• HRESULT hr = 0;HRESULT hr = 0;// Load the XFile data.// Load the XFile data.ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;DWORD numMtrls = 0;DWORD numMtrls = 0;hr = D3DXLoadMeshFromX( hr = D3DXLoadMeshFromX( "bigship1.x","bigship1.x", D3DXMESH_MANAGED,D3DXMESH_MANAGED, Device,Device, &adjBuffer,&adjBuffer, &mtrlBuffer,&mtrlBuffer, 0,0, &numMtrls,&numMtrls,

Page 15: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1515

&Mesh);&Mesh); if(FAILED(hr))if(FAILED(hr)) {{ ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);0);

return false;return false; }}

이어 이어 XfileXfile 의 실제 데이터를 읽어들임의 실제 데이터를 읽어들임 . . 여기에서는 여기에서는 D3DXMATERIAL D3DXMATERIAL 배열을 대상으로 반복하여 메쉬가 참조하는 배열을 대상으로 반복하여 메쉬가 참조하는 텍스처를 읽어들여야 함텍스처를 읽어들여야 함

• // Extract the materials, and load textures.// Extract the materials, and load textures.

if( mtrlBuffer != 0 && numMtrls != 0 )if( mtrlBuffer != 0 && numMtrls != 0 ){{

Page 16: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1616

D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer-D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();>GetBufferPointer();

for(int i = 0; i < numMtrls; i++)for(int i = 0; i < numMtrls; i++){{

// the MatD3D property doesn't have an ambient value set// the MatD3D property doesn't have an ambient value set// when its loaded, so set it now:// when its loaded, so set it now:mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;

// save the ith material// save the ith materialMtrls.push_back( mtrls[i].MatD3D );Mtrls.push_back( mtrls[i].MatD3D );// check if the ith material has an associative texture// check if the ith material has an associative textureif( mtrls[i].pTextureFilename != 0 )if( mtrls[i].pTextureFilename != 0 ){{

// yes, load the texture for the ith subset// yes, load the texture for the ith subsetIDirect3DTexture9* tex = 0;IDirect3DTexture9* tex = 0;

Page 17: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1717

D3DXCreateTextureFromFile(D3DXCreateTextureFromFile(Device,Device,mtrls[i].pTextureFilename,mtrls[i].pTextureFilename,&tex);&tex);

// save the loaded texture// save the loaded textureTextures.push_back( tex );Textures.push_back( tex );

}}elseelse{{

// no texture for the ith subset// no texture for the ith subsetTextures.push_back( 0 );Textures.push_back( 0 );

} } }}}}d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer

Page 18: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1818

.. .//.// 단원과 관련이 없는 코드는 생략 단원과 관련이 없는 코드는 생략 .. return 0;return 0;}//Setup() }//Setup() 종료종료

Display Display 함수에서는 매 프레임마다 메쉬를 조금씩 회전하도록 함함수에서는 매 프레임마다 메쉬를 조금씩 회전하도록 함 . . 메쉬 메쉬 내의 서브셋들은 내의 서브셋들은 0, 1, 2, 0, 1, 2, ……, n-1 , n-1 형식으로 번호가 매겨져 있으므로 매우 형식으로 번호가 매겨져 있으므로 매우 간단한 루프를 이용해 전체 메쉬를 렌더링할 수 있음간단한 루프를 이용해 전체 메쉬를 렌더링할 수 있음• bool Display(float timeDelta)bool Display(float timeDelta)

{{ if( Device )if( Device )

{{ static float y = 0.0f;static float y = 0.0f; D3DXMATRIX yRot;D3DXMATRIX yRot;

Page 19: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 1919

D3DXMatrixRotationY(&yRot, y);D3DXMatrixRotationY(&yRot, y);y += timeDelta;y += timeDelta;

if( y >= 6.28f )if( y >= 6.28f ) y = 0.0f;y = 0.0f;

D3DXMATRIX World = yRot;D3DXMATRIX World = yRot;

Device->SetTransform(D3DTS_WORLD, &World);Device->SetTransform(D3DTS_WORLD, &World);

// Render// Render

Device->Clear(0, 0, D3DCLEAR_TARGET | Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);Device->BeginScene();Device->BeginScene();

Page 20: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2020

for(int i = 0; i < Mtrls.size(); i++)for(int i = 0; i < Mtrls.size(); i++){{

Device->SetMaterial( &Mtrls[i] );Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]);Device->SetTexture(0, Textures[i]); Mesh->DrawSubset(i);Mesh->DrawSubset(i);}}

Device->EndScene();Device->EndScene();Device->Present(0, 0, 0, 0);Device->Present(0, 0, 0, 0);

}} return true;return true;}}

Page 21: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2121

Page 22: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2222

#include "d3dUtility.h"#include "d3dUtility.h"#include <vector>#include <vector>

IDirect3DDevice9* Device = 0; IDirect3DDevice9* Device = 0;

const int Width = 640;const int Width = 640;const int Height = 480;const int Height = 480;

ID3DXMesh* Mesh = 0;ID3DXMesh* Mesh = 0;std::vector<D3DMATERIAL9> Mtrls(0);std::vector<D3DMATERIAL9> Mtrls(0);std::vector<IDirect3DTexture9*> Textures(0);std::vector<IDirect3DTexture9*> Textures(0);

bool Setup()bool Setup(){{

HRESULT hr = 0;HRESULT hr = 0;

ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* adjBuffer = 0;

Page 23: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2323

ID3DXBuffer* mtrlBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;DWORD numMtrls = 0;DWORD numMtrls = 0;

hr = D3DXLoadMeshFromX( hr = D3DXLoadMeshFromX( "bigship1.x","bigship1.x",D3DXMESH_MANAGED,D3DXMESH_MANAGED,Device,Device,&adjBuffer,&adjBuffer,&mtrlBuffer,&mtrlBuffer,0,0,&numMtrls,&numMtrls,&Mesh);&Mesh);

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);return false;return false;

}}

Page 24: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2424

if( mtrlBuffer != 0 && numMtrls != 0 )if( mtrlBuffer != 0 && numMtrls != 0 ){{

D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer-D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();>GetBufferPointer();

for(int i = 0; i < numMtrls; i++)for(int i = 0; i < numMtrls; i++){{

// the MatD3D property doesn't have an ambient value // the MatD3D property doesn't have an ambient value setset

// when its loaded, so set it now:// when its loaded, so set it now:mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;

// save the ith material// save the ith materialMtrls.push_back( mtrls[i].MatD3D );Mtrls.push_back( mtrls[i].MatD3D );

// check if the ith material has an associative texture// check if the ith material has an associative textureif( mtrls[i].pTextureFilename != 0 )if( mtrls[i].pTextureFilename != 0 ){{

Page 25: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2525

// yes, load the texture for the ith subset// yes, load the texture for the ith subsetIDirect3DTexture9* tex = 0;IDirect3DTexture9* tex = 0;D3DXCreateTextureFromFile(D3DXCreateTextureFromFile(

Device,Device,mtrls[i].pTextureFilename,mtrls[i].pTextureFilename,&tex);&tex);

// save the loaded texture// save the loaded textureTextures.push_back( tex );Textures.push_back( tex );

}}elseelse{{

// no texture for the ith subset// no texture for the ith subsetTextures.push_back( 0 );Textures.push_back( 0 );

}}}}

}}d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer

Page 26: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2626

hr = Mesh->OptimizeInplace(hr = Mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_COMPACT |D3DXMESHOPT_COMPACT |D3DXMESHOPT_VERTEXCACHE,D3DXMESHOPT_VERTEXCACHE,(DWORD*)adjBuffer->GetBufferPointer(),(DWORD*)adjBuffer->GetBufferPointer(),0, 0, 0);0, 0, 0);

d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);return false;return false;

}}

Page 27: 11 장   메쉬  파트 II

Device->SetSamplerState(0, D3DSAMP_MAGFILTER, Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);D3DTEXF_LINEAR);

Device->SetSamplerState(0, D3DSAMP_MINFILTER, Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);D3DTEXF_LINEAR);

Device->SetSamplerState(0, D3DSAMP_MIPFILTER, Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);D3DTEXF_POINT);

// //

// Set Lights.// Set Lights.

////

D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);

D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);

D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2727

Page 28: 11 장   메쉬  파트 II

Device->SetLight(0, &light);Device->SetLight(0, &light);

Device->LightEnable(0, true);Device->LightEnable(0, true);

Device->SetRenderState(D3DRS_NORMALIZENORMALS, Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);true);

Device->SetRenderState(D3DRS_SPECULARENABLE, true);Device->SetRenderState(D3DRS_SPECULARENABLE, true);

////

// Set camera.// Set camera.

////

D3DXVECTOR3 pos(4.0f, 4.0f, -13.0f);D3DXVECTOR3 pos(4.0f, 4.0f, -13.0f);

D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);

D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2828

Page 29: 11 장   메쉬  파트 II

D3DXMATRIX V;D3DXMATRIX V;D3DXMatrixLookAtLH(D3DXMatrixLookAtLH(

&V,&V,&pos,&pos,&target,&target,&up);&up);

Device->SetTransform(D3DTS_VIEW, &V);Device->SetTransform(D3DTS_VIEW, &V);

D3DXMATRIX proj;D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(D3DXMatrixPerspectiveFovLH(

&proj,&proj,D3DX_PI * 0.5f, // 90 - degreeD3DX_PI * 0.5f, // 90 - degree(float)Width / (float)Height,(float)Width / (float)Height,1.0f,1.0f,1000.0f);1000.0f);

Device->SetTransform(D3DTS_PROJECTION, &proj);Device->SetTransform(D3DTS_PROJECTION, &proj);2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 2929

Page 30: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3030

return true;return true;}}

void Cleanup()void Cleanup(){{

d3d::Release<ID3DXMesh*>(Mesh);d3d::Release<ID3DXMesh*>(Mesh);

for(int i = 0; i < Textures.size(); i++)for(int i = 0; i < Textures.size(); i++)d3d::Release<IDirect3DTexture9*>( Textures[i] );d3d::Release<IDirect3DTexture9*>( Textures[i] );

}}

bool Display(float timeDelta)bool Display(float timeDelta){{

if( Device )if( Device ){{

static float y = 0.0f;static float y = 0.0f;D3DXMATRIX yRot;D3DXMATRIX yRot;

Page 31: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3131

D3DXMatrixRotationY(&yRot, y);D3DXMatrixRotationY(&yRot, y);y += timeDelta;y += timeDelta;

if( y >= 6.28f )if( y >= 6.28f )y = 0.0f;y = 0.0f;

D3DXMATRIX World = yRot;D3DXMATRIX World = yRot;

Device->SetTransform(D3DTS_WORLD, &World);Device->SetTransform(D3DTS_WORLD, &World);

Device->Clear(0, 0, D3DCLEAR_TARGET | Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);

Device->BeginScene();Device->BeginScene();

for(int i = 0; i < Mtrls.size(); i++)for(int i = 0; i < Mtrls.size(); i++){{

Device->SetMaterial( &Mtrls[i] );Device->SetMaterial( &Mtrls[i] );

Page 32: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3232

Device->SetTexture(0, Textures[i]);Device->SetTexture(0, Textures[i]);Mesh->DrawSubset(i);Mesh->DrawSubset(i);

}}

Device->EndScene();Device->EndScene();Device->Present(0, 0, 0, 0);Device->Present(0, 0, 0, 0);

}}return true;return true;

}}

LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)wParam, LPARAM lParam)

{{switch( msg )switch( msg ){{case WM_DESTROY:case WM_DESTROY:

::PostQuitMessage(0);::PostQuitMessage(0);break;break;

Page 33: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3333

case WM_KEYDOWN:case WM_KEYDOWN:if( wParam == VK_ESCAPE )if( wParam == VK_ESCAPE )

::DestroyWindow(hwnd);::DestroyWindow(hwnd);break;break;

}}return ::DefWindowProc(hwnd, msg, wParam, lParam);return ::DefWindowProc(hwnd, msg, wParam, lParam);

}}

int WINAPI WinMain(HINSTANCE hinstance,int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, HINSTANCE prevInstance, PSTR cmdLine,PSTR cmdLine, int showCmd)int showCmd)

{{if(!d3d::InitD3D(hinstance,if(!d3d::InitD3D(hinstance,

Width, Height, true, D3DDEVTYPE_HAL, &Device))Width, Height, true, D3DDEVTYPE_HAL, &Device)){{

::MessageBox(0, "InitD3D() - FAILED", 0, 0);::MessageBox(0, "InitD3D() - FAILED", 0, 0);

Page 34: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3434

return 0;return 0;}}

if(!Setup())if(!Setup()){{

::MessageBox(0, "Setup() - FAILED", 0, 0);::MessageBox(0, "Setup() - FAILED", 0, 0);return 0;return 0;

}}

d3d::EnterMsgLoop( Display );d3d::EnterMsgLoop( Display );

Cleanup();Cleanup();

Device->Release();Device->Release();

return 0;return 0;}}

Page 35: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3535

버텍스 법선 생성하기버텍스 법선 생성하기 XfileXfile 에 만약 법선 데이터가 없다면 조명을 위해 직접 버텍스 법선 에 만약 법선 데이터가 없다면 조명을 위해 직접 버텍스 법선

데이터를 계산해내야 함데이터를 계산해내야 함 . . 다음과 같은 함수를 이용해 메쉬의 버텍스 다음과 같은 함수를 이용해 메쉬의 버텍스 법선을 만들어낼 수 있음법선을 만들어낼 수 있음

• HRESULT D3DXComputeNormals(HRESULT D3DXComputeNormals(LPD3DXBASEMESH pMesh, //LPD3DXBASEMESH pMesh, // 법선을 계산하려는 메쉬법선을 계산하려는 메쉬const DWORD *pAdjacency //const DWORD *pAdjacency // 입력 인접 정보입력 인접 정보

););

이 함수는 법선 평균을 이용해 버텍스 법선을 계산해냄이 함수는 법선 평균을 이용해 버텍스 법선을 계산해냄 . . 만약 만약 제공된 인접 정보가 있다면 중복된 버텍스를 제거하며제공된 인접 정보가 있다면 중복된 버텍스를 제거하며 , , 인접 정보가 인접 정보가 제공되지 않는다면 중복된 버텍스도 참조한 면의 평균으로 법선을 제공되지 않는다면 중복된 버텍스도 참조한 면의 평균으로 법선을 가짐가짐

Page 36: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3636

pMeshpMesh 로 전달할 메쉬는 로 전달할 메쉬는 D3DFVF_NORMAL D3DFVF_NORMAL 플래그를 포함하는 플래그를 포함하는 버텍스 포맷을 가져야 함버텍스 포맷을 가져야 함

만약 만약 XfileXfile 이 버텍스 법선 데이터를 포함하지 않는다면 이 버텍스 법선 데이터를 포함하지 않는다면 D3DXLoadMeshFromXD3DXLoadMeshFromX 으로 만든 으로 만든 ID3DXMeshID3DXMesh 객체도 버텍스 객체도 버텍스 포맷 내에 정의된포맷 내에 정의된 D3DFVF_NORMALD3DFVF_NORMAL 을 가지지 않는다는데 주의을 가지지 않는다는데 주의 ..

따라서 따라서 D3DXComputeNormalsD3DXComputeNormals 를 이용하기 전에 먼저 메쉬를 를 이용하기 전에 먼저 메쉬를 복제하고 복제한 메쉬의 버텍스 포맷을 지정복제하고 복제한 메쉬의 버텍스 포맷을 지정 . . 다음의 코드는 이 다음의 코드는 이 같은 작업 과정을 보여줌같은 작업 과정을 보여줌

Page 37: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3737

• //// 메쉬가 버텍스 포맷으로 메쉬가 버텍스 포맷으로 Dd3dfvf_normalDd3dfvf_normal 를 가지고 있는가를 가지고 있는가 ??

if(!(pMesh->GetFVF() & D3DFVF_NORMAL))if(!(pMesh->GetFVF() & D3DFVF_NORMAL)){{ //// 아니다아니다 . . 따라서 새 메쉬를 복제하고 포맷으로 따라서 새 메쉬를 복제하고 포맷으로

D3DFVF_NORMALD3DFVF_NORMAL 를 추가를 추가 ID3DXMesh* pTempMesh = 0;ID3DXMesh* pTempMesh = 0;

pMesh->CloneMeshFVF(pMesh->CloneMeshFVF( D3DXMESH_MANAGED,D3DXMESH_MANAGED,

pMesh->GetFVF()|D3DFVF_NORMAL,//pMesh->GetFVF()|D3DFVF_NORMAL,// 이곳에 추가이곳에 추가 Device,Device, &pTempMesh);&pTempMesh);

//// 법선을 계산법선을 계산D3DXComputeNormals(pTempMesh,0);D3DXComputeNormals(pTempMesh,0);pMesh->Release(); //pMesh->Release(); // 기존의 메쉬를 제거기존의 메쉬를 제거pMesh=pTempMesh; //pMesh=pTempMesh; //새로운 메쉬를 법선과 함께 저장새로운 메쉬를 법선과 함께 저장}}

Page 38: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3838

프로그레시브 메쉬프로그레시브 메쉬 ID3DXPMesh ID3DXPMesh 인터페이스에 의해 표현되는 프로그레시브 메쉬는 인터페이스에 의해 표현되는 프로그레시브 메쉬는 경계 상실 경계 상실

변환변환 (ECT: edge collapse transformation) (ECT: edge collapse transformation) 시퀀스를 적용하여 메쉬를 시퀀스를 적용하여 메쉬를 단순화할단순화할 수 있도록 함 수 있도록 함

각각의 각각의 ECTECT 는 하나의 버텍스와 하나 혹은 두 개의 면을 제거하는데는 하나의 버텍스와 하나 혹은 두 개의 면을 제거하는데 , , 각각의 각각의 ECTECT 를 되돌릴 수가 있으므로를 되돌릴 수가 있으므로 (( 되돌리는 과정은 버텍스 분할이라 부름되돌리는 과정은 버텍스 분할이라 부름 ) ) 단순화 단순화 과정을 되돌려 원래 상태의 메쉬로 돌아갈 수 있음과정을 되돌려 원래 상태의 메쉬로 돌아갈 수 있음

프로그레시브 메쉬의 작동 원리는 텍스처에서 밉맵을 이용하는 것과 유사프로그레시브 메쉬의 작동 원리는 텍스처에서 밉맵을 이용하는 것과 유사 . . 텍스처링을 수행할 때텍스처링을 수행할 때 , , 작고 먼 기본형에 복잡한 고해상도의 텍스처를 이용하는 작고 먼 기본형에 복잡한 고해상도의 텍스처를 이용하는 것이 낭비가 된다는 것을 잘 알고 있는데것이 낭비가 된다는 것을 잘 알고 있는데 , , 메쉬에 있어서도 마찬가지 개념이 메쉬에 있어서도 마찬가지 개념이 적용적용• 작고 먼 메쉬는 크고 가까운 메쉬만큼 많은 삼각형이 필요치 않음작고 먼 메쉬는 크고 가까운 메쉬만큼 많은 삼각형이 필요치 않음• 작은 메쉬에서는 부가적인 삼각형에 의한 세부적인 면이 유실될 것임작은 메쉬에서는 부가적인 삼각형에 의한 세부적인 면이 유실될 것임

프로그레시브 메쉬를 이용하는 한 가지 방법은 카메라와의 거리에 따라 메쉬의 프로그레시브 메쉬를 이용하는 한 가지 방법은 카메라와의 거리에 따라 메쉬의 LODLOD 를 조정하는 방법이 있는데를 조정하는 방법이 있는데 , , 다시 말해서 카메라와의 거리가 감소하면 다시 말해서 카메라와의 거리가 감소하면 메쉬의 세부메쉬의 세부 (( 삼각형삼각형 )) 를 더하고 거리가 증가하면 세부를 감소시킴를 더하고 거리가 증가하면 세부를 감소시킴

Page 39: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 3939

프로그레시브 메쉬 생성하기프로그레시브 메쉬 생성하기 다음과 같은 함수를 이용하면 다음과 같은 함수를 이용하면 ID3DXPMesh ID3DXPMesh 객체를 만들 수 있음객체를 만들 수 있음

HRESULT D3DXGeneratePMesh(HRESULT D3DXGeneratePMesh(

LPD3DXMESH pMesh,LPD3DXMESH pMesh,

CONST DWORD *pAdjacency,CONST DWORD *pAdjacency,

CONST LPD3DXATTRIBUTEWEIGHTS CONST LPD3DXATTRIBUTEWEIGHTS pVertexAttributeWeights,pVertexAttributeWeights,

CONST FLOAT *pVertexWeights,CONST FLOAT *pVertexWeights,

DWORD MinValue,DWORD MinValue,

DWORD Options,DWORD Options,

LPD3DXPMESH *ppPMeshLPD3DXPMESH *ppPMesh

););

Page 40: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4040

• pMesh pMesh –– 프로그레시브 메쉬를 생성하고자 하는 입력 원본 메쉬프로그레시브 메쉬를 생성하고자 하는 입력 원본 메쉬• pAdjacency pAdjacency –– pMesh pMesh 의 인접 정보를 포함하는 의 인접 정보를 포함하는 DWORD DWORD 배열로의 배열로의

포인터포인터• pVertexAttributeWeights pVertexAttributeWeights –– i i 번째 배열이 번째 배열이 pMesh pMesh 내의 내의 ii 번째 번째

버텍스와 대응되며 속성의 영향력을 지정하는 버텍스와 대응되며 속성의 영향력을 지정하는 D3DXATTRIBUTEWEIGHTS D3DXATTRIBUTEWEIGHTS 배열배열 (Pmesh->GetNumVertices() (Pmesh->GetNumVertices() 크기크기 )) 로의 포인터로의 포인터

• pVertexWeight pVertexWeight –– i i 번째 항목이 번째 항목이 pMesh pMesh 내의 내의 ii 번째 버텍스와 번째 버텍스와 대응되며 대응되며 pMesh->GetNumVertices() pMesh->GetNumVertices() 크기를 가지는 크기를 가지는 float float 배열배열

• MinValue MinValue –– 단순화의 결과로 얻어질 최소한의 버텍스나 면단순화의 결과로 얻어질 최소한의 버텍스나 면• Options Options –– D3DXMESHSIMP D3DXMESHSIMP 열거형 중 하나를 사용열거형 중 하나를 사용

D3DXMESHSIMP_VERTEX D3DXMESHSIMP_VERTEX –– 앞서의 앞서의 MinValue MinValue 인자가 인자가 버텍스에 적용됨을 지정버텍스에 적용됨을 지정

Page 41: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4141

D3DXMESHSIMP_FACE - D3DXMESHSIMP_FACE - 앞서의 앞서의 MinValue MinValue 인자가 면에 인자가 면에 적용됨을 지정적용됨을 지정

• ppMesh ppMesh –– 생성된 프로그레시브 메쉬를 리턴생성된 프로그레시브 메쉬를 리턴

Page 42: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4242

버텍스 속성 영향력버텍스 속성 영향력

typedef struct _D3DXATTRIBUTEWEIGHTS {typedef struct _D3DXATTRIBUTEWEIGHTS { FLOAT Position;FLOAT Position; FLOAT Boundary;FLOAT Boundary; FLOAT Normal;FLOAT Normal; FLOAT Diffuse;FLOAT Diffuse; FLOAT Specular;FLOAT Specular; FLOAT Texcoord[8];FLOAT Texcoord[8]; FLOAT Tangent;FLOAT Tangent; FLOAT Binormal;FLOAT Binormal;} D3DXATTRIBUTEWEIGHTS;} D3DXATTRIBUTEWEIGHTS;

버텍스 영향력 구조체는 버텍스 각 요소의 영향력을 지정할 수 있도록 해줌버텍스 영향력 구조체는 버텍스 각 요소의 영향력을 지정할 수 있도록 해줌 . . 0.0 0.0 값은 요소가 전혀 영향력을 가지고 있지 않음을 지정하며값은 요소가 전혀 영향력을 가지고 있지 않음을 지정하며 , , 값이 값이 높을수록 버텍스의 영향력이 높아져 단순화 과정에서 제거될 가능성이 높을수록 버텍스의 영향력이 높아져 단순화 과정에서 제거될 가능성이 낮아짐낮아짐

Page 43: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4343

디폴트 영향력은 다음과 같음디폴트 영향력은 다음과 같음• D3DXATRIBUTEWIGHTS AttributeWeights;D3DXATRIBUTEWIGHTS AttributeWeights;• AttributeWeights.Position = 1.0;AttributeWeights.Position = 1.0;• AttributeWeights.Boundary = 1.0;AttributeWeights.Boundary = 1.0;• AttributeWeights.Normal = 1.0;AttributeWeights.Normal = 1.0;• AttributeWeights.Diffuse = 0.0;AttributeWeights.Diffuse = 0.0;• AttributeWeights.Specular = 0.0;AttributeWeights.Specular = 0.0;• AttributeWeights.Tex[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, AttributeWeights.Tex[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,

0.0, 0.0};0.0, 0.0};

Page 44: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4444

ID3DXPMesh ID3DXPMesh 메서드메서드 ID3DXPMesh ID3DXPMesh 인터페이스는 인터페이스는 ID3DXBaseMesh ID3DXBaseMesh 인터페이스를 인터페이스를

상속받음상속받음 . . 따라서 앞서 공부한 따라서 앞서 공부한 ID3DXMeshID3DXMesh 의 모든 기능을 가지고 의 모든 기능을 가지고 있으며있으며 , , 다음과 같은 추가 메서드들을 포함다음과 같은 추가 메서드들을 포함

• DWORD GetMaxFaces(VOID); - DWORD GetMaxFaces(VOID); - 프로그레시브 메쉬가 가질 프로그레시브 메쉬가 가질 수 있는 최대 면 수를 리턴수 있는 최대 면 수를 리턴

• DWORD GetMaxVertices(VOID); - DWORD GetMaxVertices(VOID); - 프로그레시브 메쉬가 프로그레시브 메쉬가 가질 수 있는 최대 면 수를 리턴가질 수 있는 최대 면 수를 리턴

• DWORD GetMinFaces(VOID); - DWORD GetMinFaces(VOID); - 프로그레시브 메쉬가 가질 수 프로그레시브 메쉬가 가질 수 있는 최소 면 수를 리턴있는 최소 면 수를 리턴

• DWORD GetMinVertices(VOID); - DWORD GetMinVertices(VOID); - 프로그레시브 메쉬가 가질 프로그레시브 메쉬가 가질 수 있는 최소 버텍스 수를 리턴수 있는 최소 버텍스 수를 리턴

• HRESULT SetNumFaces(DWORD faces); - HRESULT SetNumFaces(DWORD faces); - 이 메서드는 이 메서드는 단순화단순화 //복잡화 하려는 메쉬의 면 수를 지정할 수 있게 해줌복잡화 하려는 메쉬의 면 수를 지정할 수 있게 해줌 . . 예를 들어 현재 예를 들어 현재 5050 면을 가진 메쉬가 있다고 할 때 이를 면을 가진 메쉬가 있다고 할 때 이를 3030면으로 줄이고자 한다면 다음과 같은 코드 라인을 이용면으로 줄이고자 한다면 다음과 같은 코드 라인을 이용

pmesh->SetNumFaces(30);pmesh->SetNumFaces(30);

Page 45: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4545

• HRESULT SetNumVertices(DWORD Vertices); - HRESULT SetNumVertices(DWORD Vertices); - 이 메서드는 이 메서드는 단순화단순화 //복잡화하려는 메쉬의 버텍스 수를 지정할 수 있게 해줌복잡화하려는 메쉬의 버텍스 수를 지정할 수 있게 해줌 . . 예를 들어 현재 예를 들어 현재 2020 개의 버텍스를 가진 메쉬가 있고 버텍스의 수를 개의 버텍스를 가진 메쉬가 있고 버텍스의 수를 4040 개로 늘리고자 한다면 다음과 같은 코드 라인을 이용개로 늘리고자 한다면 다음과 같은 코드 라인을 이용

pmesh->SetNumVertices(40);pmesh->SetNumVertices(40);

• HRESULT TrimByFaces(DWORD NewFacesMin, DWORD HRESULT TrimByFaces(DWORD NewFacesMin, DWORD NewFaceMax, DWORD *rgiFaceRemap, DWORD NewFaceMax, DWORD *rgiFaceRemap, DWORD *rgiVertexRemap); - *rgiVertexRemap); - 이 메서드는 이 메서드는 NewFacesMinNewFacesMin 과 과 NewFacesMax NewFacesMax 인자를 통해 새로운 최소 면 수와 최대 면 수를 인자를 통해 새로운 최소 면 수와 최대 면 수를 지정할 수 있도록 해줌지정할 수 있도록 해줌 . . 새로운 최소새로운 최소 //최대 값은 반드시 현재의 최최대 값은 반드시 현재의 최소소 //최대 면 수 범위에 있어야 함최대 면 수 범위에 있어야 함

Page 46: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4646

• HRESULT TrimByVertices(DWORD NewVerticesMin, HRESULT TrimByVertices(DWORD NewVerticesMin, DWORD NewVerticesMax, DWORD *rgiFaceRemap, DWORD NewVerticesMax, DWORD *rgiFaceRemap, DWORD *rgiVertRemap); - DWORD *rgiVertRemap); - 이 메서드는 이 메서드는 NewVerticesMinNewVerticesMin과 과 NewVerticesMax NewVerticesMax 인자를 통해 새로운 최소 버텍스 수와 인자를 통해 새로운 최소 버텍스 수와 최대 버텍스 수를 지정할 수 있도록 해줌최대 버텍스 수를 지정할 수 있도록 해줌 . . 새로운 최소새로운 최소 //최대 최대 값은 반드시 현재의 최소값은 반드시 현재의 최소 //최대 버텍스 수 범위에 있어야 함최대 버텍스 수 범위에 있어야 함

가장 중요한 메서드는 메서드의 가장 중요한 메서드는 메서드의 LODLOD 를 직접 지정할 수 있도록 를 직접 지정할 수 있도록 해주는 해주는 SetNumFacesSetNumFaces 와 와 SetNumVertices SetNumVertices 두 가지임두 가지임

Page 47: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4747

예제 애플리케이션예제 애플리케이션 : : 프로그레시브 프로그레시브 메쉬메쉬

프로그레시브 메쉬를 이용해 메쉬를 만들고 렌더링하므로 프로그레시브 메쉬를 이용해 메쉬를 만들고 렌더링하므로 ID3DXPMesh ID3DXPMesh 인터페이스를 이용해 메쉬를 표현인터페이스를 이용해 메쉬를 표현

예제에 이용된 전역 변수는 예제에 이용된 전역 변수는 Xfile Xfile 예제에 이용된 것과 거의 예제에 이용된 것과 거의 동일하지만 프로그레시브 메쉬를 보관하기 위한 부가적인 변수를 동일하지만 프로그레시브 메쉬를 보관하기 위한 부가적인 변수를 추가했다는 점이 다름추가했다는 점이 다름

• ID3DXMesh* SourceMesh = 0;ID3DXMesh* SourceMesh = 0;

ID3DXPMesh* PMesh = 0; // progressive meshID3DXPMesh* PMesh = 0; // progressive mesh

std::vector<D3DMATERIAL9> Mtrls(0);std::vector<D3DMATERIAL9> Mtrls(0);

std::vector<IDirect3DTexture9*> Textures(0);std::vector<IDirect3DTexture9*> Textures(0);

Page 48: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4848

프로그레시브 메쉬를 만들기 위해서는 프로그레시브 메쉬를 생성할 프로그레시브 메쉬를 만들기 위해서는 프로그레시브 메쉬를 생성할 원본 메쉬 데이터를 전달해야 하는데원본 메쉬 데이터를 전달해야 하는데 , ,

먼저 먼저 Xfile Xfile 데이터를 데이터를 ID3DXMeshID3DXMesh 객체인 객체인 SourceMeshSourceMesh 에 에 로드하고 이를 프로그레시브 메쉬 데이터를 생성해야 함로드하고 이를 프로그레시브 메쉬 데이터를 생성해야 함

Page 49: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 4949

원본 메쉬를 얻은 뒤에는 다음과 같은 코드를 이용해 프로그레시브 원본 메쉬를 얻은 뒤에는 다음과 같은 코드를 이용해 프로그레시브 메쉬를 만들어낼 수 있음메쉬를 만들어낼 수 있음• //// 프로그레시브 메쉬를 생성프로그레시브 메쉬를 생성

hr = D3DXGeneratePMesh(hr = D3DXGeneratePMesh(SourceMesh,SourceMesh,(DWORD*)adjBuffer->GetBufferPointer(), // (DWORD*)adjBuffer->GetBufferPointer(), // 인접인접0, // 0, // 디폴트 버텍스 속성 영향력디폴트 버텍스 속성 영향력0, // 0, // 디폴트 버텍스 영향력디폴트 버텍스 영향력1, // 1, // 최대한 단순화최대한 단순화D3DXMESHSIMP_FACE, // D3DXMESHSIMP_FACE, // 면의 수로 단순화면의 수로 단순화&PMesh);&PMesh);

d3d::Release<ID3DXMesh*>(SourceMesh);//d3d::Release<ID3DXMesh*>(SourceMesh);// 원본메쉬정리원본메쉬정리d3d::Release<ID3DXBuffer*>(adjBuffer); //d3d::Release<ID3DXBuffer*>(adjBuffer); // 버퍼정리버퍼정리

Page 50: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5050

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, ::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0);0);

return false;return false;}}

• 이 코드는 하나의 면으로 메쉬를 단순화하도록 요청하고 있지만이 코드는 하나의 면으로 메쉬를 단순화하도록 요청하고 있지만 , , 버텍스버텍스 //속성 영향력에 의해 실제로 하나의 면만 남는 일은 일어나지 속성 영향력에 의해 실제로 하나의 면만 남는 일은 일어나지 않음않음 ..

이제 프로그레시브 메쉬가 만들어졌지만 현재 시점에서 이를 렌더링하면 이제 프로그레시브 메쉬가 만들어졌지만 현재 시점에서 이를 렌더링하면 가장 낮은 해상도로 렌더링 됨가장 낮은 해상도로 렌더링 됨 . . 최대 해상도로 메쉬를 렌더링할 것이므로 최대 해상도로 메쉬를 렌더링할 것이므로 다음과 같은 코드를 이용해 해상도를 지정다음과 같은 코드를 이용해 해상도를 지정• // // 원본 원본 (( 최대최대 )) 으로 지정으로 지정

DWORD maxFaces = PMesh->GetMaxFaces();DWORD maxFaces = PMesh->GetMaxFaces();PMesh->SetNumFaces(maxFaces);PMesh->SetNumFaces(maxFaces);

Page 51: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5151

Display Display 함수에서는 함수에서는 AA 키와 키와 SS 키가 눌렸는지를 확인하고 적절하게 키가 눌렸는지를 확인하고 적절하게 대응대응• bool Display(float timeDelta)bool Display(float timeDelta)

{{ if( Device )if( Device )

{{ // // 갱신갱신 :: 메쉬 해상도메쉬 해상도

// Pmesh// Pmesh 의 현재 면수를 구함의 현재 면수를 구함 int numFaces = PMesh->GetNumFaces();int numFaces = PMesh->GetNumFaces();

// // 면을 추가면을 추가 , , 지정된 값이 경계를 넘는 경우지정된 값이 경계를 넘는 경우 // SetNumFaces()// SetNumFaces() 는 자동으로 최대 값으로 고정는 자동으로 최대 값으로 고정 if( ::GetAsyncKeyState('A') & 0x8000f )if( ::GetAsyncKeyState('A') & 0x8000f ) {{

Page 52: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5252

//// 면의 수를 확실하게 늘리기 위해서는 두 개의 면을면의 수를 확실하게 늘리기 위해서는 두 개의 면을//// 한번에 추가해야 할 수도 있음한번에 추가해야 할 수도 있음PMesh->SetNumFaces( numFaces + 1 );PMesh->SetNumFaces( numFaces + 1 );if( PMesh->GetNumFaces() == numFaces )if( PMesh->GetNumFaces() == numFaces )

PMesh->SetNumFaces( numFaces + 2 );PMesh->SetNumFaces( numFaces + 2 ); }}

// // 면을 감소시킴면을 감소시킴 . . 지정된 값이 경계보다 작은 경우지정된 값이 경계보다 작은 경우 // SetNumFaces()// SetNumFaces() 는 자동으로 최소값으로 고정는 자동으로 최소값으로 고정 if( ::GetAsyncKeyState('S') & 0x8000f )if( ::GetAsyncKeyState('S') & 0x8000f )

PMesh->SetNumFaces( numFaces - 1 );PMesh->SetNumFaces( numFaces - 1 );• 코드는 상당히 간단하지만코드는 상당히 간단하지만 , , 경계 상실 변환의 결과를 바꾸기 경계 상실 변환의 결과를 바꾸기

위해서는 때로 두 개의 면을 추가해야 한다는 점을 주의위해서는 때로 두 개의 면을 추가해야 한다는 점을 주의

Page 53: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5353

ID3DXPMesh ID3DXPMesh 객체를 렌더링하는 과정은 객체를 렌더링하는 과정은 ID3DXMesh ID3DXMesh 객체를 렌더링할 객체를 렌더링할 때와 동일함때와 동일함 . .

부가적으로 노란색 재질을 이용해 메쉬의 삼각형을 노란색 외곽선으로 그려낼 부가적으로 노란색 재질을 이용해 메쉬의 삼각형을 노란색 외곽선으로 그려낼 수도 있음수도 있음 . .

여기에서는 프로그레시브 메쉬의 각 삼각형이 어떻게 추가여기에서는 프로그레시브 메쉬의 각 삼각형이 어떻게 추가 //감소되는지를 감소되는지를 확실하게 확인할 수 있도록 이러한 와이어 프레임 모드를 이용확실하게 확인할 수 있도록 이러한 와이어 프레임 모드를 이용• Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,

0xffffffff, 1.0f, 0);0xffffffff, 1.0f, 0);Device->BeginScene();Device->BeginScene();

for(int i = 0; i < Mtrls.size(); i++)for(int i = 0; i < Mtrls.size(); i++){{ // draw pmesh// draw pmesh Device->SetMaterial( &Mtrls[i] );Device->SetMaterial( &Mtrls[i] ); Device->SetTexture(0, Textures[i]);Device->SetTexture(0, Textures[i]); PMesh->DrawSubset(i);PMesh->DrawSubset(i);

Page 54: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5454

// draw wireframe outline// draw wireframe outline Device->SetMaterial(&d3d::YELLOW_MTRL);Device->SetMaterial(&d3d::YELLOW_MTRL); Device->SetRenderState(D3DRS_FILLMODE, Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);D3DFILL_WIREFRAME); PMesh->DrawSubset(i);PMesh->DrawSubset(i); Device->SetRenderState(D3DRS_FILLMODE, Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);D3DFILL_SOLID);

}}

Device->EndScene();Device->EndScene();Device->Present(0, 0, 0, 0);Device->Present(0, 0, 0, 0);

}} return true;return true;}}

Page 55: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5555

Page 56: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5656

#include "d3dUtility.h"#include "d3dUtility.h"#include <vector>#include <vector>

IDirect3DDevice9* Device = 0; IDirect3DDevice9* Device = 0;

const int Width = 640;const int Width = 640;const int Height = 480;const int Height = 480;

ID3DXMesh* SourceMesh = 0;ID3DXMesh* SourceMesh = 0;ID3DXPMesh* PMesh = 0; // progressive meshID3DXPMesh* PMesh = 0; // progressive meshstd::vector<D3DMATERIAL9> Mtrls(0);std::vector<D3DMATERIAL9> Mtrls(0);std::vector<IDirect3DTexture9*> Textures(0);std::vector<IDirect3DTexture9*> Textures(0);

bool Setup()bool Setup(){{

HRESULT hr = 0;HRESULT hr = 0;

Page 57: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5757

ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;DWORD numMtrls = 0;DWORD numMtrls = 0;

hr = D3DXLoadMeshFromX( hr = D3DXLoadMeshFromX( "bigship1.x","bigship1.x",D3DXMESH_MANAGED,D3DXMESH_MANAGED,Device,Device,&adjBuffer,&adjBuffer,&mtrlBuffer,&mtrlBuffer,0,0,&numMtrls,&numMtrls,&SourceMesh);&SourceMesh);

if(FAILED(hr))if(FAILED(hr)){{

Page 58: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5858

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);return false;return false;

}}

if( mtrlBuffer != 0 && numMtrls != 0 )if( mtrlBuffer != 0 && numMtrls != 0 ){{

D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer-D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();>GetBufferPointer();

for(int i = 0; i < numMtrls; i++)for(int i = 0; i < numMtrls; i++){{

// the MatD3D property doesn't have an ambient value // the MatD3D property doesn't have an ambient value setset

// when its loaded, so set it now:// when its loaded, so set it now:mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;

// save the ith material// save the ith materialMtrls.push_back( mtrls[i].MatD3D );Mtrls.push_back( mtrls[i].MatD3D );

Page 59: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 5959

// check if the ith material has an associative texture// check if the ith material has an associative textureif( mtrls[i].pTextureFilename != 0 )if( mtrls[i].pTextureFilename != 0 ){{

// yes, load the texture for the ith subset// yes, load the texture for the ith subsetIDirect3DTexture9* tex = 0;IDirect3DTexture9* tex = 0;D3DXCreateTextureFromFile(D3DXCreateTextureFromFile(

Device,Device,mtrls[i].pTextureFilename,mtrls[i].pTextureFilename,&tex);&tex);

// save the loaded texture// save the loaded textureTextures.push_back( tex );Textures.push_back( tex );

}}elseelse{{

// no texture for the ith subset// no texture for the ith subsetTextures.push_back( 0 );Textures.push_back( 0 );

}}

Page 60: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6060

}}}}d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer

hr = SourceMesh->OptimizeInplace(hr = SourceMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_COMPACT |D3DXMESHOPT_COMPACT |D3DXMESHOPT_VERTEXCACHE,D3DXMESHOPT_VERTEXCACHE,(DWORD*)adjBuffer->GetBufferPointer(),(DWORD*)adjBuffer->GetBufferPointer(),(DWORD*)adjBuffer->GetBufferPointer(), // new adjacency info(DWORD*)adjBuffer->GetBufferPointer(), // new adjacency info0, 0);0, 0);

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);d3d::Release<ID3DXBuffer*>(adjBuffer); // freed3d::Release<ID3DXBuffer*>(adjBuffer); // freereturn false;return false;

}}

Page 61: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6161

hr = D3DXGeneratePMesh(hr = D3DXGeneratePMesh(SourceMesh,SourceMesh,(DWORD*)adjBuffer->GetBufferPointer(), // adjacency(DWORD*)adjBuffer->GetBufferPointer(), // adjacency0, // default vertex attribute weights0, // default vertex attribute weights0, // default vertex weights0, // default vertex weights1, // simplify as low as possible1, // simplify as low as possibleD3DXMESHSIMP_FACE, // simplify by face countD3DXMESHSIMP_FACE, // simplify by face count&PMesh);&PMesh);

d3d::Release<ID3DXMesh*>(SourceMesh); // done w/ source meshd3d::Release<ID3DXMesh*>(SourceMesh); // done w/ source meshd3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0);::MessageBox(0, "D3DXGeneratePMesh() - FAILED", 0, 0);return false;return false;

}}

Page 62: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6262

// set to original detail// set to original detailDWORD maxFaces = PMesh->GetMaxFaces();DWORD maxFaces = PMesh->GetMaxFaces();PMesh->SetNumFaces(maxFaces);PMesh->SetNumFaces(maxFaces);

// Set texture filters.// Set texture filters.Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

// Set Lights.// Set Lights.D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);

Device->SetLight(0, &light);Device->SetLight(0, &light);Device->LightEnable(0, true);Device->LightEnable(0, true);

Page 63: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6363

Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);Device->SetRenderState(D3DRS_SPECULARENABLE, true);Device->SetRenderState(D3DRS_SPECULARENABLE, true);

// Set camera.// Set camera.D3DXVECTOR3 pos(-8.0f, 4.0f, -12.0f);D3DXVECTOR3 pos(-8.0f, 4.0f, -12.0f);D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

D3DXMATRIX V;D3DXMATRIX V;D3DXMatrixLookAtLH(D3DXMatrixLookAtLH(

&V,&V,&pos,&pos,&target,&target,&up);&up);

Device->SetTransform(D3DTS_VIEW, &V);Device->SetTransform(D3DTS_VIEW, &V);

Page 64: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6464

// Set projection matrix.// Set projection matrix.D3DXMATRIX proj;D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(D3DXMatrixPerspectiveFovLH(

&proj,&proj,D3DX_PI * 0.5f, // 90 - degreeD3DX_PI * 0.5f, // 90 - degree(float)Width / (float)Height,(float)Width / (float)Height,1.0f,1.0f,1000.0f);1000.0f);

Device->SetTransform(D3DTS_PROJECTION, &proj);Device->SetTransform(D3DTS_PROJECTION, &proj);

return true;return true;}}

void Cleanup()void Cleanup(){{

d3d::Release<ID3DXPMesh*>(PMesh);d3d::Release<ID3DXPMesh*>(PMesh);

Page 65: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6565

for(int i = 0; i < Textures.size(); i++)for(int i = 0; i < Textures.size(); i++)d3d::Release<IDirect3DTexture9*>( Textures[i] );d3d::Release<IDirect3DTexture9*>( Textures[i] );

}}

bool Display(float timeDelta)bool Display(float timeDelta){{

if( Device )if( Device ){{

// Update: Mesh resolution.// Update: Mesh resolution.

// Get the current number of faces the pmesh has.// Get the current number of faces the pmesh has.int numFaces = PMesh->GetNumFaces();int numFaces = PMesh->GetNumFaces();

// Add a face, note the SetNumFaces() will automatically// Add a face, note the SetNumFaces() will automatically// clamp the specified value if it goes out of bounds.// clamp the specified value if it goes out of bounds.if( ::GetAsyncKeyState('A') & 0x8000f )if( ::GetAsyncKeyState('A') & 0x8000f ){{

Page 66: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6666

// Sometimes we must add more than one face to // Sometimes we must add more than one face to invertinvert

// an edge collapse transformation// an edge collapse transformationPMesh->SetNumFaces( numFaces + 1 );PMesh->SetNumFaces( numFaces + 1 );if( PMesh->GetNumFaces() == numFaces )if( PMesh->GetNumFaces() == numFaces )

PMesh->SetNumFaces( numFaces + 2 );PMesh->SetNumFaces( numFaces + 2 );}}

// Remove a face, note the SetNumFaces() will automatically// Remove a face, note the SetNumFaces() will automatically// clamp the specified value if it goes out of bounds.// clamp the specified value if it goes out of bounds.if( ::GetAsyncKeyState('S') & 0x8000f )if( ::GetAsyncKeyState('S') & 0x8000f )

PMesh->SetNumFaces( numFaces - 1 );PMesh->SetNumFaces( numFaces - 1 );

// Render// RenderDevice->Clear(0, 0, D3DCLEAR_TARGET | Device->Clear(0, 0, D3DCLEAR_TARGET |

D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);Device->BeginScene();Device->BeginScene();

Page 67: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6767

for(int i = 0; i < Mtrls.size(); i++)for(int i = 0; i < Mtrls.size(); i++){{

// draw pmesh// draw pmeshDevice->SetMaterial( &Mtrls[i] );Device->SetMaterial( &Mtrls[i] );Device->SetTexture(0, Textures[i]);Device->SetTexture(0, Textures[i]);PMesh->DrawSubset(i);PMesh->DrawSubset(i);

// draw wireframe outline// draw wireframe outlineDevice->SetMaterial(&d3d::YELLOW_MTRL);Device->SetMaterial(&d3d::YELLOW_MTRL);Device->SetRenderState(D3DRS_FILLMODE, Device->SetRenderState(D3DRS_FILLMODE,

D3DFILL_WIREFRAME);D3DFILL_WIREFRAME);PMesh->DrawSubset(i);PMesh->DrawSubset(i);Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

}}

Device->EndScene();Device->EndScene();Device->Present(0, 0, 0, 0);Device->Present(0, 0, 0, 0);

}}

Page 68: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6868

return true;return true;}}

LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)wParam, LPARAM lParam)

{{switch( msg )switch( msg ){{case WM_DESTROY:case WM_DESTROY:

::PostQuitMessage(0);::PostQuitMessage(0);break;break;

case WM_KEYDOWN:case WM_KEYDOWN:if( wParam == VK_ESCAPE )if( wParam == VK_ESCAPE )

::DestroyWindow(hwnd);::DestroyWindow(hwnd);break;break;

}}return ::DefWindowProc(hwnd, msg, wParam, lParam);return ::DefWindowProc(hwnd, msg, wParam, lParam);

}}

Page 69: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 6969

return true;return true;}}

LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)wParam, LPARAM lParam)

{{switch( msg )switch( msg ){{case WM_DESTROY:case WM_DESTROY:

::PostQuitMessage(0);::PostQuitMessage(0);break;break;

case WM_KEYDOWN:case WM_KEYDOWN:if( wParam == VK_ESCAPE )if( wParam == VK_ESCAPE )

::DestroyWindow(hwnd);::DestroyWindow(hwnd);break;break;

}}return ::DefWindowProc(hwnd, msg, wParam, lParam);return ::DefWindowProc(hwnd, msg, wParam, lParam);

}}

Page 70: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7070

int WINAPI WinMain(HINSTANCE hinstance,int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, HINSTANCE prevInstance, PSTR cmdLine,PSTR cmdLine, int showCmd)int showCmd)

{{if(!d3d::InitD3D(hinstance,if(!d3d::InitD3D(hinstance,

Width, Height, true, D3DDEVTYPE_HAL, &Device))Width, Height, true, D3DDEVTYPE_HAL, &Device)){{

::MessageBox(0, "InitD3D() - FAILED", 0, 0);::MessageBox(0, "InitD3D() - FAILED", 0, 0);return 0;return 0;

}}

if(!Setup())if(!Setup()){{

::MessageBox(0, "Setup() - FAILED", 0, 0);::MessageBox(0, "Setup() - FAILED", 0, 0);return 0;return 0;

}}

Page 71: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7171

d3d::EnterMsgLoop( Display );d3d::EnterMsgLoop( Display );

Cleanup();Cleanup();

Device->Release();Device->Release();

return 0;return 0;}}

Page 72: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7272

경계 볼륨경계 볼륨

메쉬의 경계 볼륨을 계산할 필요가 있음메쉬의 경계 볼륨을 계산할 필요가 있음 . . 가장 자주 이용되는 경계 가장 자주 이용되는 경계 볼륨의 예로는 구체와 상자를 들 수 있지만볼륨의 예로는 구체와 상자를 들 수 있지만 , , 원기둥이나 타원면원기둥이나 타원면 , , 마름모꼴마름모꼴 , , 캡슐형 등과 같은 경계 볼륨도 존재캡슐형 등과 같은 경계 볼륨도 존재

경계 상자경계 상자 //구체의 응용 분야는 다양하지만 그 중에서도 가시성 구체의 응용 분야는 다양하지만 그 중에서도 가시성 테스트와 충돌 테스트를 빼놓을 수 없음테스트와 충돌 테스트를 빼놓을 수 없음

예를 들어예를 들어 , , 메쉬의 경계 상자메쉬의 경계 상자 //구체가 보이지 않는다면 메쉬 역시 구체가 보이지 않는다면 메쉬 역시 보이지 않는다고 말할 수 있음보이지 않는다고 말할 수 있음 . . 상자상자 //구체 가시성 테스트는 메쉬 구체 가시성 테스트는 메쉬 내의 각 삼각형들의 가시성 테스트에 비해 훨씬 간단함내의 각 삼각형들의 가시성 테스트에 비해 훨씬 간단함

충돌 테스트의 예를 들면충돌 테스트의 예를 들면• 장면 내에 발사된 미사일이 물체를 맞추었는지 확인하는 예를 장면 내에 발사된 미사일이 물체를 맞추었는지 확인하는 예를

생각해보면생각해보면 , , 물체는 삼각형들로 구성되므로 물체를 이루는 물체는 삼각형들로 구성되므로 물체를 이루는 각각의 삼각형들을 대상으로 미사일과 충돌했는지 확인해야 함각각의 삼각형들을 대상으로 미사일과 충돌했는지 확인해야 함

Page 73: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7373

• 이 방법은 하나의 물체에 대해서 상당히 많은 광선이 방법은 하나의 물체에 대해서 상당히 많은 광선 //삼각형 교차 삼각형 교차 테스트를 필요로 함테스트를 필요로 함

• 만약 각 메쉬의 경계 상자만약 각 메쉬의 경계 상자 //구체를 계산하고 각 물체에 대해 한 구체를 계산하고 각 물체에 대해 한 번씩만 광선번씩만 광선 //상자 혹은 광선상자 혹은 광선 //구체 교차 테스트만을 수행한다면 구체 교차 테스트만을 수행한다면 훨씬 높은 효율을 얻을 수 있음훨씬 높은 효율을 얻을 수 있음

D3DX D3DX 라이브러리는 메쉬의 경계 상자와 경계 구체를 계산하는 라이브러리는 메쉬의 경계 상자와 경계 구체를 계산하는 함수를 제공함수를 제공 . . 이 함수들은 버텍스의 배열을 입력 인자로 받고 경계 이 함수들은 버텍스의 배열을 입력 인자로 받고 경계 볼륨을 계산해냄볼륨을 계산해냄

Page 74: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7474

이들 함수는 높은 유연성을 가지도록 디자인되었으며 다양한 버텍스 포맷을 이들 함수는 높은 유연성을 가지도록 디자인되었으며 다양한 버텍스 포맷을 이용할 수 있음이용할 수 있음HRESULT D3DXComputeBoundingSphere(HRESULT D3DXComputeBoundingSphere(

LPD3DXVECTOR3 pFirstPosition,LPD3DXVECTOR3 pFirstPosition,DWORD NumVertices,DWORD NumVertices,DWORD dwStride,DWORD dwStride,D3DXVECTOR3* pCenter,D3DXVECTOR3* pCenter,FLOAT* pRadius);FLOAT* pRadius);

• pFirstPosition pFirstPosition –– 버텍스들의 위치를 나타내는 버텍스 배열의 첫번째 버텍스들의 위치를 나타내는 버텍스 배열의 첫번째 버텍스 벡터를 가리키는 포인터버텍스 벡터를 가리키는 포인터

• NumVertices NumVertices –– 버텍스 배열 내 버텍스의 수버텍스 배열 내 버텍스의 수• dwStride dwStride –– 바이트 단위의 버텍스 크기바이트 단위의 버텍스 크기 . . 버텍스 구조에는 법선 벡터나 버텍스 구조에는 법선 벡터나

텍스처 좌표와 같이 경계 구체 계산에 불필요한 부가 정보가 포함될 수 텍스처 좌표와 같이 경계 구체 계산에 불필요한 부가 정보가 포함될 수 있으므로 다음 버텍스 위치로 이동하기 위해 건너뛸 데이터의 양을 있으므로 다음 버텍스 위치로 이동하기 위해 건너뛸 데이터의 양을 결정하는데 이 정보가 이용됨결정하는데 이 정보가 이용됨

• pRadius pRadius –– 경계 구체의 반지름을 리턴경계 구체의 반지름을 리턴

Page 75: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7575

HRESULT D3DXComputeBoundingBox(HRESULT D3DXComputeBoundingBox( LPD3DXVECTOR3 pFirstPosition,LPD3DXVECTOR3 pFirstPosition,

DWORD NumVertices,DWORD NumVertices,DWORD dwStride,DWORD dwStride,D3DXVECTOR3* pMin,D3DXVECTOR3* pMin,D3DXVECTOR3* pMax,D3DXVECTOR3* pMax,

););

처음의 세 인자는 처음의 세 인자는 D3DXComputeBoundingSphereD3DXComputeBoundingSphere 의 세 의 세 인자와 완전히 동일하며인자와 완전히 동일하며 , , 뒷부분의 두 인자는 경계 상자의 뒷부분의 두 인자는 경계 상자의 최소점과 최대점을 리턴최소점과 최대점을 리턴

Page 76: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7676

몇 가지 새로운 특수 상수몇 가지 새로운 특수 상수 이 단원에서 유용하게 이용될 두 개의 상수를 소개하는데이 단원에서 유용하게 이용될 두 개의 상수를 소개하는데 , , 이 이

상수들은 상수들은 d3d d3d 네임스페이스에 추가됨네임스페이스에 추가됨• namespace d3dnamespace d3d

{{

……

const float INFINITY = FLT_MAX;const float INFINITY = FLT_MAX;

const float EPSILON = 0.001f;const float EPSILON = 0.001f;

Page 77: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7777

• INFINITY INFINITY 상수는 상수는 floatfloat 에 저장할 수 있는 가장 큰 수를 나타냄에 저장할 수 있는 가장 큰 수를 나타냄 .. FLT_MAXFLT_MAX 보다 큰 보다 큰 floatfloat 은 존재할 수 없으므로 이를 무한이라는 은 존재할 수 없으므로 이를 무한이라는

개념으로 정의개념으로 정의 . . 이로서 좀 더 이해하기 쉬운 코드가 만들어지며 무한이라는 이로서 좀 더 이해하기 쉬운 코드가 만들어지며 무한이라는

개념을 확실하게 표현 할 수 있게 됨개념을 확실하게 표현 할 수 있게 됨• EPSILON EPSILON 상수는 매우 작아서 상수는 매우 작아서 00 과 같은 것으로 취급할 수 있는 과 같은 것으로 취급할 수 있는 값을 의미값을 의미 . .

이와 같은 의미가 필요한 이유는 부동 소수점의 부정확성 이와 같은 의미가 필요한 이유는 부동 소수점의 부정확성 때문으로때문으로 , ,

00 이 되어야 할 값이 조금 벗어난 값이 될 수 있기 때문에 직접 이 되어야 할 값이 조금 벗어난 값이 될 수 있기 때문에 직접 00과 비교하면 의도와는 다른 결과를 얻으므로 과 비교하면 의도와는 다른 결과를 얻으므로 00 과 비교하는 대신 과 비교하는 대신 EPSILONEPSILON 보다 작은지를 검사하는 방법이 이용보다 작은지를 검사하는 방법이 이용

• 다음의 함수는 두 부동 소수점 값이 같은지를 검사하는 데 다음의 함수는 두 부동 소수점 값이 같은지를 검사하는 데 EPSILONEPSILON을 이용하는 예를 보여줌을 이용하는 예를 보여줌

Page 78: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7878

bool Equals(float lhs, float rhs)bool Equals(float lhs, float rhs)

{{

// // 만약 만약 lhs == rhslhs == rhs 라면 두 값의 차이는 라면 두 값의 차이는 00 이어야 함이어야 함return fabs(lhs-rhs) < EPSILON ? true : false;return fabs(lhs-rhs) < EPSILON ? true : false;

}}

Page 79: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 7979

경계 볼륨 형경계 볼륨 형

경계 구체와 경계 볼륨을 이용하는 작업을 원활히 하기 위해서는 경계 구체와 경계 볼륨을 이용하는 작업을 원활히 하기 위해서는 이들을 클래스로 구현하는 것이 자연스러움 이들을 클래스로 구현하는 것이 자연스러움

이들 클래스를 이들 클래스를 d3d d3d 네임스페이스 내에 구현하는 방법은 다음과 네임스페이스 내에 구현하는 방법은 다음과 같음같음struct BoundingBoxstruct BoundingBox

{{ BoundingBox();BoundingBox();

bool isPointInside(D3DXVECTOR3& p);bool isPointInside(D3DXVECTOR3& p);

D3DXVECTOR3 _min;D3DXVECTOR3 _min; D3DXVECTOR3 _max;D3DXVECTOR3 _max;

};};

Page 80: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8080

struct BoundingSpherestruct BoundingSphere {{ BoundingSphere();BoundingSphere();

D3DXVECTOR3 _center;D3DXVECTOR3 _center; float _radius;float _radius;

};};

d3d::BoundingBox::BoundingBox()d3d::BoundingBox::BoundingBox(){{

// infinite small // infinite small _min.x = d3d::INFINITY;_min.x = d3d::INFINITY;_min.y = d3d::INFINITY;_min.y = d3d::INFINITY;_min.z = d3d::INFINITY;_min.z = d3d::INFINITY;

Page 81: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8181

_max.x = -d3d::INFINITY;_max.x = -d3d::INFINITY;_max.y = -d3d::INFINITY;_max.y = -d3d::INFINITY;_max.z = -d3d::INFINITY;_max.z = -d3d::INFINITY;

}}

bool d3d::BoundingBox::isPointInside(D3DXVECTOR3& p)bool d3d::BoundingBox::isPointInside(D3DXVECTOR3& p){{

if( p.x >= _min.x && p.y >= _min.y && p.z >= _min.z &&if( p.x >= _min.x && p.y >= _min.y && p.z >= _min.z &&p.x <= _max.x && p.y <= _max.y && p.z p.x <= _max.x && p.y <= _max.y && p.z

<= _max.z )<= _max.z ){{

return true;return true;}}elseelse{{

return false;return false;

Page 82: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8282

}}}}

d3d::BoundingSphere::BoundingSphere()d3d::BoundingSphere::BoundingSphere(){{

_radius = 0.0f;_radius = 0.0f;}}

Page 83: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8383

예제 애플리케이션예제 애플리케이션 : : 경계 볼륨경계 볼륨 D3DXComputeBoundingSphereD3DXComputeBoundingSphere 와 와

D3DXComputeBoundingBox D3DXComputeBoundingBox 이용 방법을 보여주는 바운딩 볼륨 이용 방법을 보여주는 바운딩 볼륨 예제는 단원 예제 폴더에 포함되어 있음예제는 단원 예제 폴더에 포함되어 있음

이 프로그램은 이 프로그램은 XfileXfile 을 로드하고 메쉬와 경계 구체를 계산하여을 로드하고 메쉬와 경계 구체를 계산하여 , , 이어 경계 구체와 경계 상자를 위한 두 개의 이어 경계 구체와 경계 상자를 위한 두 개의 ID3DXMesh ID3DXMesh 객체를 객체를 만든다만든다

읽어들인 읽어들인 XfileXfile 의 메쉬와 대응되는 경계 구체나 경계 상자가 의 메쉬와 대응되는 경계 구체나 경계 상자가 출력되며 사용자는 스페이스 키를 이용해 경계 구체와 경계 상자 출력되며 사용자는 스페이스 키를 이용해 경계 구체와 경계 상자 사이를 전환할 수 있음사이를 전환할 수 있음

다음은 메쉬의 경계 구체와 경계 상자를 계산해내는 두 함수의 소스 다음은 메쉬의 경계 구체와 경계 상자를 계산해내는 두 함수의 소스 코드임코드임

Page 84: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8484

bool ComputeBoundingSphere(ID3DXMesh* mesh, bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere)d3d::BoundingSphere* sphere)

{{HRESULT hr = 0;HRESULT hr = 0;

BYTE* v = 0;BYTE* v = 0;mesh->LockVertexBuffer(0, (void**)&v);mesh->LockVertexBuffer(0, (void**)&v);

hr = D3DXComputeBoundingSphere(hr = D3DXComputeBoundingSphere((D3DXVECTOR3*)v,(D3DXVECTOR3*)v,mesh->GetNumVertices(),mesh->GetNumVertices(),D3DXGetFVFVertexSize(mesh-D3DXGetFVFVertexSize(mesh-

>GetFVF()),>GetFVF()),&sphere->_center,&sphere->_center,&sphere->_radius);&sphere->_radius);

mesh->UnlockVertexBuffer();mesh->UnlockVertexBuffer();

Page 85: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8585

if( FAILED(hr) )if( FAILED(hr) )return false;return false;

return true;return true;}}

bool ComputeBoundingBox(ID3DXMesh* mesh, bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box)d3d::BoundingBox* box)

{{HRESULT hr = 0;HRESULT hr = 0;

BYTE* v = 0;BYTE* v = 0;mesh->LockVertexBuffer(0, (void**)&v);mesh->LockVertexBuffer(0, (void**)&v);

hr = D3DXComputeBoundingBox(hr = D3DXComputeBoundingBox((D3DXVECTOR3*)v,(D3DXVECTOR3*)v,mesh->GetNumVertices(),mesh->GetNumVertices(),

Page 86: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8686

D3DXGetFVFVertexSize(mesh-D3DXGetFVFVertexSize(mesh->GetFVF()),>GetFVF()),

&box->_min,&box->_min,&box->_max);&box->_max);

mesh->UnlockVertexBuffer();mesh->UnlockVertexBuffer();

if( FAILED(hr) )if( FAILED(hr) )return false;return false;

return true;return true;}} 이 코드에서 이 코드에서 (D3DXVECTOR3*) v(D3DXVECTOR3*) v 는 우리가 이용하는 버텍스 는 우리가 이용하는 버텍스

구조체의 시작에 버텍스 위치 속성이 보관되어 있다고 가정하고 구조체의 시작에 버텍스 위치 속성이 보관되어 있다고 가정하고 있음있음 . . 주어진 버텍스 포맷 정보에서 버텍스 구조체의 크기를 주어진 버텍스 포맷 정보에서 버텍스 구조체의 크기를 얻으려면 얻으려면 D3DXGetFVFVertexSize D3DXGetFVFVertexSize 함수를 이용함수를 이용

Page 87: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8787

Page 88: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8888

#include "d3dUtility.h"#include "d3dUtility.h"#include <vector>#include <vector>

IDirect3DDevice9* Device = 0; IDirect3DDevice9* Device = 0;

const int Width = 640;const int Width = 640;const int Height = 480;const int Height = 480;

ID3DXMesh* Mesh = 0;ID3DXMesh* Mesh = 0;std::vector<D3DMATERIAL9> Mtrls(0);std::vector<D3DMATERIAL9> Mtrls(0);std::vector<IDirect3DTexture9*> Textures(0);std::vector<IDirect3DTexture9*> Textures(0);

ID3DXMesh* SphereMesh = 0;ID3DXMesh* SphereMesh = 0;ID3DXMesh* BoxMesh = 0;ID3DXMesh* BoxMesh = 0;

bool RenderBoundingSphere = true;bool RenderBoundingSphere = true;

Page 89: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 8989

bool ComputeBoundingSphere(ID3DXMesh* mesh, bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere);d3d::BoundingSphere* sphere);

bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box);box);

bool Setup()bool Setup(){{

HRESULT hr = 0;HRESULT hr = 0;

////// Load the XFile data.// Load the XFile data.////ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* adjBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;ID3DXBuffer* mtrlBuffer = 0;DWORD numMtrls = 0;DWORD numMtrls = 0;

hr = D3DXLoadMeshFromX( hr = D3DXLoadMeshFromX( "bigship1.x","bigship1.x",

Page 90: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9090

D3DXMESH_MANAGED,D3DXMESH_MANAGED,Device,Device,&adjBuffer,&adjBuffer,&mtrlBuffer,&mtrlBuffer,0,0,&numMtrls,&numMtrls,&Mesh);&Mesh);

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);return false;return false;

}}

if( mtrlBuffer != 0 && numMtrls != 0 )if( mtrlBuffer != 0 && numMtrls != 0 ){{

D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer-D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();>GetBufferPointer();

Page 91: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9191

for(int i = 0; i < numMtrls; i++)for(int i = 0; i < numMtrls; i++){{

// the MatD3D property doesn't have an ambient value set// the MatD3D property doesn't have an ambient value set// when its loaded, so set it now:// when its loaded, so set it now:mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;

// save the ith material// save the ith materialMtrls.push_back( mtrls[i].MatD3D );Mtrls.push_back( mtrls[i].MatD3D );

// check if the ith material has an associative texture// check if the ith material has an associative textureif( mtrls[i].pTextureFilename != 0 )if( mtrls[i].pTextureFilename != 0 ){{

// yes, load the texture for the ith subset// yes, load the texture for the ith subsetIDirect3DTexture9* tex = 0;IDirect3DTexture9* tex = 0;D3DXCreateTextureFromFile(D3DXCreateTextureFromFile(

Device,Device,mtrls[i].pTextureFilename,mtrls[i].pTextureFilename,&tex);&tex);

Page 92: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9292

// save the loaded texture// save the loaded textureTextures.push_back( tex );Textures.push_back( tex );

}}elseelse{{

// no texture for the ith subset// no texture for the ith subsetTextures.push_back( 0 );Textures.push_back( 0 );

}}}}

}}d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer

hr = Mesh->OptimizeInplace(hr = Mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_COMPACT |D3DXMESHOPT_COMPACT |D3DXMESHOPT_VERTEXCACHE,D3DXMESHOPT_VERTEXCACHE,(DWORD*)adjBuffer->GetBufferPointer(),(DWORD*)adjBuffer->GetBufferPointer(),0, 0, 0);0, 0, 0);

Page 93: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9393

d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ bufferd3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer

if(FAILED(hr))if(FAILED(hr)){{

::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);return false;return false;

}}

// Compute Bounding Sphere and Bounding Box.// Compute Bounding Sphere and Bounding Box.d3d::BoundingSphere boundingSphere;d3d::BoundingSphere boundingSphere;d3d::BoundingBox boundingBox;d3d::BoundingBox boundingBox;

ComputeBoundingSphere(Mesh, &boundingSphere);ComputeBoundingSphere(Mesh, &boundingSphere);ComputeBoundingBox(Mesh, &boundingBox);ComputeBoundingBox(Mesh, &boundingBox);

D3DXCreateSphere(D3DXCreateSphere(Device,Device,

Page 94: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9494

boundingSphere._radius,boundingSphere._radius,20,20,20,20,&SphereMesh,&SphereMesh,0);0);

D3DXCreateBox(D3DXCreateBox(Device,Device,boundingBox._max.x - boundingBox._min.x,boundingBox._max.x - boundingBox._min.x,boundingBox._max.y - boundingBox._min.y,boundingBox._max.y - boundingBox._min.y,boundingBox._max.z - boundingBox._min.z,boundingBox._max.z - boundingBox._min.z,&BoxMesh,&BoxMesh,0);0);

Device->SetSamplerState(0, D3DSAMP_MAGFILTER, Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);D3DTEXF_LINEAR);

Page 95: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9595

Device->SetSamplerState(0, D3DSAMP_MINFILTER, Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);D3DTEXF_LINEAR);Device->SetSamplerState(0, D3DSAMP_MIPFILTER, Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);D3DTEXF_POINT);

D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);

Device->SetLight(0, &light);Device->SetLight(0, &light);Device->LightEnable(0, true);Device->LightEnable(0, true);Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);Device->SetRenderState(D3DRS_SPECULARENABLE, true);Device->SetRenderState(D3DRS_SPECULARENABLE, true);

D3DXVECTOR3 pos(4.0f, 12.0f, -20.0f);D3DXVECTOR3 pos(4.0f, 12.0f, -20.0f);D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

Page 96: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9696

D3DXMATRIX V;D3DXMATRIX V;D3DXMatrixLookAtLH(D3DXMatrixLookAtLH(

&V,&V,&pos,&pos,&target,&target,&up);&up);

Device->SetTransform(D3DTS_VIEW, &V);Device->SetTransform(D3DTS_VIEW, &V);

D3DXMATRIX proj;D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(D3DXMatrixPerspectiveFovLH(

&proj,&proj,D3DX_PI * 0.5f, // 90 - degreeD3DX_PI * 0.5f, // 90 - degree(float)Width / (float)Height,(float)Width / (float)Height,1.0f,1.0f,1000.0f);1000.0f);

Device->SetTransform(D3DTS_PROJECTION, &proj);Device->SetTransform(D3DTS_PROJECTION, &proj);

Page 97: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9797

return true;return true;}}

void Cleanup()void Cleanup(){{

d3d::Release<ID3DXMesh*>(Mesh);d3d::Release<ID3DXMesh*>(Mesh);

for(int i = 0; i < Textures.size(); i++)for(int i = 0; i < Textures.size(); i++)d3d::Release<IDirect3DTexture9*>( Textures[i] );d3d::Release<IDirect3DTexture9*>( Textures[i] );

d3d::Release<ID3DXMesh*>(SphereMesh);d3d::Release<ID3DXMesh*>(SphereMesh);d3d::Release<ID3DXMesh*>(BoxMesh);d3d::Release<ID3DXMesh*>(BoxMesh);

}}

bool Display(float timeDelta)bool Display(float timeDelta){{

if( Device )if( Device ){{

Page 98: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9898

static float y = 0.0f;static float y = 0.0f;D3DXMATRIX yRot;D3DXMATRIX yRot;D3DXMatrixRotationY(&yRot, y);D3DXMatrixRotationY(&yRot, y);y += timeDelta;y += timeDelta;

if( y >= 6.28f )if( y >= 6.28f )y = 0.0f;y = 0.0f;

D3DXMATRIX World = yRot;D3DXMATRIX World = yRot;

Device->SetTransform(D3DTS_WORLD, &World);Device->SetTransform(D3DTS_WORLD, &World);

// Render// RenderDevice->Clear(0, 0, D3DCLEAR_TARGET | Device->Clear(0, 0, D3DCLEAR_TARGET |

D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);Device->BeginScene();Device->BeginScene();

Page 99: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 9999

// draw the mesh// draw the meshfor(int i = 0; i < Mtrls.size(); i++)for(int i = 0; i < Mtrls.size(); i++){{

Device->SetMaterial( &Mtrls[i] );Device->SetMaterial( &Mtrls[i] );Device->SetTexture(0, Textures[i]);Device->SetTexture(0, Textures[i]);Mesh->DrawSubset(i);Mesh->DrawSubset(i);

}}

// Draw bounding volume in blue and at 10% opacity// Draw bounding volume in blue and at 10% opacityD3DMATERIAL9 blue = d3d::BLUE_MTRL;D3DMATERIAL9 blue = d3d::BLUE_MTRL;blue.Diffuse.a = 0.10f; // 10% opacityblue.Diffuse.a = 0.10f; // 10% opacity

Device->SetMaterial(&blue);Device->SetMaterial(&blue);Device->SetTexture(0, 0); // disable textureDevice->SetTexture(0, 0); // disable texture

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);Device->SetRenderState(D3DRS_SRCBLEND, Device->SetRenderState(D3DRS_SRCBLEND,

D3DBLEND_SRCALPHA);D3DBLEND_SRCALPHA);

Page 100: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 100100

Device->SetRenderState(D3DRS_DESTBLEND, Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);D3DBLEND_INVSRCALPHA);

if( RenderBoundingSphere )if( RenderBoundingSphere )SphereMesh->DrawSubset(0);SphereMesh->DrawSubset(0);

elseelseBoxMesh->DrawSubset(0);BoxMesh->DrawSubset(0);

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);false);

Device->EndScene();Device->EndScene();Device->Present(0, 0, 0, 0);Device->Present(0, 0, 0, 0);

}}return true;return true;

}}LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM

wParam, LPARAM lParam)wParam, LPARAM lParam)

Page 101: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 101101

{{switch( msg )switch( msg ){{case WM_DESTROY:case WM_DESTROY:

::PostQuitMessage(0);::PostQuitMessage(0);break;break;

case WM_KEYDOWN:case WM_KEYDOWN:if( wParam == VK_ESCAPE )if( wParam == VK_ESCAPE )

::DestroyWindow(hwnd);::DestroyWindow(hwnd);if( wParam == VK_SPACE )if( wParam == VK_SPACE )

RenderBoundingSphere = !RenderBoundingSphere;RenderBoundingSphere = !RenderBoundingSphere;

break;break;}}return ::DefWindowProc(hwnd, msg, wParam, lParam);return ::DefWindowProc(hwnd, msg, wParam, lParam);

}}

Page 102: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 102102

int WINAPI WinMain(HINSTANCE hinstance,int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, HINSTANCE prevInstance, PSTR cmdLine,PSTR cmdLine, int showCmd)int showCmd)

{{if(!d3d::InitD3D(hinstance,if(!d3d::InitD3D(hinstance,

Width, Height, true, D3DDEVTYPE_HAL, &Device))Width, Height, true, D3DDEVTYPE_HAL, &Device)){{

::MessageBox(0, "InitD3D() - FAILED", 0, 0);::MessageBox(0, "InitD3D() - FAILED", 0, 0);return 0;return 0;

}}

if(!Setup())if(!Setup()){{

::MessageBox(0, "Setup() - FAILED", 0, 0);::MessageBox(0, "Setup() - FAILED", 0, 0);return 0;return 0;

}}

Page 103: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 103103

d3d::EnterMsgLoop( Display );d3d::EnterMsgLoop( Display );

Cleanup();Cleanup();

Device->Release();Device->Release();

return 0;return 0;}}

bool ComputeBoundingSphere(ID3DXMesh* mesh, bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere)d3d::BoundingSphere* sphere)

{{HRESULT hr = 0;HRESULT hr = 0;

BYTE* v = 0;BYTE* v = 0;mesh->LockVertexBuffer(0, (void**)&v);mesh->LockVertexBuffer(0, (void**)&v);

Page 104: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 104104

hr = D3DXComputeBoundingSphere(hr = D3DXComputeBoundingSphere((D3DXVECTOR3*)v,(D3DXVECTOR3*)v,mesh->GetNumVertices(),mesh->GetNumVertices(),D3DXGetFVFVertexSize(mesh->GetFVF()),D3DXGetFVFVertexSize(mesh->GetFVF()),&sphere->_center,&sphere->_center,&sphere->_radius);&sphere->_radius);

mesh->UnlockVertexBuffer();mesh->UnlockVertexBuffer();

if( FAILED(hr) )if( FAILED(hr) )return false;return false;

return true;return true;}}

bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box)bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box){{

Page 105: 11 장   메쉬  파트 II

2010-12010-1 학기학기 컴퓨터게임컴퓨터게임 (DirectX)(DirectX) 105105

HRESULT hr = 0;HRESULT hr = 0;BYTE* v = 0;BYTE* v = 0;mesh->LockVertexBuffer(0, (void**)&v);mesh->LockVertexBuffer(0, (void**)&v);hr = D3DXComputeBoundingBox(hr = D3DXComputeBoundingBox(

(D3DXVECTOR3*)v,(D3DXVECTOR3*)v,mesh->GetNumVertices(),mesh->GetNumVertices(),D3DXGetFVFVertexSize(mesh->GetFVF()),D3DXGetFVFVertexSize(mesh->GetFVF()),&box->_min,&box->_min,&box->_max);&box->_max);

mesh->UnlockVertexBuffer();mesh->UnlockVertexBuffer();if( FAILED(hr) )if( FAILED(hr) )

return false;return false;

return true;return true;}}