응애맘마조

230721 강의 본문

공부/3D강의

230721 강의

TH.Wert 2023. 7. 23. 21:15

임의의 노드에 노드를 위치시키고 간선으로 연결시키는 것을 강의했습니다. 동시에 과제였습니다.

#pragma once

class DiNode
{
    friend class Di;
private:
    int             id;
    bool            find;   //검색한적 있는가?
    int             prev;   //내가 갱신된 노드
public:
    unordered_map< int, float> linkedList;
    Vector3         pos;
    float     cost;   //현재까지 비용
    DiNode(int id)
    {
        this->id = id;
    }
    void Link(int node, float cost)
    {
        linkedList[node] = cost;
    }
    void Reset()
    {
        prev = -1;
        cost = FLT_MAX;
        find = false;
    }
};

class DiNodeCompare
{
public:
    bool operator()(DiNode*& a, DiNode*& b)
    {
        return a->cost > b->cost;
    }
};

class Di
{
public:
    unordered_map< int, DiNode*> list;
    string                      file = " ";

    int GetNode(Vector3 pos)
    {
        for (auto it = list.begin(); it != list.end(); it++)
        {
            if ((it->second->pos - pos).Length() < 4)
            {
                return it->first;
            }
        }
        return 0;
    }

    DiNode*& AddNode(Vector3 pos)
    {
        int number = 1;
        for (auto it = list.begin(); it != list.end(); it++)
        {
            if (list.find(number) == list.end())
            {
                break;
            }
            number++;
        }
        DiNode* temp = new DiNode(number);
        temp->pos = pos;
        list[number] = temp;
        return temp;
    }
    bool PopNode(int str)
    {
        auto it = list.find(str);
        if (it != list.end())
        {
            for (auto it2 = it->second->linkedList.begin();
                it2 != it->second->linkedList.end(); it2++)
            {
                list[it2->first]->linkedList.erase(str);
            }

            delete it->second;
            list.erase(str);
            return true;
        }
        return false;
    }

    void LinkNode(int str1, int str2)
    {
        if (str1 == str2) return;

        Vector3 temp = list[str1]->pos - list[str2]->pos;
        float dis = temp.Length();
        list[str1]->Link(str2, dis);
        list[str2]->Link(str1, dis);
    }

    std::list<Vector3> PathFinding(int from, int to)
    {
        //노드비용을 초기화
        for (auto it = list.begin(); it != list.end(); it++)
        {
            it->second->Reset();
        }
        //우선순위큐
        priority_queue<DiNode*, vector<DiNode*>, DiNodeCompare>
            Searchlist;

        Searchlist.push(list[from]);
        list[from]->cost = 0;
        list[from]->find = true;

        while (not Searchlist.empty())
        {
            DiNode* top = Searchlist.top();
            Searchlist.pop();

            for (auto it = top->linkedList.begin();
                it != top->linkedList.end(); it++)
            {
                //기존노드의 비용 갱신
                if (list[it->first]->cost > top->cost + it->second)
                {
                    list[it->first]->cost = top->cost + it->second;
                    list[it->first]->prev = top->id;
                    if (not list[it->first]->find)
                    {
                        Searchlist.push(list[it->first]);
                        list[it->first]->find = true;
                    }
                }
            }
        }
        std::list<Vector3> way;
        DiNode* iter = list[to];
        way.push_back(iter->pos);
        while (1)
        {
            iter = list[iter->prev];
            way.push_back(iter->pos);
            if (iter->id == from)
            {
                break;
            }
        }
        return way;
    }
};

class Terrain : public Actor
{
    struct InputDesc
    {
        UINT index;
        Vector3 v0, v1, v2;
    };
    struct OutputDesc
    {
        int picked;
        float u, v, distance;
    };
    struct RayDesc
    {
        Vector3 position;
        float size;
        Vector3 direction;
        float padding;
    };
    static ID3D11ComputeShader* computeShader;
    static class Actor*         Node; //구 모양
    static class Actor*         Line; //선 모양
public:
    static void		CreateStaticMember();
    static void		DeleteStaticMember();
    static Terrain* Create(string Name = "Terrain", int	terrainSize = 257, float uvScale = 1.0f);
private:
    //compute Input
    InputDesc* inputArray;
    ID3D11Resource* input;
    ID3D11ShaderResourceView* srv = nullptr;
    //compute Output
    OutputDesc* outputArray;
    ID3D11Resource* output;
    ID3D11UnorderedAccessView* uav;
    //copy용
    ID3D11Resource* result;
    //ray
    RayDesc                     ray;
    ID3D11Buffer*               rayBuffer;
public:
    Di                          di;
    Terrain(string Name);

    float                       uvScale;
    int                         triSize;
    bool                        showNode;
    void	        RenderDetail();
    void            UpdateMeshUv();
    void            UpdateMeshNormal();

    void            CreateMesh(int Size = 257);
    //CS
    void            CreateStructuredBuffer();
    void            DeleteStructuredBuffer();

    bool            ComPutePicking(Ray WRay, OUT Vector3& HitPoint);
    void            Render() override;

    std::list<Vector3> PathFinding(int from, int to);
};
#include "framework.h"
ID3D11ComputeShader* Terrain::computeShader = nullptr;
Actor* Terrain::Node = nullptr;
Actor* Terrain::Line = nullptr;
void Terrain::CreateStaticMember()
{
    Node = Actor::Create();
    Node->LoadFile("Sphere.xml");
    Line = Actor::Create();
    Line->LoadFile("Line.xml");

    ID3D10Blob* CsBlob;

    wstring path = L"../Shaders/ComputeShader.hlsl";

    DWORD flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG;

    D3DCompileFromFile(path.c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
        "CS", "cs_5_0", flags, 0, &CsBlob, nullptr);

    D3D->GetDevice()->CreateComputeShader(CsBlob->GetBufferPointer(), CsBlob->GetBufferSize(),
        nullptr, &computeShader);
}

void Terrain::DeleteStaticMember()
{
    SafeRelease(computeShader);
}

Terrain* Terrain::Create(string Name, int terrainSize, float uvScale)
{
    Terrain* result = new Terrain(Name);
    result->uvScale = uvScale;
    result->triSize = (terrainSize - 1) * (terrainSize - 1) * 2;
    result->shader = RESOURCE->shaders.Load("5.Cube.hlsl");
    result->CreateMesh(terrainSize);
    result->material = new Material();
    result->material->normalMap = RESOURCE->textures.Load("20000001.png");
    result->material->ambient.w = 1.0f;

    return result;
}

Terrain::Terrain(string Name)
    : Actor()
{
    type = ObType::Terrain;
    name = Name;
    uvScale = 1.0f;
    showNode = false;
}

void Terrain::CreateMesh(int Size)
{
    VertexTerrain* vertices;
    UINT* indices;
    UINT vertexCount;
    UINT indexCount;
    vector<VertexTerrain> VecVertex;
    vector<UINT> Vecindex;

    triSize = (Size - 1) * (Size - 1) * 2;
    float half = Size * 0.5f;

    for (int z = 0; z < Size; z++)
    {
        for (int x = 0; x < Size; x++)
        {
            //배열에 들어갈 인덱스
            int Index = (z * Size) + x;
            float _x = x - half;
            float _z = -z + half;
            float _y = 0.0f;

            float _u = float(x) * uvScale / float(Size - 1);
            float _v = float(z) * uvScale / float(Size - 1);
            VertexTerrain temp;
            temp.uv = Vector2(_u, _v);
            temp.position = Vector3(_x, _y, _z);
            temp.weights.x = 1.0f;
            temp.normal = Vector3(0, 1, 0);
            VecVertex.push_back(temp);
        }
    }

    vertexCount = (UINT)VecVertex.size();
    vertices = new VertexTerrain[vertexCount];

    for (int z = 0; z < Size - 1; z++)
    {
        for (int x = 0; x < Size - 1; x++)
        {
            //Vecindex.push_back(z* MaxZ + x);
            UINT Index = z * Size + x;
            //0
            Vecindex.push_back(Index);

            //1
            Vecindex.push_back(Index + 1);

            //2
            Vecindex.push_back(Index + Size + 1);

            //0
            Vecindex.push_back(Index);

            //1
            Vecindex.push_back(Index + Size + 1);

            //2
            Vecindex.push_back(Index + Size);
        }
    }
    indexCount = (UINT)Vecindex.size();
    indices = new UINT[indexCount];

    copy(VecVertex.begin(), VecVertex.end(),
        stdext::checked_array_iterator<VertexTerrain*>(vertices, vertexCount));
    copy(Vecindex.begin(), Vecindex.end(),
        stdext::checked_array_iterator<UINT*>(indices, indexCount));

    SafeReset(mesh);
    mesh = make_shared<Mesh>(vertices, vertexCount, indices,
        indexCount, VertexType::TERRAIN);

    if (srv)
    {
        DeleteStructuredBuffer();
        CreateStructuredBuffer();
    }
}

void Terrain::UpdateMeshUv()
{
    VertexTerrain* vertices = (VertexTerrain*)mesh->vertices;
    int terrainSize = (int)sqrt(mesh->vertexCount);
    for (int z = 0; z < terrainSize; z++)
    {
        for (int x = 0; x < terrainSize; x++)
        {
            //배열에 들어갈 인덱스
            float _u = float(x) * uvScale / float(terrainSize - 1);
            float _v = float(z) * uvScale / float(terrainSize - 1);
            vertices[z * terrainSize + x].uv = Vector2(_u, _v);
        }
    }
    mesh->Update();
}
void Terrain::UpdateMeshNormal()
{
    VertexTerrain* vertices = (VertexTerrain*)mesh->vertices;

    for (UINT i = 0; i < mesh->vertexCount; i++)
    {
        vertices[i].normal = Vector3();
    }

    //삼각형 갯수만큼 반복
    for (UINT i = 0; i < mesh->indexCount / 3; i++)
    {
        //하나의 삼각형
        UINT index0 = mesh->indices[i * 3 + 0];
        UINT index1 = mesh->indices[i * 3 + 1];
        UINT index2 = mesh->indices[i * 3 + 2];

        Vector3 v0 = vertices[index0].position;
        Vector3 v1 = vertices[index1].position;
        Vector3 v2 = vertices[index2].position;

        Vector3 A = v1 - v0;
        Vector3 B = v2 - v0;

        Vector3 normal = A.Cross(B);

        vertices[index0].normal += normal;
        vertices[index1].normal += normal;
        vertices[index2].normal += normal;
    }
    mesh->Update();
}
void Terrain::CreateStructuredBuffer()
{
    //삼각형 단위
    inputArray = new InputDesc[triSize];
    for (UINT i = 0; i < triSize; i++)
    {
        UINT index0 = mesh->indices[i * 3 + 0];
        UINT index1 = mesh->indices[i * 3 + 1];
        UINT index2 = mesh->indices[i * 3 + 2];

        inputArray[i].v0 = ((VertexTerrain*)(mesh->vertices))[index0].position;
        inputArray[i].v1 = ((VertexTerrain*)(mesh->vertices))[index1].position;
        inputArray[i].v2 = ((VertexTerrain*)(mesh->vertices))[index2].position;

        inputArray[i].index = i;
    }
    //삼각형 단위
    outputArray = new OutputDesc[triSize];

    //input
    {
        ID3D11Buffer* buffer;
        D3D11_BUFFER_DESC desc = {};
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.ByteWidth = sizeof(InputDesc) * triSize;
        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
        desc.StructureByteStride = sizeof(InputDesc);

        D3D11_SUBRESOURCE_DATA initData = {};
        initData.pSysMem = inputArray;

        D3D->GetDevice()->CreateBuffer(&desc, &initData, &buffer);
        input = (ID3D11Resource*)buffer;

        D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
        srvDesc.Format = DXGI_FORMAT_UNKNOWN;
        srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
        srvDesc.BufferEx.FirstElement = 0;
        srvDesc.BufferEx.NumElements = triSize;
        //srv
        D3D->GetDevice()->CreateShaderResourceView(buffer, &srvDesc, &srv);
    }
    //output
    {
        ID3D11Buffer* buffer;
        D3D11_BUFFER_DESC desc = {};
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.ByteWidth = sizeof(OutputDesc) * triSize;
        desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
        desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
        desc.StructureByteStride = sizeof(OutputDesc);

        D3D->GetDevice()->CreateBuffer(&desc, nullptr, &buffer);
        //ID3D11Resource
        output = (ID3D11Resource*)buffer;

        D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
        uavDesc.Format = DXGI_FORMAT_UNKNOWN;
        uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
        uavDesc.Buffer.FirstElement = 0;
        uavDesc.Buffer.NumElements = triSize;
        //uav
        D3D->GetDevice()->CreateUnorderedAccessView(buffer, &uavDesc, &uav);
    }
    //result read
    {
        ID3D11Buffer* buffer;
        D3D11_BUFFER_DESC desc = {};
        ((ID3D11Buffer*)output)->GetDesc(&desc);
        desc.Usage = D3D11_USAGE_STAGING;
        desc.BindFlags = 0;
        desc.MiscFlags = 0;
        desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

        D3D->GetDevice()->CreateBuffer(&desc, nullptr, &buffer);

        result = (ID3D11Resource*)buffer;
    }
    {
        D3D11_BUFFER_DESC desc = { 0 };
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.ByteWidth = sizeof(RayDesc);
        desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

        HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, NULL, &rayBuffer);
        assert(SUCCEEDED(hr));
    }
}

void Terrain::DeleteStructuredBuffer()
{
    input->Release();
    srv->Release();
    output->Release();
    uav->Release();
    result->Release();
    rayBuffer->Release();
    delete[] inputArray;
    delete[] outputArray;
}

bool Terrain::ComPutePicking(Ray WRay, OUT Vector3& HitPoint)
{
    //쉐이더부터 준비
    D3D->GetDC()->CSSetShader(computeShader, 0, 0);

    //raybuffer binding
    ray.position = WRay.position;
    ray.direction = WRay.direction;
    ray.size = (float)triSize;//삼각형갯수
    Matrix inverse = W.Invert();
    ray.direction = Vector3::TransformNormal(ray.direction, inverse);
    ray.direction.Normalize();
    ray.position = Vector3::Transform(ray.position, inverse);

    //트랜스폼한 Ray를 상수버퍼로 바인딩
    D3D->GetDC()->UpdateSubresource(rayBuffer, 0, NULL, &ray, 0, 0);

    D3D->GetDC()->CSSetConstantBuffers(0, 1, &rayBuffer);

    //input binding
    D3D->GetDC()->CSSetShaderResources(0, 1, &srv);
    //output binding
    D3D->GetDC()->CSSetUnorderedAccessViews(0, 1, &uav, nullptr);

    UINT x = (UINT)ceil((float)triSize / 1024.0f);
    D3D->GetDC()->Dispatch(x, 1, 1);

    //동기화

    //gpu -> cpu 복사
    D3D->GetDC()->CopyResource(result, output);

    D3D11_MAPPED_SUBRESOURCE subResource;

    D3D->GetDC()->Map(result, 0, D3D11_MAP_READ, 0, &subResource);
    memcpy(outputArray, subResource.pData, sizeof(OutputDesc) * triSize);
    D3D->GetDC()->Unmap(result, 0);

    float minDistance = FLT_MAX;
    int minIndex = -1;
    for (int i = 0; i < triSize; i++)
    {
        OutputDesc temp = outputArray[i];
        if (temp.picked)
        {
            if (minDistance > temp.distance)
            {
                minDistance = temp.distance;
                minIndex = i;
            }
        }
    }
    if (minIndex >= 0)
    {
        HitPoint = ray.position + ray.direction
            * minDistance;
        HitPoint = Vector3::Transform(HitPoint, W);
        return true;
    }

    return false;
}

void Terrain::Render()
{
    Actor::Render();
    //다익스트라 노드 렌더링
    if (showNode)
    {
        DEPTH->Set(false);
        for (auto it = di.list.begin(); it != di.list.end(); it++)
        {
            Node->SetLocalPos(it->second->pos);
            Node->Update();
            //local * srt;
            Node->W *= W;
            Node->W = S.Invert() * Node->W;

            Node->Render();

            for (auto it2 = it->second->linkedList.begin();
                it2 != it->second->linkedList.end(); it2++)
            {
                Line->mesh->SetVertexPosition(0) = it->second->pos;
                Line->mesh->SetVertexPosition(1) = di.list[it2->first]->pos;
                Line->mesh->Update();
                Line->W = W;
                Line->Render();
            }
        }
        DEPTH->Set(true);
    }
}

std::list<Vector3> Terrain::PathFinding(int from, int to)
{
    std::list<Vector3> way = di.PathFinding(from, to);
    for (auto it = way.begin(); it != way.end(); it++)
    {
        *it = Vector3::Transform(*it, W);
    }
    return way;
}

터레인의 클래스입니다. 노드를 배치하고 간선으로 연결하기 위해 수정했습니다.

#pragma once

struct Brush
{
	int		shape = 0;
	int		texture = 1;
	int     type = 0;
	float 	range = 10.0f;
	float	YScale = 3.0f;
};

class Main : public Scene
{
private:
	Camera* Cam;

	Terrain* terrain;
	
	bool	textureBrush = false;
	bool	nodeEdit = false;

	Actor*	mousePoint;
	int		brushIdx;
	Brush	brush[3];

	struct Brush
	{
		Vector3 point;
		float	range = 2.0f;

		float	shape;
		float	type;
		Vector2 padding;
	} _brush;
	ID3D11Buffer* brushBuffer;

	int nodeState;
	int firstLink;
	int secondLink;

public:
	Main();
	~Main();
	virtual void Init() override;
	virtual void Release() override;
	virtual void Update() override;
	virtual void LateUpdate() override;
	virtual void Render() override;
	virtual void PreRender() override;
	virtual void ResizeScreen() override;
	void NormalizeWeight(Vector4& in);
};
#include "stdafx.h"
#include "Main.h"

Main::Main()
{
	D3D11_BUFFER_DESC desc = { 0 };
	desc.ByteWidth = sizeof(Brush);
	desc.Usage = D3D11_USAGE_DYNAMIC;
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;//상수버퍼
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	desc.MiscFlags = 0;
	desc.StructureByteStride = 0;
	HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, NULL, &brushBuffer);
	assert(SUCCEEDED(hr));
	D3D->GetDC()->PSSetConstantBuffers(10, 1, &brushBuffer);
}

Main::~Main()
{
}

void Main::Init()
{
    Cam = Camera::Create();
    Cam->LoadFile("Cam.xml");
    Camera::main = Cam;

	Cam->width = App.GetWidth();
	Cam->height = App.GetHeight();
	Cam->viewport.width = App.GetWidth();
	Cam->viewport.height = App.GetHeight();

	terrain = Terrain::Create();
	terrain->LoadFile("Terrain.xml");
	terrain->CreateStructuredBuffer();

	mousePoint = Actor::Create();
	mousePoint->LoadFile("Deadpool.xml");
	terrain->showNode = true;

	brushIdx = 0;
	nodeState = 0;
	firstLink = 0;
	secondLink = 0;
}

void Main::Release()
{
}

void Main::Update()
{
	ImGui::Checkbox("nodeEdit", &nodeEdit);

	if (nodeEdit)
	{
		ImGui::Text("firstLink: %d  secondLink: %d", firstLink, secondLink);
		if (ImGui::Button("AddNode"))
		{
			nodeState = 0;
		}
		ImGui::SameLine();
		if (ImGui::Button("DeleteNode"))
		{
			nodeState = 1;
		}
		ImGui::SameLine();
		if (ImGui::Button("LinkNode"))
		{
			nodeState = 2;
		}
	}
	else
	{
		if (GUI->FileImGui("Load", "LoadRawFile",
			".raw,.RAW", "../Contents/Raw"))
		{
			string path = ImGuiFileDialog::Instance()->GetCurrentPath();
			Util::Replace(&path, "\\", "/");
			if (path.find("/Raw/") != -1)
			{
				size_t tok = path.find("/Raw/") + 5;
				path = path.substr(tok, path.length())
					+ "/" + ImGuiFileDialog::Instance()->GetCurrentFileName();
			}
			else
			{
				path = ImGuiFileDialog::Instance()->GetCurrentFileName();
			}
			string file = "../Contents/Raw/" + path;
			FILE* fp;
			//파일 열기
			fopen_s(&fp, file.c_str(), "rb");
			fseek(fp, 0, SEEK_END);
			int Size = ftell(fp);
			fseek(fp, 0, SEEK_SET);

			BYTE* Height = new BYTE[Size];

			for (int i = 0; i < Size; i++)
			{
				char c = fgetc(fp);
				Height[i] = c;
			}

			int terrainSize = (int)sqrt(Size);
			int triSize = (terrainSize - 1) * (terrainSize - 1) * 2;
			float half = terrainSize * 0.5f;

			VertexTerrain* vertices = new VertexTerrain[Size];

			for (int z = 0; z < terrainSize; z++)
			{
				for (int x = 0; x < terrainSize; x++)
				{
					int Index = (z * terrainSize) + x;
					float _x = x - half;
					float _z = -z + half;
					float _y = Height[Index] / 255.0f * (float)terrainSize;

					float _u = float(x) / float(terrainSize - 1);
					float _v = float(z) / float(terrainSize - 1);

					vertices[Index].uv = Vector2(_u, _v);
					vertices[Index].position = Vector3(_x, _y, _z);
					vertices[Index].normal = Vector3(0, 1, 0);
				}
			}

			UINT* indices = new UINT[triSize * 3];
			int Idx = 0;
			for (int z = 0; z < terrainSize - 1; z++)
			{
				for (int x = 0; x < terrainSize - 1; x++)
				{
					UINT Index = z * terrainSize + x;
					indices[Idx] = Index;
					Idx++;
					indices[Idx] = Index + 1;
					Idx++;
					indices[Idx] = Index + terrainSize + 1;
					Idx++;
					indices[Idx] = Index;
					Idx++;
					indices[Idx] = Index + terrainSize + 1;
					Idx++;
					indices[Idx] = Index + terrainSize;
					Idx++;
				}
			}
			terrain->mesh = make_shared<Mesh>(vertices, Size, indices, Idx,
				VertexType::TERRAIN);
			terrain->UpdateMeshNormal();

			//파일 닫기
			fclose(fp);
		}
		ImGui::Text("Select Brush");
		ImGui::Checkbox("textureBrush", &textureBrush);

		for (int i = 0; i < 3; i++)
		{
			string temp = "Brush" + to_string(i);
			if (ImGui::Button(temp.c_str()))
			{
				brushIdx = i;
			}
			if (i < 2)
				ImGui::SameLine();
		}

		ImGui::SliderFloat("brushRange", &brush[brushIdx].range, 1.0f, 100.0f);
		ImGui::SliderFloat("brushYScale", &brush[brushIdx].YScale, -100.0f, 100.0f);
		ImGui::SliderInt("brushType", &brush[brushIdx].type, 0, 2);
		if (ImGui::Button("[]"))
		{
			brush[brushIdx].shape = 1;
		}
		ImGui::SameLine();
		if (ImGui::Button("()"))
		{
			brush[brushIdx].shape = 0;
		}

		if (terrain->material->ambient.w)
		{
			ImVec2 size;
			size.x = 20; size.y = 20;
			if (ImGui::ImageButton((void*)terrain->material->normalMap->srv, size))
			{
				brush[brushIdx].texture = 0;
			}
			ImGui::SameLine();
		}
		if (terrain->material->diffuse.w)
		{
			ImVec2 size;
			size.x = 20; size.y = 20;
			if (ImGui::ImageButton((void*)terrain->material->diffuseMap->srv, size))
			{
				brush[brushIdx].texture = 1;
			}
			ImGui::SameLine();
		}
		if (terrain->material->specular.w)
		{
			ImVec2 size;
			size.x = 20; size.y = 20;
			if (ImGui::ImageButton((void*)terrain->material->specularMap->srv, size))
			{
				brush[brushIdx].texture = 2;
			}
			ImGui::SameLine();
		}
		if (terrain->material->emissive.w)
		{
			ImVec2 size;
			size.x = 20; size.y = 20;
			if (ImGui::ImageButton((void*)terrain->material->emissiveMap->srv, size))
			{
				brush[brushIdx].texture = 3;
			}
		}
	}
	Camera::ControlMainCam();
	//ImGui::SliderFloat3("dirLight", (float*)(&LIGHT->dirLight.direction), -1, 1);

	ImGui::Text("FPS: %d", TIMER->GetFramePerSecond());
	ImGui::Begin("Hierarchy");
	Cam->RenderHierarchy();
	terrain->RenderHierarchy();
	mousePoint->RenderHierarchy();
	//Cam->RenderHierarchy();
	ImGui::End();
	Cam->Update();
	terrain->Update();
	mousePoint->Update();
}

void Main::LateUpdate()
{
	Vector3 Hit;
	if (terrain->ComPutePicking(Util::MouseToRay(), Hit))
	{
		_brush.point = Hit;
		mousePoint->SetWorldPos(Hit);
		
		if (nodeEdit)
		{
			if (INPUT->KeyDown(VK_MBUTTON))
			{
				Matrix inverse = terrain->W.Invert();
				Vector3 localPos = Vector3::Transform(Hit, inverse);
				if (nodeState == 0)
				{
					terrain->di.AddNode(localPos);
				}
				if (nodeState == 1)
				{
					int temp = terrain->di.GetNode(localPos);
					if (temp)
					{
						terrain->di.PopNode(temp);
					}
				}
				if (nodeState == 2)
				{
					if (not firstLink)
					{
						firstLink = terrain->di.GetNode(localPos);
					}
					else
					{
						secondLink = terrain->di.GetNode(localPos);

						terrain->di.LinkNode(firstLink, secondLink);
						secondLink = 0;
						firstLink = 0;
					}
				}
			}
		}
		else
		{
			if (INPUT->KeyPress(VK_MBUTTON))
			{
				VertexTerrain* vertices = (VertexTerrain*)terrain->mesh->vertices;

				Matrix Inverse = terrain->W.Invert();
				Hit = Vector3::Transform(Hit, Inverse);
				float YScale = brush[brushIdx].YScale / terrain->S._22;
				float Range = brush[brushIdx].range / terrain->S._11;

				for (UINT i = 0; i < terrain->mesh->vertexCount; i++)
				{
					Vector3 v1 = Vector3(Hit.x, 0.0f, Hit.z);
					Vector3 v2 = Vector3(vertices[i].position.x,
						0.0f, vertices[i].position.z);
					float w;
					Vector3 temp = v2 - v1;
					float Dis = temp.Length();
					if (brush[brushIdx].shape == 1)
					{
						if (fabs(v1.x - v2.x) < brush[brushIdx].range and
							fabs(v1.z - v2.z) < brush[brushIdx].range)
						{
							//nomalize
							w = Dis / (Range * 1.414f);
							// 0 ~ 1
							w = Util::Saturate(w);

							w = (1.0f - w);
						}
						else
						{
							w = 0.0f;
						}
					}
					if (brush[brushIdx].shape == 0)
					{
						//nomalize
						w = Dis / Range;
						// 0 ~ 1
						w = Util::Saturate(w);

						w = (1.0f - w);
					}

					if (brush[brushIdx].type == 1)
						w = sin(w * PI * 0.5f);

					if (brush[brushIdx].type == 2)
						w = w ? 1 : 0;

					if (textureBrush)
					{
						if (brush[brushIdx].texture == 0)
						{
							vertices[i].weights.x += w * YScale * DELTA;
							vertices[i].weights.y -= w * YScale * DELTA;
							vertices[i].weights.z -= w * YScale * DELTA;
							vertices[i].weights.w -= w * YScale * DELTA;
						}
						if (brush[brushIdx].texture == 1)
						{
							vertices[i].weights.x -= w * YScale * DELTA;
							vertices[i].weights.y += w * YScale * DELTA;
							vertices[i].weights.z -= w * YScale * DELTA;
							vertices[i].weights.w -= w * YScale * DELTA;
						}
						if (brush[brushIdx].texture == 2)
						{
							vertices[i].weights.x -= w * YScale * DELTA;
							vertices[i].weights.y -= w * YScale * DELTA;
							vertices[i].weights.z += w * YScale * DELTA;
							vertices[i].weights.w -= w * YScale * DELTA;
						}
						if (brush[brushIdx].texture == 3)
						{
							vertices[i].weights.x -= w * YScale * DELTA;
							vertices[i].weights.y -= w * YScale * DELTA;
							vertices[i].weights.z -= w * YScale * DELTA;
							vertices[i].weights.w += w * YScale * DELTA;
						}
						NormalizeWeight(vertices[i].weights);
					}
					else
						vertices[i].position.y += w * YScale * DELTA;
				}
				terrain->mesh->Update();
			}
		}
	}

	if (INPUT->KeyUp(VK_MBUTTON))
	{
		terrain->UpdateMeshNormal();
		terrain->DeleteStructuredBuffer();
		terrain->CreateStructuredBuffer();
	}
}
void Main::PreRender()
{
}

void Main::Render()
{
	_brush.range = brush[brushIdx].range;
	_brush.shape = brush[brushIdx].shape;
	_brush.type = brush[brushIdx].type;
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	D3D->GetDC()->Map(brushBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	memcpy_s(mappedResource.pData, sizeof(Brush), &_brush, sizeof(Brush));
	D3D->GetDC()->Unmap(brushBuffer, 0);

	Cam->Set();
	terrain->Render();
	mousePoint->Render();
}

void Main::ResizeScreen()
{
	Cam->width = App.GetWidth();
	Cam->height = App.GetHeight();
	Cam->viewport.width = App.GetWidth();
	Cam->viewport.height = App.GetHeight();
}

void Main::NormalizeWeight(Vector4& in)
{
	float* weight = (float*)&in;
	float	sum = 0;
	for (int i = 0; i < 4; i++)
	{
		weight[i] = Util::Saturate(weight[i]);
		sum += weight[i];
	}
	for (int i = 0; i < 4; i++)
	{
		weight[i] /= sum;
	}
}

int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR param, int command)
{
	App.SetAppName(L"Game1");
	App.SetInstance(instance);
    WIN->Create();
    D3D->Create();
	Main * main = new Main();
    main->Init();

	int wParam = (int)WIN->Run(main);

    main->Release();
	SafeDelete(main);
    D3D->DeleteSingleton();
	WIN->DeleteSingleton();

	return wParam;
}

그렇게 만든 것을 런타임 중에 확인하기 위해 ImGui를 사용하여 원하는 위치에 노드를 배치하고 연결할 수 있도록 했습니다.

노드 추가 및 간선 연결, 노드 삭제영상

읽어주셔서 감사합니다.

'공부 > 3D강의' 카테고리의 다른 글

230725 강의  (0) 2023.07.25
230724 강의  (0) 2023.07.24
230720 강의  (0) 2023.07.20
230719 강의  (0) 2023.07.19
230718 강의  (0) 2023.07.18
Comments