그리드의 크기가 일정한 지형을 만들어보자.

 

목차

     

     


     

    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