필요한 개념
- Redering 부분을 따로 Renderer 클래스로 처리해서 좀 더 코드가 간편해졌습니다.
- Renderer Class
<DirectX11 3D> 32. Renderer
필요한 개념 - Renderer : 정점 버퍼, 인덱스 버퍼, Perframe, 한번에 묶어서 관리(+ Transform) Why? 그려질 친구들은 이 친구를 상속 받는다. - PerFrame https://cpplab.tistory.com/26 32. Renderer - PerFram..
cpplab.tistory.com
.h
더보기
#pragma once
class Terrain : public Renderer
{
public:
typedef VertexNormal TerrainVertex;
public:
Terrain(Shader* shader, wstring heightFile);
~Terrain();
void Update() override;
void Render() override;
float GetHeight(Vector3& position);
float GetVerticalRaycast(Vector3& position);
private:
void CreateVertexData();
void CreateIndexData();
void CreateNormalData();
void CreateBuffer();
private:
Texture* height_map;
UINT width, height;
UINT vertexCount;
TerrainVertex* vertices;
UINT indexCount;
UINT* indices;
};
.Cpp
더보기
#include "Framework.h"
#include "Terrain.h"
Terrain::Terrain(Shader* shader, wstring heightFile) :
Renderer(shader)
{
height_map = new Texture(heightFile);
CreateVertexData();
CreateIndexData();
CreateNormalData();
CreateBuffer();
}
Terrain::~Terrain()
{
SafeDelete(height_map);
SafeDeleteArray(vertices);
SafeDeleteArray(indices);
}
void Terrain::Update()
{
static Vector3 direction = Vector3(-1, -1, 1);
ImGui::SliderFloat3("Direction", direction, -1, 1);
shader->AsVector("Direction")->SetFloatVector(direction);
Super::Update();
}
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));
//}
Super::Render();
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;
}
float Terrain::GetVerticalRaycast(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 p[4];
for (int i = 0; i < 4; i++)
p[i] = vertices[index[i]].Position;
// 50 = 지면 최대 높이 + 플레이어 사이즈
Vector3 start(position.x, 50, position.z);
Vector3 direction(0, -1, 0);
float u, v, distance;
Vector3 result(-1, FLT_MIN, -1);
// 체크할 삼각형 3개, 반직선 방향
// U(ddx), V(ddz)가 리턴됨
// 왼쪽 삼각형 체크
if (D3DXIntersectTri(&p[0], &p[1], &p[2], &start, &direction, &u, &v, &distance) == TRUE)
result = p[0] + (p[1] - p[0]) * u + (p[2] - p[0]) * v;
// 오른쪽 삼각형 체크
if (D3DXIntersectTri(&p[3], &p[1], &p[2], &start, &direction, &u, &v, &distance) == TRUE)
result = p[3] + (p[1] - p[3]) * u + (p[2] - p[3]) * v;
return result.y;
}
void Terrain::CreateVertexData()
{
vector<Color> heights;
height_map->ReadPixel(DXGI_FORMAT_R8G8B8A8_UNORM, &heights);
width = height_map->GetWidth();
height = height_map->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;
// 10은 작게 보이기 위해 오프셋
vertices[index].Position.y = heights[pixel].r * 255.0f / 10;
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++)
{
// 이렇게 하면 어느 삼각형이던 시작점 나옴(0, 1, 2, 2, 1, 3)
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()
{
vertexBuffer = new VertexBuffer(vertices, vertexCount, sizeof(TerrainVertex));
indexBuffer = new IndexBuffer(indices, indexCount);
}
.fx
더보기
#include "00_Global.fx"
float3 Direction;
struct VertexOutput
{
float4 Position : SV_Position;
float3 Normal : Normal;
};
VertexOutput VS(VertexNormal input)
{
VertexOutput output;
output.Position = WorldPosition(input.Position);
output.Position = ViewProjection(output.Position);
output.Normal = WorldNormal(input.Normal);
return output;
}
float4 PS(VertexOutput input) : SV_Target
{
float3 normal = normalize(input.Normal);
// 뒤집는다.
float3 light = -Direction;
return float4(1, 1, 1, 1) * dot(light, normal);
}
technique11 T0
{
P_VP(P0, VS, PS)
P_RS_VP(P1, FillMode_WireFrame, VS, PS)
}
결과
기존이랑 같은 결과 입니다. 차이점은 Terrain class가 Renderer만 상속했습니다.
'DirectX11 3D > 과제' 카테고리의 다른 글
<DirectX11 3D 과제 > 68 - Unprojection을 이용한 이동 (0) | 2022.03.07 |
---|---|
<DirectX11 3D 과제> 42 - 모델 다운 받아 렌더링 해보기 (0) | 2022.02.15 |
<DirectX11 3D 과제> 39 - Model(Bone + Mesh + Material) 탱크 움직이기 (0) | 2022.02.13 |
<DirectX11 3D 과제> 39 - Model(Bone + Mesh + Material) 내용 정리 (0) | 2022.02.10 |
<DirectX11 3D 과제> 39 - XML 파일 형식이란? (0) | 2022.02.10 |