• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 17일차(HeightMap)

20 Jun 2021

Reading time ~2 minutes

HeightMap

지형에서 사용되는 높낮이를 표현하는 Map이다.

일반적으로

이런 텍스쳐를 갖고 작동하는데 처음엔 이게 뭔 높낮이 인가 싶다.

작동하는 방법은 하얀색으로 갈수록 높이 그려준다.

Terrian.h

#pragma once

class Terrain
{
public:
	typedef Vertex TerrainVertex;

public:
	Terrain(Shader* shader, wstring heightFile);
	~Terrain();

	void Update();
	void Render();

	void Pass(UINT val) { pass = val; }

private:
	void CreateVertexData();
	void CreateIndexData();
	void CreateBuffer();

private:
	UINT pass = 1;
	Shader* shader;

	Texture* heightMap;

	UINT width;
	UINT height;

	UINT vertexCount;
	TerrainVertex* vertices;
	ID3D11Buffer* vertexBuffer;

	UINT indexCount;
	UINT* indices;
	ID3D11Buffer* indexBuffer;
};

지형을 만들 헤더다 Framework에 만들었다.

방법은 삼각형 2개로 사각형을 만들고, 그것들을 많이 만들어 넓게 만드는 것이다.

Terrian.cpp

Terrain::Terrain(Shader * shader, wstring heightFile)
	: shader(shader)
{
	heightMap = new Texture(heightFile);

	CreateVertexData();
	CreateIndexData();
	CreateBuffer();
}

생성자에선 텍스쳐 파일을 받아오고 Vertex, Index, Buffer를 만들어준다.

void Terrain::CreateVertexData()
{
	vector<Color> heights;
	heightMap->ReadPixel(DXGI_FORMAT_R8G8B8A8_UNORM, &heights);

	width = heightMap->GetWidth();
	height = heightMap->GetHeight();

	vertexCount = width * height;
	vertices = new TerrainVertex[vertexCount];
	for (UINT z = 0; z < height; z++)
	{
		for (UINT x = 0; x < width; x++)
		{
			UINT index = width * z + x;

			vertices[index].Position.x = (float)x;
			vertices[index].Position.y = heights[index].r * 255.0f / 10.0f;
			vertices[index].Position.z = (float)z;
		}
	}
}

텍스쳐의 가로 세로를 받아오고 그 넓이만큼 VertexCount를 세팅해준다.

그리고 Vertex를 VectexCount만큼 만들어준다.

그리고 그 만큼 만들어 준다. 높이는 현재 rgb중 r만큼 높게 만들어 준다.

void Terrain::CreateIndexData()
{
	indexCount = (width - 1) * (height - 1) * 6;
	indices = new UINT[indexCount];

	UINT index = 0;
	for (UINT y = 0; y < height - 1; y++)
	{
		for (UINT x = 0; x < width - 1; x++)
		{
			indices[index + 0] = width * y + x;
			indices[index + 1] = width * (y + 1) + x;
			indices[index + 2] = width * y + (x + 1);
			indices[index + 3] = width * y + (x + 1);
			indices[index + 4] = width *  (y + 1) + x;
			indices[index + 5] = width * (y + 1) + (x + 1);

			index += 6;
		}
	}
}

Index도 사각형 찍듯이 만들어 준다.

쉐이더 경우에는 일반적으로 면을 생성하는 쉐이더에 PixelShader부분의 색을 원하는 색(지금은 흰색)으로 반환해준다.

HeightMapDemp.cpp

#include "stdafx.h"
#include "HeightMapDemo.h"

void HeightMapDemo::Initialize()
{	
	Context::Get()->GetCamera()->RotationDegree(12, 0, 0);
	Context::Get()->GetCamera()->Position(35, 10, -55);

	shader = new Shader(L"19_Terrain.fx");

	terrain = new Terrain(shader, L"Terrain/Gray256.png");
	terrain->Pass(1);
}

void HeightMapDemo::Destroy()
{
	SafeDelete(shader);
	SafeDelete(terrain);
}

void HeightMapDemo::Update()
{
	terrain->Update();
}

void HeightMapDemo::Render()
{
	terrain->Render();
}

그리고 실행을 해주면

Map

Texture

잘 보면 하얀색부분이 높게 솟아있다. 그런데 뭔가 이상하다 위 아래가 반대다.

왜냐하면 UV좌표계와 지금 DirectX의 좌표계가 다르기 때문이다.

그래서

UINT pixel = width * (height - 1 - z) + x;

vertices[index].Position.x = (float)x;
vertices[index].Position.y = heights[pixel].r * 255.0f / 10.0f;
vertices[index].Position.z = (float)z;

Vertex를 찍는 부분을 이렇게 바꾸면

잘 나온다.

하지만, wireframe을 색으로만 바꾸면,

와… 그냥 하얀색이다. 왜냐하면 아직 그림자가 없기 때문이다.

이걸 조금만 활용하면, height의 rgb값을 활용해서 높낮이나 다른 텍스쳐를 편하게 활용할 수 있을것 같다. 예를들어 빨간부분은 높이를 낮게 하고, 초록 부분은 물 텍스쳐를 입히고 파랑 부분은 검은색으로 없애던가 할 수 있을 것 같다.



DirectX Share Tweet +1