75
13 13 제 제제제제 제제 제제제 제 제제제제 제제 제제제 2010-1 2010-1 제제 제제 1 제제제제제 제제제제제 (DirectX) (DirectX)

제 13 장 기본적인 지형 렌더링

  • Upload
    aysha

  • View
    155

  • Download
    0

Embed Size (px)

DESCRIPTION

제 13 장 기본적인 지형 렌더링. 기본적인 지형 렌더링. 지형 렌더링 지형 메쉬 : 삼각형 격자 격자 내 각 버텍스에 높이 부여하여 지형 표현 텍스처 추가하여 해변 , 언덕 , 눈 덮힌 산 등 표현 이 장의 내용 Terrain 클래스 구현 과정을 보여줌 전체 지형의 버텍스 / 인덱스 데이터를 보관하고 한 번에 렌더링 작은 지형의 경우에는 적용할 수 있으나 큰 지형에는 세부레벨조정 (Level of Detail) 이나 추려내기 기능 필요. 목표 - PowerPoint PPT Presentation

Citation preview

Page 1: 제 13 장 기본적인 지형 렌더링

제제 1313 장 기본적인 지형 렌더링장 기본적인 지형 렌더링

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

Page 2: 제 13 장 기본적인 지형 렌더링

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

기본적인 지형 렌더링기본적인 지형 렌더링 지형 렌더링지형 렌더링

• 지형 메쉬지형 메쉬 : : 삼각형 격자삼각형 격자• 격자 내 각 버텍스에 높이 부여하여 지형 표현격자 내 각 버텍스에 높이 부여하여 지형 표현• 텍스처 추가하여 해변텍스처 추가하여 해변 , , 언덕언덕 , , 눈 덮힌 산 등 표현눈 덮힌 산 등 표현

이 장의 내용이 장의 내용• Terrain Terrain 클래스 구현 과정을 보여줌클래스 구현 과정을 보여줌

전체 지형의 버텍스전체 지형의 버텍스 //인덱스 데이터를 보관하고 한 번에 인덱스 데이터를 보관하고 한 번에 렌더링렌더링

작은 지형의 경우에는 적용할 수 있으나 큰 지형에는 작은 지형의 경우에는 적용할 수 있으나 큰 지형에는 세부레벨조정세부레벨조정 (Level of Detail) (Level of Detail) 이나 추려내기 기능 필요이나 추려내기 기능 필요

Page 3: 제 13 장 기본적인 지형 렌더링

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

목표목표• 산이나 계곡과 같은 자연스러운 지형을 표현하기 위한 지형의 산이나 계곡과 같은 자연스러운 지형을 표현하기 위한 지형의

높이 정보 생성 방법 높이 정보 생성 방법 • 지형을 위한 버텍스와 삼각형 데이터 생성 방법지형을 위한 버텍스와 삼각형 데이터 생성 방법• 지형에 조명과 텍스처 적용을 위한 테크닉지형에 조명과 텍스처 적용을 위한 테크닉• 지형 표면에 카메라를 이식지형 표면에 카메라를 이식 , , 지형 위를 걷거나 뛰는 효과 구현지형 위를 걷거나 뛰는 효과 구현

Page 4: 제 13 장 기본적인 지형 렌더링

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

높 이 맵높 이 맵

지형의 언덕이나 계곡을 표현하는 데 이용되는 것이 높이맵지형의 언덕이나 계곡을 표현하는 데 이용되는 것이 높이맵(heightmap)(heightmap)

각각의 항목이 지형 격자 내의 특정 버텍스의 높이와 대응각각의 항목이 지형 격자 내의 특정 버텍스의 높이와 대응 각 요소가 지형 격자 내의 각 버텍스와 일대일 대응관계를 가지는 각 요소가 지형 격자 내의 각 버텍스와 일대일 대응관계를 가지는

행렬로 생각행렬로 생각

높이맵을 디스크에 보관할 때높이맵을 디스크에 보관할 때• 각 높이에 한 바이트의 메모리를 할당각 높이에 한 바이트의 메모리를 할당• 0 0 부터 부터 255255 까지의 높이를 가짐까지의 높이를 가짐

높이맵의 그래픽 표현 중 하나로높이맵의 그래픽 표현 중 하나로• 낮은 고도를 어두운 값으로낮은 고도를 어두운 값으로 , , 높은 고도를 밝은 값으로 표현하는 높은 고도를 밝은 값으로 표현하는

그레이스케일 맵이 있다그레이스케일 맵이 있다 ..

Page 5: 제 13 장 기본적인 지형 렌더링

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

높이맵 만들기높이맵 만들기

높이맵은 절차적인 방법을 이용하거나 포토샵과 같은 이미지 높이맵은 절차적인 방법을 이용하거나 포토샵과 같은 이미지 편집기를 이용해 만들 수 있다편집기를 이용해 만들 수 있다 ..

이미지 편집기로 높이맵에 이용할 이미지를 만들 때이미지 편집기로 높이맵에 이용할 이미지를 만들 때• 먼저 이미지 포맷으로 그레이 스케일을 지정먼저 이미지 포맷으로 그레이 스케일을 지정

높이맵 작성을 마친 뒤높이맵 작성을 마친 뒤 , 8, 8 비트 비트 RAWRAW 파일로 저장파일로 저장• 경우에 따라서는 다른 파일 포맷으로 저장 가능경우에 따라서는 다른 파일 포맷으로 저장 가능

Page 6: 제 13 장 기본적인 지형 렌더링

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

(( 그림그림 13.3) 13.3) 포토샵에서 만든 그레이스케일 포토샵에서 만든 그레이스케일 이미지이미지

Page 7: 제 13 장 기본적인 지형 렌더링

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

Page 8: 제 13 장 기본적인 지형 렌더링

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

RAW RAW 파일 로딩하기파일 로딩하기

RAWRAW 파일은 일련의 연속된 바이트 블록으로 다음의 메서드를 파일은 일련의 연속된 바이트 블록으로 다음의 메서드를 이용해 손쉽게 블록을 읽기 가능이용해 손쉽게 블록을 읽기 가능

std::vector<int> _heightmap;std::vector<int> _heightmap;

bool Terrain::readRawFile(std::string fileName)bool Terrain::readRawFile(std::string fileName)

{{

// // 각 벡터를 위한 높이각 벡터를 위한 높이std::vector<BYTE> in( _numVertices);std::vector<BYTE> in( _numVertices);

std::ifstream inFile(fileName.c_str(), std::ios_base::binary);std::ifstream inFile(fileName.c_str(), std::ios_base::binary);

if(inFile == 0)if(inFile == 0)

return false;return false;

Page 9: 제 13 장 기본적인 지형 렌더링

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

inFile.read(inFile.read(

(char*) &in[0]; // (char*) &in[0]; // 버퍼버퍼in.size()); // in.size()); // 버퍼로 읽어들일 바이트 수버퍼로 읽어들일 바이트 수

inFile.close();inFile.close();

// byte // byte 벡터를 벡터를 int int 벡터로 복사벡터로 복사 _heightmap.resize( _numVertices);_heightmap.resize( _numVertices);

for(int i = 0; i < in.size(); i++) _heightmap[i] = in[i];for(int i = 0; i < in.size(); i++) _heightmap[i] = in[i];

return true;return true;

}}

Page 10: 제 13 장 기본적인 지형 렌더링

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

• 코드에서 바이트 벡터를 정수 벡터로 복사하고 있다코드에서 바이트 벡터를 정수 벡터로 복사하고 있다 .. 이것은 이후에 높이값을 이것은 이후에 높이값을 [0,255] [0,255] 범위 밖으로 배율을 변경 범위 밖으로 배율을 변경

할 수 있도록 하기 위한 것이다할 수 있도록 하기 위한 것이다 ..

• 이 메서드의 유일한 제한이 메서드의 유일한 제한 RAWRAW 파일에 포함된 바이트 수만큼 지형 내의 버텍스가 파일에 포함된 바이트 수만큼 지형 내의 버텍스가

준비되어 있어야 함준비되어 있어야 함

Page 11: 제 13 장 기본적인 지형 렌더링

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

Terrain Terrain 클래스는 높이맵 내의 항목에 접근하고 수정하기 위한 클래스는 높이맵 내의 항목에 접근하고 수정하기 위한 다음의 두 메서드를 제공다음의 두 메서드를 제공

int Terrain::getHeightmapEntry(int row, int col)int Terrain::getHeightmapEntry(int row, int col)

{{

return _heightmap[row*_numVertsPerRow+col];return _heightmap[row*_numVertsPerRow+col];

}}

void Terrain::setHeightmapEntry(int row, int col, int value)void Terrain::setHeightmapEntry(int row, int col, int value)

{{

_heightmap[row*_numVertsPerRow+col] = value; _heightmap[row*_numVertsPerRow+col] = value;

}}

Page 12: 제 13 장 기본적인 지형 렌더링

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

지형 기하정보 생성하기지형 기하정보 생성하기

Z

X

셀 간격시작 =(-w/2,d/2)

끝 =(w/2, -d/2)d=깊이 W= 너비

셀 / 사각형

Page 13: 제 13 장 기본적인 지형 렌더링

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

지형의 크기를 정의하는 요소지형의 크기를 정의하는 요소

• 행당 버텍스 수행당 버텍스 수• 열당 버텍스 수열당 버텍스 수• 셀 간격셀 간격• 지형과 연결될 장치지형과 연결될 장치

높이맵 데이터를 포함하는 파일명 문자열높이맵 데이터를 포함하는 파일명 문자열 높이맵 요소들의 배율을 조정하는데 이용될 높이 스케일 값높이맵 요소들의 배율을 조정하는데 이용될 높이 스케일 값

예제에서 이 값들을 예제에서 이 값들을 Terrain Terrain 클래스의 생성자에 전달클래스의 생성자에 전달

Page 14: 제 13 장 기본적인 지형 렌더링

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

class Terrainclass Terrain

{{

public:public:

Terrain(Terrain(

IDirect3DDevice9* device,IDirect3DDevice9* device,

std::string heightmapFileName, std::string heightmapFileName,

int numVertsPerRow, int numVertsPerRow,

int numVertsPerCol, int numVertsPerCol,

int cellSpacing, // int cellSpacing, // 셀 간의 간격셀 간의 간격float heightScale); // float heightScale); // 높이 배율을 조정하는 값높이 배율을 조정하는 값

…….. // .. // 메서드 생략메서드 생략

private:private:

…… //// 장치장치 //버텍스 버퍼 생략버텍스 버퍼 생략

Page 15: 제 13 장 기본적인 지형 렌더링

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

int _numVertsPerRow;int _numVertsPerRow;int _numVertsPerCol;int _numVertsPerCol;int _cellSpacing;int _cellSpacing;

int _numCellsPerRow;int _numCellsPerRow;int _numCellsPerCol;int _numCellsPerCol;int _width;int _width;int _depth;int _depth;int _numVertices;int _numVertices;int _numTriangles;int _numTriangles;

float _heightScale;float _heightScale;};};

전체 코드는 예제 참고전체 코드는 예제 참고

Page 16: 제 13 장 기본적인 지형 렌더링

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

생성자에 전달된 값들을 이용해 다음과 같은 방법으로 다른 생성자에 전달된 값들을 이용해 다음과 같은 방법으로 다른 변수들의 값을 계산함변수들의 값을 계산함 ..

_numCellsPerRow = _numVertsPerRow _numCellsPerRow = _numVertsPerRow –– 1; 1;

_numCellsPerCol = _numVertsPerCol _numCellsPerCol = _numVertsPerCol –– 1; 1;

_width = _numCellsPerCol * _cellSpacing;_width = _numCellsPerCol * _cellSpacing;

_depth = _numCellsPerCol * _cellSpacing;_depth = _numCellsPerCol * _cellSpacing;

_numVertices = _numvertsPerRow * _numvertsPerCol;_numVertices = _numvertsPerRow * _numvertsPerCol;

_numTriangles = _numCellsPerRow * _numCellsPerCol * 2;_numTriangles = _numCellsPerRow * _numCellsPerCol * 2;

Page 17: 제 13 장 기본적인 지형 렌더링

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

우리가 이용할 지형의 버텍스 구조체우리가 이용할 지형의 버텍스 구조체

struct TerrainVertex{struct TerrainVertex{

TerrainVertex(){}TerrainVertex(){}

TerrainVertex(float x, float y, float z, float u, float TerrainVertex(float x, float y, float z, float u, float v){v){

_x = x; _y = y; _z = z; _u = u; _v = _x = x; _y = y; _z = z; _u = u; _v = v;v;

}}

float _x, _y, _z;float _x, _y, _z;

float _u, _v;float _u, _v;

static const DWORD FVF;static const DWORD FVF;

};};

const DWORD Terrain::TerrainVertex::FVF = D3DFVF_XYZ | const DWORD Terrain::TerrainVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;D3DFVF_TEX1;

Page 18: 제 13 장 기본적인 지형 렌더링

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

TerrainVertex TerrainVertex 는 는 Terrain Terrain 클래스 내부의 중첩된 클래스임클래스 내부의 중첩된 클래스임• Terrain Terrain 클래스 외부에서는 이 클래스가 필요하지 않기 클래스 외부에서는 이 클래스가 필요하지 않기

때문이다때문이다 ..

Page 19: 제 13 장 기본적인 지형 렌더링

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

버텍스 계산하기버텍스 계산하기

삼각형 격자의 버텍스들을 계산하기 위해서는삼각형 격자의 버텍스들을 계산하기 위해서는

• 시작점의 버텍스를 생성하기 시작시작점의 버텍스를 생성하기 시작 ,,• 끝점에 이를 때까지 셀 간격만큼 버텍스의 간격을 비우고 끝점에 이를 때까지 셀 간격만큼 버텍스의 간격을 비우고

버텍스들을 만들면 된다버텍스들을 만들면 된다 ..• YY 좌표는 읽어들인 높이맵 데이터 구조체 내의 대응되는 좌표는 읽어들인 높이맵 데이터 구조체 내의 대응되는

항목에서 간단하게 얻을 수 있다항목에서 간단하게 얻을 수 있다 ..

Page 20: 제 13 장 기본적인 지형 렌더링

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

지형 버텍스와 텍스춰 버텍스간의 대응지형 버텍스와 텍스춰 버텍스간의 대응 텍스처 좌표 계산방법은 아래 그림을 참고텍스처 좌표 계산방법은 아래 그림을 참고 이 그림은 버텍스이 그림은 버텍스 (i,j)(i,j) 에 해당하는 텍스처 좌표에 해당하는 텍스처 좌표 (u,v)(u,v) 를 얻는 간단한 를 얻는 간단한

시나리오를 보여줌시나리오를 보여줌

(0,0)

(1,0)

(0,1)

(1,1)

+U

+V

Page 21: 제 13 장 기본적인 지형 렌더링

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

u = j · uCoordIncreamentSizeu = j · uCoordIncreamentSize

v = i · vCoordIncreamentSizev = i · vCoordIncreamentSize

여기에서 여기에서

uCoordIncreamentSize = uCoordIncreamentSize =

vCoordIncreamentSize =vCoordIncreamentSize =

numCellCols

numCellRows

1

1

Page 22: 제 13 장 기본적인 지형 렌더링

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

최종적으로 버텍스를 생성하는 코드최종적으로 버텍스를 생성하는 코드

bool Terrain::computeVertices(){bool Terrain::computeVertices(){HRESULT hr = 0;HRESULT hr = 0;hr = _device->CreateVertexBuffer(hr = _device->CreateVertexBuffer(

_numVertices * sizeof(TerrainVertex),_numVertices * sizeof(TerrainVertex),D3DUSAGE_WRITEONLY,D3DUSAGE_WRITEONLY,TerrainVertex::FVF,TerrainVertex::FVF,D3DPOOL_MANAGED,D3DPOOL_MANAGED,&_vb, &_vb, 0);0);

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

int startX = -_width / 2; // int startX = -_width / 2; // 버텍스 생성을 시작할 좌표버텍스 생성을 시작할 좌표int startZ = _depth / 2;int startZ = _depth / 2;

Page 23: 제 13 장 기본적인 지형 렌더링

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

int endX = _width / 2; // int endX = _width / 2; // 버텍스 생성을 마칠 좌표버텍스 생성을 마칠 좌표int endZ = -_depth / 2;int endZ = -_depth / 2;

// // 하나의 버텍스에서 다음 버텍스로 증가할하나의 버텍스에서 다음 버텍스로 증가할// // 텍스처 좌표의 크기를 계산텍스처 좌표의 크기를 계산

float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;float uCoordIncrementSize = 1.0f / (float)_numCellsPerRow;float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;float vCoordIncrementSize = 1.0f / (float)_numCellsPerCol;

TerrainVertex* v = 0;TerrainVertex* v = 0;_vb->Lock(0, 0, (void**)&v, 0);_vb->Lock(0, 0, (void**)&v, 0);

int i = 0;int i = 0;

Page 24: 제 13 장 기본적인 지형 렌더링

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

for(int z = startZ; z >= endZ; z -= _cellSpacing)for(int z = startZ; z >= endZ; z -= _cellSpacing){{

int j = 0;int j = 0;for(int x = startX; x <= endX; x += _cellSpacing)for(int x = startX; x <= endX; x += _cellSpacing){{

// // 중첩된 루프 내의 위치에 따라중첩된 루프 내의 위치에 따라// // 버텍스 버퍼와 높이맵으로의 올바른버텍스 버퍼와 높이맵으로의 올바른// // 인덱스를 계산한다인덱스를 계산한다 ..

int index = i * _numVertsPerRow + j;int index = i * _numVertsPerRow + j;

Page 25: 제 13 장 기본적인 지형 렌더링

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

v[index] = TerrainVertex( (float)x,v[index] = TerrainVertex( (float)x,(float)_heightmap[index], (float)z,(float)_heightmap[index], (float)z,(float)j * uCoordIncrementSize,(float)j * uCoordIncrementSize,(float)i * vCoordIncrementSize);(float)i * vCoordIncrementSize);

j++; // next columnj++; // next column}}i++; // next rowi++; // next row

}}

_vb->Unlock();_vb->Unlock();

return true;return true;}}

Page 26: 제 13 장 기본적인 지형 렌더링

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

인덱스 계산 인덱스 계산 –– 삼각형 정의하기삼각형 정의하기

삼각형 격자의 인덱스를 계산하기 위해서는삼각형 격자의 인덱스를 계산하기 위해서는

• 그림의 좌측 상단에서 시작그림의 좌측 상단에서 시작• 우측 하단으로 각각의 사각형을 구성하는 두 개의 삼각형들을 우측 하단으로 각각의 사각형을 구성하는 두 개의 삼각형들을

차례대로 계산차례대로 계산

(0,0)

(m,n)

버텍스열 j

버텍스열 j + 1버텍스행 i

버텍스행 i+1

ij 번째 셀

A B

C D

Page 27: 제 13 장 기본적인 지형 렌더링

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

• 사각형사각형 (i,j)(i,j) 를 찾기 위한 범용 공식를 찾기 위한 범용 공식

∆ ∆ ABC = {i·numVertsPerRow+j i·numVertsPerRow+j+1 ABC = {i·numVertsPerRow+j i·numVertsPerRow+j+1 (i+1) ·numVertsPerRow+J}(i+1) ·numVertsPerRow+J}

∆ ∆ CBD = {(i+1)·numVertsPerRow+j CBD = {(i+1)·numVertsPerRow+j i·numVertsPerRow+j+1 (i+1) ·numVertsPerRow+j+1}i·numVertsPerRow+j+1 (i+1) ·numVertsPerRow+j+1}

Page 28: 제 13 장 기본적인 지형 렌더링

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

인덱스를 계산하는 코드인덱스를 계산하는 코드

Bool Terrain::computeIndices()Bool Terrain::computeIndices()

{{

HRESULT hr = 0;HRESULT hr = 0;

hr = _device->CreateIndexBuffer(hr = _device->CreateIndexBuffer(

_numTriangles * 3 * sizeof(WORD), //_numTriangles * 3 * sizeof(WORD), // 삼각형당 삼각형당 33 개의 개의 인덱스인덱스

D3DUSAGE_WRITEONLY,D3DUSAGE_WRITEONLY,

D3DFMT_INDEX16,D3DFMT_INDEX16,

D3DPOOLMANAGED,D3DPOOLMANAGED,

&_ib,&_ib,

0);0);

Page 29: 제 13 장 기본적인 지형 렌더링

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

If(FAILED(hr))If(FAILED(hr))

return false;return false;

WORD* indices = 0;WORD* indices = 0;

_ib->Lock(0, 0, (void**)&indices, 0);_ib->Lock(0, 0, (void**)&indices, 0);

// // 하나의 사각형을 구성하는 두 개의 삼각형을 나타내기 위한하나의 사각형을 구성하는 두 개의 삼각형을 나타내기 위한// 6// 6 개의 인덱스 그룹의 시작점개의 인덱스 그룹의 시작점int baseIndex = 0;int baseIndex = 0;

// // 각 사각형의 삼각형을 계산하는 루프각 사각형의 삼각형을 계산하는 루프for(int i = 0; i < _numCellsPerCol; i++)for(int i = 0; i < _numCellsPerCol; i++)

{{

Page 30: 제 13 장 기본적인 지형 렌더링

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

for(int j = 0; j < _numCellsPerRow; j++)for(int j = 0; j < _numCellsPerRow; j++){{

indices[baseIndex] = i * _numVertsPerRow + j;indices[baseIndex] = i * _numVertsPerRow + j;indices[baseIndex + 1] = i * _numVertsPerRow + j + 1;indices[baseIndex + 1] = i * _numVertsPerRow + j + 1;indices[baseIndex + 2] = (i+1) * _numVertsPerRow + j;indices[baseIndex + 2] = (i+1) * _numVertsPerRow + j;indices[baseIndex + 3] = (i+1) * _numVertsPerRow + j;indices[baseIndex + 3] = (i+1) * _numVertsPerRow + j;indices[baseIndex + 4] = i * _numVertsPerRow + j + 1;indices[baseIndex + 4] = i * _numVertsPerRow + j + 1;indices[baseIndex + 5] = (i+1) * _numVertsPerRow + j + indices[baseIndex + 5] = (i+1) * _numVertsPerRow + j +

1;1;

baseIndex += 6;baseIndex += 6;}}

}}

_ib->Unlock();_ib->Unlock();

return true;return true;}}

Page 31: 제 13 장 기본적인 지형 렌더링

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

텍 스 처 링텍 스 처 링

Terrain Terrain 클래스는 지형에 텍스처를 입히는 두 가지 방법을 제공클래스는 지형에 텍스처를 입히는 두 가지 방법을 제공

1) 1) 미리 만들어둔 텍스처 파일을 읽어들이고 이를 이용하는 방법미리 만들어둔 텍스처 파일을 읽어들이고 이를 이용하는 방법

IDirect3DTexture9 IDirect3DTexture9 인터페이스로의 포인터인 인터페이스로의 포인터인 _tex_tex 데이터 데이터 멤버로 텍스처 파일을 읽어들임멤버로 텍스처 파일을 읽어들임

bool loadTexture(std::string fileName);bool loadTexture(std::string fileName);

Page 32: 제 13 장 기본적인 지형 렌더링

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

bool loadTexture(std::string fileName);bool loadTexture(std::string fileName);

bool Terrain::loadTexture(std::string fileName)bool Terrain::loadTexture(std::string fileName){{

HRESULT hr = 0;HRESULT hr = 0;

hr = D3DXCreateTextureFromFile(hr = D3DXCreateTextureFromFile(_device,_device,fileName.c_str(),fileName.c_str(),&_tex);&_tex);

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

return true;return true;}}

Page 33: 제 13 장 기본적인 지형 렌더링

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

2) 2) 절차적 방식절차적 방식

• 지형에 텍스처를 입히는 두 번째 방법지형에 텍스처를 입히는 두 번째 방법 절차적으로 텍스처를 계산해 내는 것절차적으로 텍스처를 계산해 내는 것

• 먼저 먼저 ““빈빈”” 텍스처를 만들고 미리 정의된 인자를 바탕으로 텍스처를 만들고 미리 정의된 인자를 바탕으로 코드에서 각 텍셀의 컬러를 계산코드에서 각 텍셀의 컬러를 계산

예제에서는 지형의 높이를 인자로 이용예제에서는 지형의 높이를 인자로 이용

Page 34: 제 13 장 기본적인 지형 렌더링

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

Terrain:genTexture Terrain:genTexture 메서드를 이용한 절차적 텍스처메서드를 이용한 절차적 텍스처

• D3DXCreateTextureD3DXCreateTexture 를 이용해 빈 텍스처를 만들고를 이용해 빈 텍스처를 만들고• 최상의 레벨최상의 레벨 (( 밉맵 레벨밉맵 레벨 )) 을 잠근 다음을 잠근 다음 , , 각각의 텍셀을 대상으로 각각의 텍셀을 대상으로

반복하여 컬러를 입힘반복하여 컬러를 입힘• 대응되는 사각형의 높이에 따라 텍셀의 컬러를 결정하여 각 대응되는 사각형의 높이에 따라 텍셀의 컬러를 결정하여 각

텍셀을 대상으로 반복하여 컬러를 입힘텍셀을 대상으로 반복하여 컬러를 입힘• 각각의 텍셀에 색상을 입힌 뒤에는 텍셀을 비추는 태양 빛의 각각의 텍셀에 색상을 입힌 뒤에는 텍셀을 비추는 태양 빛의

각도에 따라 텍셀의 밝기를 조정각도에 따라 텍셀의 밝기를 조정 Terrain::lightTerrain Terrain::lightTerrain 메서드에서 이루어짐메서드에서 이루어짐

• 하위 밉맵 레벨의 텍셀을 계산하는 것으로 끝을 맺음하위 밉맵 레벨의 텍셀을 계산하는 것으로 끝을 맺음 D3DXFilterTexture D3DXFilterTexture 함수가 담당함수가 담당

Page 35: 제 13 장 기본적인 지형 렌더링

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

텍스처를 만들어내는 코드텍스처를 만들어내는 코드bool Terrain::genTexture(D3DXVECTOR3* directionToLight)bool Terrain::genTexture(D3DXVECTOR3* directionToLight){{

HRESULT hr = 0;HRESULT hr = 0;

// // 각각의 사각형 셀을 위한 텍셀각각의 사각형 셀을 위한 텍셀int texWidth = _numCellsPerRow;int texWidth = _numCellsPerRow;int texHeight = _numCellsPerCol;int texHeight = _numCellsPerCol;

// // 빈 텍스처를 만든다빈 텍스처를 만든다 ..hr = D3DXCreateTexture(hr = D3DXCreateTexture(

_device,_device,texWidth, texHeight,texWidth, texHeight,0, // create a complete mipmap chain0, // create a complete mipmap chain0, // usage0, // usageD3DFMT_X8R8G8B8,// 32 bit XRGB formatD3DFMT_X8R8G8B8,// 32 bit XRGB formatD3DPOOL_MANAGED, &_tex);D3DPOOL_MANAGED, &_tex);

Page 36: 제 13 장 기본적인 지형 렌더링

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

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

D3DSURFACE_DESC textureDesc; D3DSURFACE_DESC textureDesc; _tex->GetLevelDesc(0 /*level*/, &textureDesc);_tex->GetLevelDesc(0 /*level*/, &textureDesc);

////직접 직접 3232 비트 픽셀을 이용해 텍스처를 채우므로비트 픽셀을 이용해 텍스처를 채우므로//// 올바른 포맷인지를 먼저 확인올바른 포맷인지를 먼저 확인if( textureDesc.Format != D3DFMT_X8R8G8B8 )if( textureDesc.Format != D3DFMT_X8R8G8B8 )

return false;return false;

D3DLOCKED_RECT lockedRect;D3DLOCKED_RECT lockedRect;_tex->LockRect(0/*lock top surface*/, &lockedRect, _tex->LockRect(0/*lock top surface*/, &lockedRect,

0 /* lock entire tex*/, 0/*flags*/); 0 /* lock entire tex*/, 0/*flags*/); // // 텍스처를 채운다텍스처를 채운다 ..

DWORD* imageData = (DWORD*)lockedRect.pBits;DWORD* imageData = (DWORD*)lockedRect.pBits;

Page 37: 제 13 장 기본적인 지형 렌더링

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

for(int i = 0; i < texHeight; i++)for(int i = 0; i < texHeight; i++) {{for(int j = 0; j < texWidth; j++) {for(int j = 0; j < texWidth; j++) {

D3DXCOLOR c;D3DXCOLOR c;// // 사각형의 우측 상단 높이를 구한다사각형의 우측 상단 높이를 구한다 ..

float height = (float)getHeightmapEntry(i, j) / _heightScale;float height = (float)getHeightmapEntry(i, j) / _heightScale; // // 대응되는 사각형 높이에 따라 텍셀의 컬러를 지정한다대응되는 사각형 높이에 따라 텍셀의 컬러를 지정한다 ..

if( (height) < 42.5f ) if( (height) < 42.5f ) c = d3d::BEACH_SAND;c = d3d::BEACH_SAND;

else if( (height) < 85.0f )else if( (height) < 85.0f ) c = d3d::LIGHT_YELLOW_GREEN;c = d3d::LIGHT_YELLOW_GREEN;

else if( (height) < 127.5f )else if( (height) < 127.5f ) c = d3d::PUREGREEN;c = d3d::PUREGREEN;

else if( (height) < 170.0f )else if( (height) < 170.0f ) c = d3d::DARK_YELLOW_GREEN;c = d3d::DARK_YELLOW_GREEN;

else if( (height) < 212.5f ) c = else if( (height) < 212.5f ) c = d3d::DARKBROWN;d3d::DARKBROWN;

elseelse c = d3d::WHITE; c = d3d::WHITE;

Page 38: 제 13 장 기본적인 지형 렌더링

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

imageData[i * lockedRect.Pitch / 4 + j] = imageData[i * lockedRect.Pitch / 4 + j] = (D3DCOLOR)c;(D3DCOLOR)c;

}}}}_tex->UnlockRect(0);_tex->UnlockRect(0);

// // 지형을 밝힌다지형을 밝힌다 ..if(!lightTerrain(directionToLight))if(!lightTerrain(directionToLight)) {{

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

}}

hr = D3DXFilterTexture(hr = D3DXFilterTexture(_tex, // _tex, // 밉맵 레벨을 채울 텍스처밉맵 레벨을 채울 텍스처0, // 0, // 디폴트 팔레트디폴트 팔레트0, // 0, // 하위 레벨의 원본으로 최상위 레벨을 이용하위 레벨의 원본으로 최상위 레벨을 이용D3DX_DEFAULT); // D3DX_DEFAULT); // 디폴트 필터디폴트 필터

Page 39: 제 13 장 기본적인 지형 렌더링

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

if(FAILED(hr))if(FAILED(hr)) {{::MessageBox(0, "D3DXFilterTexture() - FAILED", 0, ::MessageBox(0, "D3DXFilterTexture() - FAILED", 0,

0);0);return false;return false;

}}return true;return true;

}}

Page 40: 제 13 장 기본적인 지형 렌더링

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

조 명조 명

Terrain::genTexture Terrain::genTexture 메서드는 지형에 조명을 추가메서드는 지형에 조명을 추가 , , 사실감을 사실감을 더하는 더하는 Terrain::lightTerrain Terrain::lightTerrain 메서드 호출메서드 호출

Direct3DDirect3D 에게 지형의 음영만 계산하는 것을 맡기지 않고 지형의 에게 지형의 음영만 계산하는 것을 맡기지 않고 지형의 조명을 계산하는 이유조명을 계산하는 이유• 버텍스 법선을 저장하지 않아도 되므로 메모리 절약버텍스 법선을 저장하지 않아도 되므로 메모리 절약• 지형은 정적이며 조명을 움직이지도 않을 것이므로 조명을 미리 지형은 정적이며 조명을 움직이지도 않을 것이므로 조명을 미리

계산하여 지형에 실시간으로 조명을 적용하는데 따르는 처리 계산하여 지형에 실시간으로 조명을 적용하는데 따르는 처리 부담을 덜 수 있다부담을 덜 수 있다 ..

• 약간의 수학 연습을 할 수 있으며 기본적인 조명의 개념과 약간의 수학 연습을 할 수 있으며 기본적인 조명의 개념과 Direct3D Direct3D 함수들에 익숙해짐함수들에 익숙해짐

Page 41: 제 13 장 기본적인 지형 렌더링

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

조명의 개요조명의 개요

우리가 지형의 음영을 계산하는데 이용하는 조명 테크닉은 가장 우리가 지형의 음영을 계산하는데 이용하는 조명 테크닉은 가장 기본적인 것기본적인 것• 난반사광난반사광 (Diffuse lighting)(Diffuse lighting)

빛으로의 방향을 지정하여 하나의 평행한 광원을 정의빛으로의 방향을 지정하여 하나의 평행한 광원을 정의

• 이 방향은 평행 광원에서의 빛이 발산되는 방향과는 반대의 방향이 방향은 평행 광원에서의 빛이 발산되는 방향과는 반대의 방향 예를 들어 예를 들어 lightRaysDirection=(0, -1, 0) lightRaysDirection=(0, -1, 0) 방향으로 방향으로

하늘에서 아래로 빛이 발산되기를 원한다면하늘에서 아래로 빛이 발산되기를 원한다면 , , 평행 평행 광원으로의 방향은 반대방향인 광원으로의 방향은 반대방향인 directionToLight=(0, 1, 0) directionToLight=(0, 1, 0) 이 된다이 된다 . .

Page 42: 제 13 장 기본적인 지형 렌더링

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

다음은 지형 내의 각각의 사각형에 대해 빛 벡터 다음은 지형 내의 각각의 사각형에 대해 빛 벡터 LL 과 사각형 표면 과 사각형 표면 법선 법선 NN 간의 각도 계산간의 각도 계산

• 각도가 커지면 사각형 면이 점차 광원에서 멀어져 빛을 덜 받음각도가 커지면 사각형 면이 점차 광원에서 멀어져 빛을 덜 받음• 작아지면 사각형 면이 점차 광원으로 향하며 더욱 많은 빛을 받음작아지면 사각형 면이 점차 광원으로 향하며 더욱 많은 빛을 받음• 9090 도가 넘으면 표면은 더 이상 빛을 못 받음도가 넘으면 표면은 더 이상 빛을 못 받음

L

N

N

L

Page 43: 제 13 장 기본적인 지형 렌더링

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

빛 벡터와 표면 법선과의 각도 관계를 이용해 표면이 받는 빛의 양을 빛 벡터와 표면 법선과의 각도 관계를 이용해 표면이 받는 빛의 양을 결정하는 결정하는 [0, 1] [0, 1] 범위의 음영 스칼라를 만들 수 있다범위의 음영 스칼라를 만들 수 있다 ..

• 큰 각도는 큰 각도는 00 에 가까운 스칼라로 표현되며 음영 스칼라와 컬러를 에 가까운 스칼라로 표현되며 음영 스칼라와 컬러를 곱하면 곱하면 00 에 가까운 값으로 어두운 컬러가 된다에 가까운 값으로 어두운 컬러가 된다 ..

• 작은 각도는 작은 각도는 11 에 가까운 스칼라로 표현되며 컬러와 곱하면 에 가까운 스칼라로 표현되며 컬러와 곱하면 11 에 에 가까운 밝은 값이 만들어진다가까운 밝은 값이 만들어진다 ..

Page 44: 제 13 장 기본적인 지형 렌더링

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

사각형의 음영 계산하기사각형의 음영 계산하기

광원으로의 방향은 우리가 광원으로의 방향은 우리가 L L 이라고 부르는 정규화된 벡터로 얻을 이라고 부르는 정규화된 벡터로 얻을 수 있다수 있다 ..

L L 과 사각형의 법선 벡터 과 사각형의 법선 벡터 N N 간의 각도를 계산하기 위해서는 먼저 간의 각도를 계산하기 위해서는 먼저 NN 을 찾아야 함을 찾아야 함

먼저 사각형과 공면인 먼저 사각형과 공면인 00 이 아니면서 평행이 아닌 두개의 벡터를 이 아니면서 평행이 아닌 두개의 벡터를 찾아야 함찾아야 함

Page 45: 제 13 장 기본적인 지형 렌더링

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

• 다음은 이 두 개의 벡터 다음은 이 두 개의 벡터 uu 와 와 vv 를 보여줌를 보여줌

b

c

au = b - a

v = c - a

X

Y

Z

Page 46: 제 13 장 기본적인 지형 렌더링

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

• u = (cellSpacing, bu = (cellSpacing, byy –– a ayy, 0), 0)

• v = (0, cv = (0, cyy –– a ayy, -cellSpacing), -cellSpacing)

uu 와 와 vv 가 있다면 사각형의 법선 가 있다면 사각형의 법선 NN 은 은 n = u x vn = u x v 로 얻을 수 로 얻을 수 있다있다 . .

• NN 은 정규화 되어야 한다은 정규화 되어야 한다 ..

• N =N =

LL 과 과 NN 간의 각도를 찾기 위해서는 간의 각도를 찾기 위해서는 3-3- 공간 내 두 단위 공간 내 두 단위 벡터의 내적이 두 벡터 간 각도의 코사인 이다벡터의 내적이 두 벡터 간 각도의 코사인 이다 ..

|N|

N

Page 47: 제 13 장 기본적인 지형 렌더링

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

• L · N = sL · N = s

스칼라 스칼라 ss는 는 [-1, 1] [-1, 1] 범위 내에 위치한다범위 내에 위치한다 ..

[-1, 0) [-1, 0) 내의 내의 ss값은 값은 [[ 그림 그림 13.7]13.7] 에서 빛을 받지 못하는 에서 빛을 받지 못하는 9090 도 이상의 도 이상의 LL 과 과 NN 간의 각도에 대응하므로간의 각도에 대응하므로 , [-1,0) , [-1,0) 내일 내일 경우 경우 ss를 를 00 으로 고정으로 고정

float cosine = D3DXVec3Dot(&n, directionToLight);float cosine = D3DXVec3Dot(&n, directionToLight);

If(cosine < 0.0f) cosine = 0.0f;If(cosine < 0.0f) cosine = 0.0f;

Page 48: 제 13 장 기본적인 지형 렌더링

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

이제 이제 9090 도 이상의 각도에 대해 도 이상의 각도에 대해 ss를 고정하면 를 고정하면 ss는 는 [0,1] [0,1] 범위의 범위의 스칼라가 된다스칼라가 된다 ..

00 도에서 도에서 9090 도까지의 각도가 도까지의 각도가 11 에서 에서 00 값에 대응됨값에 대응됨

각각의 사각형을 위한 음영 인수는 각각의 사각형을 위한 음영 인수는 Terrrain::computeShade Terrrain::computeShade 에서 계산한다에서 계산한다 ..• 이 메서드는 사각형을 지정하는 열과 행이 메서드는 사각형을 지정하는 열과 행 , , 그리고 평행 광원의 그리고 평행 광원의

방향을 인자로 받는다방향을 인자로 받는다 ..

Page 49: 제 13 장 기본적인 지형 렌더링

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

float Terrain::computeShade(int cellRow, int cellCol, float Terrain::computeShade(int cellRow, int cellCol, D3DXVECTOR3* directionToLight)D3DXVECTOR3* directionToLight)

{{// // 사각형의 새 버텍스 높이를 얻는다사각형의 새 버텍스 높이를 얻는다 ..float heightA = getHeightmapEntry(cellRow, cellCol);float heightA = getHeightmapEntry(cellRow, cellCol);float heightB = getHeightmapEntry(cellRow, cellCol+1);float heightB = getHeightmapEntry(cellRow, cellCol+1);float heightC = getHeightmapEntry(cellRow+1, cellCol);float heightC = getHeightmapEntry(cellRow+1, cellCol);

// // 사각형의 두 벡터 외적을 이용해사각형의 두 벡터 외적을 이용해// // 법선을 찾아낸다법선을 찾아낸다 ..D3DXVECTOR3 u(_cellSpacing, heightB - heightA, 0.0f);D3DXVECTOR3 u(_cellSpacing, heightB - heightA, 0.0f);D3DXVECTOR3 v(0.0f, heightC - heightA, -_cellSpacing);D3DXVECTOR3 v(0.0f, heightC - heightA, -_cellSpacing);

Page 50: 제 13 장 기본적인 지형 렌더링

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

D3DXVECTOR3 n;D3DXVECTOR3 n;

D3DXVec3Cross(&n, &u, &v);D3DXVec3Cross(&n, &u, &v);

D3DXVec3Normalize(&n, &n);D3DXVec3Normalize(&n, &n);

float cosine = D3DXVec3Dot(&n, directionToLight);float cosine = D3DXVec3Dot(&n, directionToLight);

if(cosine < 0.0f)if(cosine < 0.0f)

cosine = 0.0f;cosine = 0.0f;

return cosine;return cosine;

}}

Page 51: 제 13 장 기본적인 지형 렌더링

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

지형에 음영 입히기지형에 음영 입히기

특정한 사각형의 음영을 계산할 수 있게 되었다면 지형의 모든 특정한 사각형의 음영을 계산할 수 있게 되었다면 지형의 모든 사각형을 계산하는 일은 매우 간단사각형을 계산하는 일은 매우 간단

• 각각 사각형을 대상으로 반복각각 사각형을 대상으로 반복 , , 사각형의 음영값을 계산사각형의 음영값을 계산• 사각형에 대응하는 텍셀 컬러에 이 음영을 적용사각형에 대응하는 텍셀 컬러에 이 음영을 적용• 이 작업을 통해 빛을 적게 받는 사각형이 좀더 어두어짐이 작업을 통해 빛을 적게 받는 사각형이 좀더 어두어짐

Page 52: 제 13 장 기본적인 지형 렌더링

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

Terrain::lightTerrain Terrain::lightTerrain 메서드의 가장 중요한 부분메서드의 가장 중요한 부분

DWORD* imageData = (DWORD*)lockedRect.pBits;DWORD* imageData = (DWORD*)lockedRect.pBits;for(int i = 0; i < textureDesc.Height; i++){for(int i = 0; i < textureDesc.Height; i++){

for(int j = 0; j < textureDesc.Width; j++){for(int j = 0; j < textureDesc.Width; j++){

int index = i * lockedRect.Pitch / 4 + j;int index = i * lockedRect.Pitch / 4 + j;

// // 셀의 현재 컬러를 얻는다셀의 현재 컬러를 얻는다 ..D3DXCOLOR c( imageData[index] );D3DXCOLOR c( imageData[index] );

// // 셀에 음영을 적용한다셀에 음영을 적용한다 ..c *= computeShade(i, j, directionToLight);;c *= computeShade(i, j, directionToLight);;

// // 음영을 입힌 컬러를 저장한다음영을 입힌 컬러를 저장한다 ..imageData[index] = (D3DCOLOR)c;imageData[index] = (D3DCOLOR)c;

}}}}

Page 53: 제 13 장 기본적인 지형 렌더링

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

지형 위를 지형 위를 ““걷기걷기”” 지형을 구성한 다음에는 마치 지형 위를 걷는 것과 같은 카메라 지형을 구성한 다음에는 마치 지형 위를 걷는 것과 같은 카메라 움직임을 구현할 필요가 있다움직임을 구현할 필요가 있다 ..

이를 위해서는 현재 서있는 지점의 높이에 따라 카메라의 높이를 이를 위해서는 현재 서있는 지점의 높이에 따라 카메라의 높이를 조정해야 한다조정해야 한다 ..

가장 먼저 해야 할 일은 카메라 위치의 가장 먼저 해야 할 일은 카메라 위치의 xx 와 와 zz 좌표를 이용해 좌표를 이용해 현재의 셀을 찾아내는 것현재의 셀을 찾아내는 것• 이 작업은 이 작업은 Terrain::getHeight Terrain::getHeight 함수가 담당함수가 담당

이 함수는 카메라의 이 함수는 카메라의 xx 와 와 zz 좌표를 인자로 받고 카메라의 좌표를 인자로 받고 카메라의 높이로 지정할 수 있는 높이를 리턴높이로 지정할 수 있는 높이를 리턴

Page 54: 제 13 장 기본적인 지형 렌더링

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

float Terrain::getHeight(float x, float z){float Terrain::getHeight(float x, float z){

// // 지형의 시작점을 원점으로 이동하는 변환지형의 시작점을 원점으로 이동하는 변환 , xz , xz 평면상에서 평면상에서 이동이동x = ((float)_width / 2.0f) + x;x = ((float)_width / 2.0f) + x;

z = ((float)_depth / 2.0f) - z;z = ((float)_depth / 2.0f) - z;

//// 셀 간격을 셀 간격을 11 로 만드는 변환로 만드는 변환 , , 변환의 배율을 낮춘다변환의 배율을 낮춘다 ..

x /= (float)_cellSpacing;x /= (float)_cellSpacing;

z /= (float)_cellSpacing;z /= (float)_cellSpacing;

Page 55: 제 13 장 기본적인 지형 렌더링

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

일단 지형의 시작점을 원점으로 이동하는 변환을 계산하고 수행일단 지형의 시작점을 원점으로 이동하는 변환을 계산하고 수행

다음은 셀 간격 변수의 반전으로 배율을 변경다음은 셀 간격 변수의 반전으로 배율을 변경• 이 과정을 거치면 셀 간격은 이 과정을 거치면 셀 간격은 11 이 된다이 된다 ..

이어 양의 이어 양의 zz 축이 축이 ““아래아래””를 가리키도록 새로운 틀을 전환를 가리키도록 새로운 틀을 전환• +z +z 가 아래를 향하는 것으로 인식가 아래를 향하는 것으로 인식

Page 56: 제 13 장 기본적인 지형 렌더링

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

다음은 이 과정을 그림으로 보여주고 있다다음은 이 과정을 그림으로 보여주고 있다 ..

X

Z시작

셀간격

P P

X

Z1.0

0 1 2 3

0 1

2 3

Page 57: 제 13 장 기본적인 지형 렌더링

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

변경된 좌표 시스템은 행렬의 순서와 동일변경된 좌표 시스템은 행렬의 순서와 동일• 즉 좌측 상단이 원점즉 좌측 상단이 원점 , , 열의 수가 오른쪽으로 증가열의 수가 오른쪽으로 증가• 행의 수는 아래쪽으로 증가행의 수는 아래쪽으로 증가 ..

다음과 같은 코드로 간단한 셀의 행과 열을 알아냄다음과 같은 코드로 간단한 셀의 행과 열을 알아냄

• float col = ::floorf(x);float col = ::floorf(x);• float row = ::floorf(z);float row = ::floorf(z);

X 이하의 가장 큰 정수

Page 58: 제 13 장 기본적인 지형 렌더링

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

• 이젠 현재 위치의 셀을 찾을 수 있으므로 셀을 구성하는 네 이젠 현재 위치의 셀을 찾을 수 있으므로 셀을 구성하는 네 버텍스의 높이를 구성할 수 있다버텍스의 높이를 구성할 수 있다 ..

float A = getHeightmapEntry(row, col);float A = getHeightmapEntry(row, col);

float B = getHeightmapEntry(row, col+1);float B = getHeightmapEntry(row, col+1);

float C = getHeightmapEntry(row+1, col);float C = getHeightmapEntry(row+1, col);

float D = getHeightmapEntry(row+1, col+1);float D = getHeightmapEntry(row+1, col+1);

• 이젠 셀 내의 카메라가 위치한 특정 이젠 셀 내의 카메라가 위치한 특정 x, zx, z 좌표의 높이좌표의 높이 (y-(y- 좌표좌표 ))를 얻는 과정이 남아있다를 얻는 과정이 남아있다 ..

Page 59: 제 13 장 기본적인 지형 렌더링

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

X

Y

v0

v1

v2

v3

Z

(x,z)

y

Page 60: 제 13 장 기본적인 지형 렌더링

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

높이를 구하기 위해서는 우리가 셀의 어떤 삼각형에 있는지를 먼저 높이를 구하기 위해서는 우리가 셀의 어떤 삼각형에 있는지를 먼저 알아야 한다알아야 한다 ..

우리가 있는 삼각형을 찾기 위해서는우리가 있는 삼각형을 찾기 위해서는• 왼쪽 상단의 버텍스가 원점에 오도록 현재의 셀을 이동왼쪽 상단의 버텍스가 원점에 오도록 현재의 셀을 이동

colcol 과 과 rowrow 는 현재 우리가 있는 셀의 왼쪽 상단 버텍스 위치를 는 현재 우리가 있는 셀의 왼쪽 상단 버텍스 위치를 나타냄나타냄• xx 축의 축의 -col-col 이 되고 이 되고 zz 축의 축의 -row-row 가 되도록 이동해야 함가 되도록 이동해야 함

Page 61: 제 13 장 기본적인 지형 렌더링

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

xx 와 와 zz 좌표를 이동하면 다음과 같은 결과가 나옴좌표를 이동하면 다음과 같은 결과가 나옴

• float dx = x - col;float dx = x - col;• float dz = z - row;float dz = z - row;

다음은 이동한 뒤의 셀 상태를 보여줌다음은 이동한 뒤의 셀 상태를 보여줌

P

0 1 2 3

0 1

2 3

버텍스(2,1)

우리가 있는 셀

1.0

(1,1)

(0,0)

P

Page 62: 제 13 장 기본적인 지형 렌더링

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

이제 이제 dz<1.0 - dxdz<1.0 - dx 이면이면

• 우리는 우리는 ““위쪽위쪽””삼각형 삼각형 v0v1v2v0v1v2 에 있는것에 있는것• 아니라면 아니라면 ““아래쪽아래쪽”” 삼각형 삼각형 v0v2v3v0v2v3 에 있는 것에 있는 것

Page 63: 제 13 장 기본적인 지형 렌더링

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

““ 위쪽위쪽”” 삼각형에서의 높이 계산 방법 삼각형에서의 높이 계산 방법 위쪽 삼각형에서의 높이를 구하기 위해서는위쪽 삼각형에서의 높이를 구하기 위해서는

• 먼저 삼각형의 옆면과 벡터 먼저 삼각형의 옆면과 벡터 q = (qx, A, qz)q = (qx, A, qz) 의 종단점에서 의 종단점에서 시작하는 두 개의 벡터시작하는 두 개의 벡터

• u = (cellSpacing, B - A, 0)u = (cellSpacing, B - A, 0) 와와• v = (0, C - A, -cellSpacing)v = (0, C - A, -cellSpacing) 을 구성해야 함을 구성해야 함

이어 이어 dxdx 로 로 uu 를 따라 선형적으로 보간하고 를 따라 선형적으로 보간하고 dzdz 로 로 vv 를 선형적으로 를 선형적으로 보간한다보간한다 ..

Page 64: 제 13 장 기본적인 지형 렌더링

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

보간 과정 보간 과정 (( 그림그림 13.12)13.12)A) A) 삼각형의 인접하고 상반된 면의 두 벡터를 계산삼각형의 인접하고 상반된 면의 두 벡터를 계산B) uB) u 를 를 dxdx 로 선형적 보간하고 로 선형적 보간하고 vv 를 를 dzdz 로 선형적으로 보간하면 로 선형적으로 보간하면

높이가 구해짐 높이가 구해짐 => (q + dx u + dz v) => (q + dx u + dz v) 의 의 y y 좌표좌표

q

v

u

(x,z)

q

v

u

(x,z)

X

Y Z Z

X

Y dxudzv

y

Page 65: 제 13 장 기본적인 지형 렌더링

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

우리가 관심을 가지는 것은 보간된 높이값 뿐이므로 우리가 관심을 가지는 것은 보간된 높이값 뿐이므로 y-y- 성분만을 성분만을 보간하고 나머지 성분들은 무시 가능보간하고 나머지 성분들은 무시 가능

최종적으로 최종적으로 A + dx uA + dx uyy + dz v + dz vyy 를 통해 높이 구함를 통해 높이 구함

Page 66: 제 13 장 기본적인 지형 렌더링

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

Terrain::getHeightTerrain::getHeight 를 완결하는 코드를 완결하는 코드if(dz < 1.0f - dx) // if(dz < 1.0f - dx) // 위쪽 삼각형 위쪽 삼각형 ABCABC

{{float uy = B - A; // A->Bfloat uy = B - A; // A->Bfloat vy = C - A; // A->Cfloat vy = C - A; // A->C

height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, dz);dz);}}else // else // 아래쪽 삼각형 아래쪽 삼각형 DCBDCB{{

float uy = C - D; // D->Cfloat uy = C - D; // D->Cfloat vy = B - D; // D->Bfloat vy = B - D; // D->Bheight = D + d3d::Lerp(0.0f, uy, 1.0f - dx) + height = D + d3d::Lerp(0.0f, uy, 1.0f - dx) +

d3d::Lerp(0.0f, vy, 1.0f - dz);d3d::Lerp(0.0f, vy, 1.0f - dz);}}

return height;return height;}}

Page 67: 제 13 장 기본적인 지형 렌더링

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

• Lerp Lerp 함수는 함수는 1D 1D 선을 따르는 기본 선형 보간이며 다음과 같이 선을 따르는 기본 선형 보간이며 다음과 같이 구현됨구현됨

float d3d::Lerp(float a, float b, float t)float d3d::Lerp(float a, float b, float t)

{{

return a return a –– (a * t ) + ( b * t); (a * t ) + ( b * t);

}}

Page 68: 제 13 장 기본적인 지형 렌더링

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

예제 애플리케이션 예제 애플리케이션 : : 지형지형

Page 69: 제 13 장 기본적인 지형 렌더링

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

높이맵 데이터를 포함하는 높이맵 데이터를 포함하는 RAW RAW 파일을 이용해 지형을 생성하고 파일을 이용해 지형을 생성하고 텍스처를 입히며 조명을 추가텍스처를 입히며 조명을 추가

화살표 키를 이용해 지형 위를 걷는 동작화살표 키를 이용해 지형 위를 걷는 동작

먼저 지형과 카메라 초당 프레임 수를 기록하기 위한 전역 변수 추먼저 지형과 카메라 초당 프레임 수를 기록하기 위한 전역 변수 추가가 ..

Terrain* TheTerrain = 0;Terrain* TheTerrain = 0;

Camera TheCamera(Camera::LANDOBJECT);Camera TheCamera(Camera::LANDOBJECT);

FPSCounter* FPS = 0;FPSCounter* FPS = 0;

Page 70: 제 13 장 기본적인 지형 렌더링

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

bool Setup()bool Setup(){{

D3DXVECTOR3 lightDirection(0.0f, 1.0f, 0.0f);D3DXVECTOR3 lightDirection(0.0f, 1.0f, 0.0f);TheTerrain = new Terrain(Device, "coastMountain64.raw", TheTerrain = new Terrain(Device, "coastMountain64.raw", 64, 64, 10, 0.5f);64, 64, 10, 0.5f);TheTerrain->genTexture(&lightDirection);TheTerrain->genTexture(&lightDirection);FPS = new FPSCounter(Device);FPS = new FPSCounter(Device);

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_LINEAR);D3DTEXF_LINEAR);

Page 71: 제 13 장 기본적인 지형 렌더링

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

D3DXMATRIX proj;D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(D3DXMatrixPerspectiveFovLH(

&proj,&proj,D3DX_PI * 0.25f, // 45 - degreeD3DX_PI * 0.25f, // 45 - 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::Delete<Terrain*>(TheTerrain);d3d::Delete<Terrain*>(TheTerrain);d3d::Delete<FPSCounter*>(FPS);d3d::Delete<FPSCounter*>(FPS);

}}

Page 72: 제 13 장 기본적인 지형 렌더링

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

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

if( Device )if( Device ){{

if( ::GetAsyncKeyState(VK_UP) & 0x8000f )if( ::GetAsyncKeyState(VK_UP) & 0x8000f )TheCamera.walk(100.0f * timeDelta);TheCamera.walk(100.0f * timeDelta);

if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )TheCamera.walk(-100.0f * timeDelta);TheCamera.walk(-100.0f * timeDelta);

if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )TheCamera.yaw(-1.0f * timeDelta);TheCamera.yaw(-1.0f * timeDelta);

if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )TheCamera.yaw(1.0f * timeDelta);TheCamera.yaw(1.0f * timeDelta);

Page 73: 제 13 장 기본적인 지형 렌더링

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

if( ::GetAsyncKeyState('N') & 0x8000f )if( ::GetAsyncKeyState('N') & 0x8000f )TheCamera.strafe(-100.0f * timeDelta);TheCamera.strafe(-100.0f * timeDelta);

if( ::GetAsyncKeyState('M') & 0x8000f )if( ::GetAsyncKeyState('M') & 0x8000f )TheCamera.strafe(100.0f * timeDelta);TheCamera.strafe(100.0f * timeDelta);

if( ::GetAsyncKeyState('W') & 0x8000f )if( ::GetAsyncKeyState('W') & 0x8000f )TheCamera.pitch(1.0f * timeDelta);TheCamera.pitch(1.0f * timeDelta);

if( ::GetAsyncKeyState('S') & 0x8000f )if( ::GetAsyncKeyState('S') & 0x8000f )TheCamera.pitch(-1.0f * timeDelta);TheCamera.pitch(-1.0f * timeDelta);

Page 74: 제 13 장 기본적인 지형 렌더링

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

D3DXVECTOR3 pos;D3DXVECTOR3 pos;TheCamera.getPosition(&pos);TheCamera.getPosition(&pos);float height = TheTerrain->getHeight( pos.x, pos.z );float height = TheTerrain->getHeight( pos.x, pos.z );pos.y = height + 5.0f; pos.y = height + 5.0f;

TheCamera.setPosition(&pos);TheCamera.setPosition(&pos);

D3DXMATRIX V;D3DXMATRIX V;TheCamera.getViewMatrix(&V);TheCamera.getViewMatrix(&V);Device->SetTransform(D3DTS_VIEW, &V);Device->SetTransform(D3DTS_VIEW, &V);

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

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

Page 75: 제 13 장 기본적인 지형 렌더링

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

D3DXMATRIX I;D3DXMATRIX I;D3DXMatrixIdentity(&I);D3DXMatrixIdentity(&I);

if( TheTerrain )if( TheTerrain )TheTerrain->draw(&I, false);TheTerrain->draw(&I, false);

if( FPS )if( FPS )FPS->render(0xffffffff, timeDelta);FPS->render(0xffffffff, timeDelta);

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

}}

return true;return true;}}