[DirectX11] 023 Get Height
그리드의 크기가 일정한 지형을 만들어보자.
목차
Get Height
( V2 - V0 ) x ( x - V0.x)
ddx = (position.x - v[0].x) / 1.0f;
ddz = (position.z - v[0].z) / 1.0f;
V0 + ( V2 - V0 ) * ( x - V0.x) + ( V1 - V0 ) * ( z - V0.z)
v[0] + (v[2] - v[0]) * ddx + (v[1] - v[0]) * ddz;
V3 + ( V1 - V3 ) * ddx + ( V2 - V0) * ddz
v[3] + (v[1] - v[3]) * ddx + (v[2] - v[3]) * ddz;
- ddx + ddz < 1 인 경우, 좌측하단 삼각형 안에 위치
- ddx + ddz > 1 인 경우, 우측상단 삼각형 안에 위치
Terrain
Terrain.h
더보기
#pragma once
class Terrain
{
public:
typedef VertexNormal TerrainVertex;
public:
Terrain(Shader* shader, wstring heightFile);
~Terrain();
void Update();
void Render();
void Pass(UINT val) { pass = val; }
float GetHeight(Vector3& position);
private:
void CreateVertexData();
void CreateIndexData();
void CreateNormalData();
void CreateBuffer();
private:
UINT pass = 0;
Shader* shader;
Texture* heightMap;
UINT width, height;
UINT vertexCount;
TerrainVertex* vertices;
ID3D11Buffer* vertexBuffer;
UINT indexCount;
UINT* indices;
ID3D11Buffer* indexBuffer;
};
Terrain.cpp
더보기
#include "Framework.h"
#include "Terrain.h"
Terrain::Terrain(Shader * shader, wstring heightFile)
: shader(shader)
{
heightMap = new Texture(heightFile);
CreateVertexData();
CreateIndexData();
CreateNormalData();
CreateBuffer();
}
Terrain::~Terrain()
{
SafeDelete(heightMap);
SafeDeleteArray(vertices);
SafeDeleteArray(indices);
SafeRelease(vertexBuffer);
SafeRelease(indexBuffer);
}
void Terrain::Update()
{
static Vector3 direction = Vector3(-1, -1, 1);
ImGui::SliderFloat3("Direction", direction, -1, 1);
shader->AsVector("Direction")->SetFloatVector(direction);
Matrix world;
D3DXMatrixIdentity(&world);
shader->AsMatrix("World")->SetMatrix(world);
shader->AsMatrix("View")->SetMatrix(Context::Get()->View());
shader->AsMatrix("Projection")->SetMatrix(Context::Get()->Projection());
}
void Terrain::Render()
{
//for (int i = 0; i < vertexCount; i++)
//{
// Vector3 start = vertices[i].Position;
// Vector3 end = vertices[i].Position + vertices[i].Normal * 2;
// DebugLine::Get()->RenderLine(start, end, Color(0, 1, 0, 1));
//}
UINT stride = sizeof(TerrainVertex);
UINT offset = 0;
D3D::GetDC()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3D::GetDC()->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
D3D::GetDC()->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0);
shader->DrawIndexed(0, pass, indexCount);
}
float Terrain::GetHeight(Vector3 & position)
{
UINT x = (UINT)position.x;
UINT z = (UINT)position.z;
if (x < 0 || x > width) return FLT_MIN;
if (z < 0 || z > height) return FLT_MIN;
UINT index[4];
index[0] = width * z + x;
index[1] = width * (z + 1) + x;
index[2] = width * z + x + 1;
index[3] = width * (z + 1) + x + 1;
Vector3 v[4];
for (int i = 0; i < 4; i++)
v[i] = vertices[index[i]].Position;
float ddx = (position.x - v[0].x) / 1.0f;
float ddz = (position.z - v[0].z) / 1.0f;
Vector3 result;
if(ddx + ddz <= 1.0f)
result = v[0] + (v[2] - v[0]) * ddx + (v[1] - v[0]) * ddz;
else
{
//값을 뒤집어준다.
ddx = 1.0f - ddx;
ddz = 1.0f - ddz;
result = v[3] + (v[1] - v[3]) * ddx + (v[2] - v[3]) * ddz;
}
return result.y;
}
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;
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;
}
}
}
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;
}
}
}
void Terrain::CreateNormalData()
{
for (UINT i = 0; i < indexCount / 3; i++)
{
UINT index0 = indices[i * 3 + 0];
UINT index1 = indices[i * 3 + 1];
UINT index2 = indices[i * 3 + 2];
TerrainVertex v0 = vertices[index0];
TerrainVertex v1 = vertices[index1];
TerrainVertex v2 = vertices[index2];
Vector3 a = v1.Position - v0.Position;
Vector3 b = v2.Position - v0.Position;
Vector3 normal;
D3DXVec3Cross(&normal, &a, &b);
vertices[index0].Normal += normal;
vertices[index1].Normal += normal;
vertices[index2].Normal += normal;
}
for (UINT i = 0; i < vertexCount; i++)
D3DXVec3Normalize(&vertices[i].Normal, &vertices[i].Normal);
}
void Terrain::CreateBuffer()
{
//Create Vertex Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(TerrainVertex) * vertexCount;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = vertices;
Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &vertexBuffer));
}
//Create Index Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(UINT) * indexCount;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = indices;
Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &indexBuffer));
}
}
GetHeight
GetHeightDemo.h
더보기
#pragma once
#include "Systems/IExecute.h"
class GetHeightDemo : public IExecute
{
public:
virtual void Initialize() override;
virtual void Ready() override {}
virtual void Destroy() override;
virtual void Update() override;
virtual void PreRender() override {}
virtual void Render() override;
virtual void PostRender() override {}
virtual void ResizeScreen() override {}
private:
Shader* shader;
Terrain* terrain;
Vector3 position = Vector3(0, 0, 0);
Shader* triShader;
ID3D11Buffer* vertexBuffer;
};
GetHeightDemo.cpp
더보기
#include "stdafx.h"
#include "GetHeightDemo.h"
void GetHeightDemo::Initialize()
{
Context::Get()->GetCamera()->RotationDegree(12, 0, 0);
Context::Get()->GetCamera()->Position(35, 10, -55);
((Freedom *)Context::Get()->GetCamera())->Speed(20);
shader = new Shader(L"19_Terrain.fx");
terrain = new Terrain(shader, L"Terrain/Gray256.png");
terrain->Pass(1);
triShader = new Shader(L"09_World.fx");
Vertex vertices[3];
vertices[0].Position = Vector3(+0, +1, 0);
vertices[1].Position = Vector3(-1, +0, 0);
vertices[2].Position = Vector3(+1, +0, 0);
//Create Vertex Buffer
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(Vertex) * 3;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = vertices;
Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &vertexBuffer));
}
}
void GetHeightDemo::Destroy()
{
SafeDelete(shader);
SafeDelete(terrain);
SafeDelete(triShader);
SafeRelease(vertexBuffer);
}
void GetHeightDemo::Update()
{
terrain->Update();
if (Keyboard::Get()->Press(VK_RIGHT))
position.x += 20.0f * Time::Delta();
else if (Keyboard::Get()->Press(VK_LEFT))
position.x -= 20.0f * Time::Delta();
if (Keyboard::Get()->Press(VK_UP))
position.z += 20.0f * Time::Delta();
else if (Keyboard::Get()->Press(VK_DOWN))
position.z -= 20.0f * Time::Delta();
//float Terrain::GetHeight()에서 return result.y값을 가져다쓴다.
//기준점인 vertices[0].Position = Vector3(0, 1, 0). 기준점 y값이 1이므로 1.0f를 더해준다.
position.y = terrain->GetHeight(position) + 1.0f;
Matrix R, T;
D3DXMatrixRotationX(&R, Math::ToRadian(180));
D3DXMatrixTranslation(&T, position.x, position.y, position.z);
Matrix world = R * T;
triShader->AsMatrix("World")->SetMatrix(world);
triShader->AsMatrix("View")->SetMatrix(Context::Get()->View());
triShader->AsMatrix("Projection")->SetMatrix(Context::Get()->Projection());
}
void GetHeightDemo::Render()
{
terrain->Render();
UINT stride = sizeof(Vertex);
UINT offset = 0;
D3D::GetDC()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3D::GetDC()->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
triShader->Draw(0, 0, 3);
string str = to_string(position.x) + ", " + to_string(position.y) + ", " + to_string(position.z);
Gui::Get()->RenderText(5, 60, str);
}
실행화면
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 025~26 Mesh (0) | 2023.01.21 |
---|---|
[DirectX11] 024 Vertical Raycast (0) | 2023.01.20 |
[DirectX11] 020~22 Normal Vector (0) | 2023.01.18 |
[DirectX11] 019 Heightmap (0) | 2023.01.16 |
[DirectX11] 018 Texture Sampler (0) | 2023.01.16 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 025~26 Mesh
[DirectX11] 025~26 Mesh
2023.01.21 -
[DirectX11] 024 Vertical Raycast
[DirectX11] 024 Vertical Raycast
2023.01.20 -
[DirectX11] 020~22 Normal Vector
[DirectX11] 020~22 Normal Vector
2023.01.18 -
[DirectX11] 019 Heightmap
[DirectX11] 019 Heightmap
2023.01.16