Post Lists

2018년 12월 24일 월요일

Terrain Tutorials Series1 Tutorial 2 : Height Maps

http://www.rastertek.com/tertut02.html

Tutorial 2: Height Maps
이 튜토리얼은 DirectX 11과 C++을 사용하여 3D에서 terrain을 나타내는 height maps을 어떻게 구현할지를 다룰 것이다. 이 튜토리얼의 코드는 이전 terrain tutorial에 기반을 둔다.

Height maps는 그냥 한 파일에 저장된 height points의 mapping이다. height map을 저장하는 가장 흔한 방식은 bitmap, raw, text, or binary file을 사용하고, 0 ~ 255의 값을 사용하여 terrain의 높이를 저장하는 것인데, 0은 terrain의 가장 낮은 높이이고, 255는 가장 높은 높이이다. Grey scale bitmaps과 .raw files은 그것들 자체로 이것을 하는데, 너가 높이를 나타내기 위해 grey color의 강도를 사용할 수 있기 때문이다. 이것은 또한 drawing programs 또는 수학 알고리즘관련하여 수정하거나 조작하는 것을 쉽게 만든다.

height maps을 생성시키는 내가 가장 좋아하는 방법은 Perlin Noise algorithm을 사용하고, 그러고나서 그 결과물을 bitmap file에 저장하는 것이다. 너는 너 자신의 Perlin Noise generator를 쓸 수 있고, 이미 존재하는 것을 사용할 수 있다.

나는 보통 내가 찾는 것과 맞는 것을 볼 때 까지 수 많은 height maps을 만들기 위해 나의 Perlin Noise generator를 사용한다. 예를들어 나는 다음의 것을 생성했었다:

그 이후에, 나는 보통 이것과 같은 flat surface/hills style terrain을 만들어내기 위해  Perlin Noise image에 exponent algorithm을 작동시킨다:

마지막으로 나는 이것과 같은 테레인의 덜 blocky version을 만들기 위해 이웃 픽셀들을 평균화하는 smoothing process를 작동시킨다:

나는 그러고나서 그 이미지를 bitmap format에 저장하고, 나의 terrain height map으로 사용한다. bitmap은 terrain engine에 불려와지고, 나는 map에 있는 각 점을 terrain mesh를 만들기 위해 사용한다. 그 메쉬는 삼각형으로 나타내어질 것이다.

이 튜토리얼에서, 우리는 지난 튜토리얼의 grid code를 새로운 height map code로 바꿀 것이다. 그 코드는 height map을 읽어오고, 그러고나서 grid에 있는 각 점을 elevate시키도록 바뀔 것이다. 그래서 height map elevation과 부합할 것이다. 이것을 하기 위해서 우리는 오직 TerrainClass code만을 바꿀 필요가 있다.

Terrainclass.h
TerrainClass의 첫 번째 중요한 변화는 height map data를 유지할 새로운 struct이다. height map에서 각 점은 x, y, 그리고 z 좌표를 가질 것이다. 이 구조는 그것을 다루는 준비이다.

struct HeightMapType
{
   float x, y, z;
}

그 다음 변화는 Initialize function이 이제 두 번째 입력 파라미터로 height map의 파일 이름을 받는다.

또한 height map data를 loading, normalizing, and unloading 하는 것을 다루는 세 개의 새로운 함수들이 있다.

그리고 마지막으로 우리는 height map array에 대한, 새로운 포인터를 가진다. 이것은 bitmap height map file로 부터 읽혀진 데이터를 저장하는데 사용될 것이다.

Terrainclass.cpp
new height map array pointer를 class constructor에서 null로 초기화한다.

그 Initialize function이 조금 바뀐다. 그것은 이제 height map file을 height map array에 불러오고, 그것을 표준화한다. 그것이 완료된 후에, 그것은 테레인을 렌더링하는데 필요한 버퍼를 만드는 height map array를 작동시키는 InitializeBuffers function을 호출한다.

The Shutdown function은 이제 terrain initialization 동안 만들어진 height map array를 해제하는 ShutdownHeightMap function을 호출한다.

LoadHeightMap은 height map을 포함하는 bitmap file을 새로운 height map array로 불러오는 새로운 함수이다. 만약 너가 .raw 같은 좀 더 최적의 file structure를 사용하길 원한다면, 너는 대신에 그것을 불러오는 코드로 변경할 수 있다. 그러나, 간단함을 위해서, 나는 bitmap format을 사용했다. 왜냐하면 그것은 매우 흔하고, 대부분의 사람들이 이전에 그것으로 작업해왔기 때문이다. bitmap이 red, green, and blue colors를 포함한다는 걳에 주목해라. 그러나 이것은 grey scale image이기 때문에, 너는 red, green or blue color든 어떤 것이든 읽을 수 있다. 왜냐하면 그것들은 같은 grey value 일 것이고, 너는 그것들 중 하나만 필요하기 때문이다.

파일을 열어서 시작하고그것을 unsigned char array에 읽어들이자. 우리가 그 데이터를 읽는 것이 끝났고나서 그 파일을 닫자.

그 terrain의 size를 저장하자. 그래서 우리는 vertex 와 index buffers를 만드는데 이 값들을 사용할 수 있다. 또한 테레인을 렌더링하는데도.

bitmap이 읽어들여졌으니, 2차원 height map array를 만들고, 그 버퍼를 그곳에 읽여들여라. for loop도안 내가 두 개의 loop 변수 (i와 j)를 사용한다나는 것을 주목해라. 그것은 terrain의 X(width)와 Z(depth)가 될 것이다. 그러고나서 나는 bitmap value를 terrain의 Y(height)가 되도록 사용한다. 너는 또한 내가 index를 세 개마다 (k)씩 증가시키는 것을 볼 것이다. 왜냐하면 우리는 grey scale value들로 사용될 그 컬러 값들 중 오직 하나만 필요하기 때문이다.


// Initialize the position in the imgae data buffer.
k = 0;

// Read the image data into the height map.
for (j = 0; j < m_terrainHeight; ++j)
{
 for (i = 0; i < m_terrainWidth; ++i)
 {
  height = bitmapImage[k];

  index = (m_terrainHeight * j) + i;

  m_heightMap[index].x = (float)i;
  m_heightMap[index].y = (float)height;
  m_heightMap[index].z = (float)j;

  k += 3;
 }
}

우리의 배열에 terrain을 위한 height map data를 저장했으니, 우리는 bitmap array를 해제할 수 있다.

다음 새로운 함수는 NormalizeHeightMap이다. 그것이 하는 것은 terrain을 훑어서 각 높이 값을 15로 나누는 것이다. 이것은 terrain이 너무 spikey 보이지 않도록 한다. 일반적으로 height map을 불러오기전에 그것에 이 작업을 하는 것이 더 좋다.

ShutdownHeightMap 함수는 이차원 height map array를 해제한다.

InitializeBuffers는 바뀌고 이제 테레인을 렌더링하기 위해 사용될 vertex and index buffer를 구성하기 위해 height map array를 사용한다.

처음에 height map의 주어진 차원으로 terrain을 구성하는데 필요한 정점과 인덱스들의 개수를 결정한다. 또한 우리는 테레인에서 quads 대신에 삼각형을 구성할 것이다. 그래서 우리는 line lists를 사용하여 각 삼각형으로 quad당 두 개의 삼각형을 만들 열 두개의 정점들이 필요하다.

그러고나서 terrain mesh를 저장할 vertex와 index array를 만든다.

이제 height map array에 있는 모든 점들을 반복시키고, lines으로 구성된 삼각형을 만든다. line당 두 개의 정점, 삼각형달 세 개의 정점, 그리고 quad/square 당 두 개의 삼각형이다.

배열이 주닙되었으니, 너는 terrain을 렌더링하는데 사용될 vertex와 index buffers를 만들수 있다.

=====================================================
이 튜토리얼은 삼각형 메쉬를 line으로 만든다. 일단 다른 튜토리얼을 참고해서 gl_trinagles or gl_trinagle_strip으로 하는 튜토리얼 번역한 걸 가지고 구현하도록 해야겠다.

그전에 pixelscratch에서 perlin noise에 대해서 공부하도록 하겠다.














댓글 없음:

댓글 쓰기