DirectX/DirectX 3D_(구)

18_ModelEditor [2/2]

컴맹학자 2021. 7. 14. 22:20
728x90

Framework(솔루션) -> Model.cpp, h

더보기
#include "Framework.h"
#include "Model.h"
#include "Utilities/BinaryFile.h"

Model::Model()
{
}

Model::~Model()
{
	for (ModelBone* bone : bones)
		SafeDelete(bone);

	for (ModelMesh* mesh : meshes)
		SafeDelete(mesh);
}

void Model::ReadMesh(wstring file)
{
	file = L"../../_Models/" + file + L".mesh";

	BinaryReader* r = new BinaryReader(file);

	UINT count = 0;
	count = r->UInt();
	for (UINT i = 0; i < count; i++)
	{
		ModelBone* bone = new ModelBone();

		bone->index = r->Int();
		bone->name = String::ToWString(r->String());
		bone->parentIndex = r->Int();
		bone->transform = r->Matrix();

		bones.push_back(bone);
	}

	count = r->UInt();
	for (UINT i = 0; i < count; i++)
	{
		ModelMesh* mesh = new ModelMesh();

		mesh->boneIndex = r->Int();

		//VertexData
		{
			UINT count = r->UInt();

			vector<Model::VertexModel> vertices;
			vertices.assign(count, Model::VertexModel());

			void* ptr = (void*)&(vertices[0]);
			r->Byte(&ptr, sizeof(Model::VertexModel) * count);

			mesh->vertices = new Model::VertexModel[count];
			mesh->vertexCount = count;
			copy
			(
				vertices.begin(), vertices.end(),
				stdext::checked_array_iterator<Model::VertexModel*>(mesh->vertices, count)
			);
		}

		//IndexData
		{
			UINT count = r->UInt();

			vector<UINT> indices;
			indices.assign(count, sizeof(UINT));

			void* ptr = (void*)&(indices[0]);
			r->Byte(&ptr, sizeof(UINT) * count);

			mesh->indices = new UINT[count];
			mesh->indexCount = count;
			copy
			(
				indices.begin(), indices.end(),
				stdext::checked_array_iterator<UINT*>(mesh->indices, count)
			);
		}

		//MeshPart::DrawCall에 사용될 값
		UINT partCount = r->UInt();
		for (UINT k = 0; k < partCount; k++)
		{
			ModelMeshPart* meshPart = new ModelMeshPart();
			meshPart->materialName = String::ToWString(r->String());

			meshPart->startVertex = r->UInt();
			meshPart->vertexCount = r->UInt();

			meshPart->startIndex = r->UInt();
			meshPart->indexCount = r->UInt();

			mesh->meshParts.push_back(meshPart);
		}

		meshes.push_back(mesh);
	}
	SafeDelete(r);

	BindBone();
	BindMesh();
}

void Model::BindBone()
{
	root = bones[0]; //root Bone

	for (ModelBone* bone : bones)
	{
		//부모가 없다면
		if (bone->parentIndex > -1)
		{
			bone->parent = bones[bone->parentIndex];
			bone->parent->childs.push_back(bone);
		}
		else
			bone->parent = NULL;
	}

}

void Model::BindMesh()
{
	//모델이 보유한 Mesh(덩어리) 개수만큼 돌면서
	for (ModelMesh* mesh : meshes)
	{
		mesh->bone = bones[mesh->boneIndex]; //이 Mesh가 참조할 뽄을 저장
		mesh->Binding(this);
	}
}

ModelBone * Model::BoneByName(wstring name)
{
	for (ModelBone* bone : bones)
	{
		if (name == bone->Name())
			return bone;
	}

	return NULL;
}

 

#pragma once

#define MAX_MODEL_TRANSFORMS 250

class ModelBone;
class ModelMesh;
class ModelMeshPart;

class Model
{
public:
	friend class ModelRender;
	struct VertexModel;

private:
	Model();
	~Model();

private:
	//.mesh 파일 불러오기
	void ReadMesh(wstring file);

private:
	//부모, 자식 관계가 맺어진 bone을 bones에 저장
	void BindBone();
	//이 모델이 가진 Mesh(덩어리)를 meshes에 저장
	void BindMesh();

public:
	UINT BoneCount() { return bones.size(); }
	vector<ModelBone*>& Bones() { return bones; }
	ModelBone* BoneByIndex(UINT index) { return bones[index]; }
	ModelBone* BoneByName(wstring name);

	UINT MeshCount() { return meshes.size(); }
	vector<ModelMesh*>& Meshes() { return meshes; }
	ModelMesh* MeshByIndex(UINT index) { return meshes[index]; }

public:
	struct VertexModel
	{
		Vector3 Position;
		Vector2 Uv;
		Vector3 Normal;
		Vector3 Tangent; //NormalMapping
		Vector4 BlendIndices; //Animation Skinning
		Vector4 BlendWeights;

		VertexModel()
		{
			Position = Vector3(0, 0, 0);
			Uv = Vector2(0, 0);
			Normal = Vector3(0, 0, 0);
			Tangent = Vector3(0, 0, 0);
			BlendIndices = Vector4(0, 0, 0, 0);
			BlendWeights = Vector4(0, 0, 0, 0);
		}
	};

private:
	ModelBone* root;

	vector<ModelBone*> bones;
	vector<ModelMesh*> meshes;
};

Framework(솔루션) -> ModelMesh.cpp, h

더보기
#include "Framework.h"
#include "ModelMesh.h"

ModelBone::ModelBone()
{
}

ModelBone::~ModelBone()
{
	
}

///////////////////////////////////////////////////////////////////////////////

ModelMesh::ModelMesh()
{
	boneBuffer = new ConstantBuffer(&boneDesc, sizeof(BoneDesc));
}

ModelMesh::~ModelMesh()
{
	SafeDelete(transform);
	SafeDelete(perframe);

	SafeDeleteArray(vertices);
	SafeDeleteArray(indices);

	SafeDelete(vertexBuffer);
	SafeDelete(indexBuffer);

	SafeDelete(boneBuffer);

	for (ModelMeshPart* part : meshParts)
		SafeDelete(part);
}

void ModelMesh::Binding(Model * model)
{
	vertexBuffer = new VertexBuffer(vertices, vertexCount, sizeof(Model::VertexModel));
	indexBuffer = new IndexBuffer(indices, indexCount);

	for (ModelMeshPart* part : meshParts)
		part->Binding(model);
}

void ModelMesh::Pass(UINT val)
{
	for (ModelMeshPart* part : meshParts)
		part->Pass(val);
}

void ModelMesh::SetShader(Shader * shader)
{
	this->shader = shader;

	SafeDelete(transform);
	transform = new Transform(shader);

	SafeDelete(perframe);
	perframe = new PerFrame(shader);

	sBoneBuffer = shader->AsConstantBuffer("CB_Bones");

	for (ModelMeshPart* part : meshParts)
		part->SetShader(shader);
}

void ModelMesh::Update()
{
	boneDesc.BoneIndex = boneIndex;

	perframe->Update();
	transform->Update();

	for (ModelMeshPart* part : meshParts)
		part->Update();
}

void ModelMesh::Render()
{
	boneBuffer->Render();
	sBoneBuffer->SetConstantBuffer(boneBuffer->Buffer());

	perframe->Render();
	transform->Render();

	vertexBuffer->Render();
	indexBuffer->Render();

	D3D::GetDC()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	for (ModelMeshPart* part : meshParts)
		part->Render();
}

void ModelMesh::Transforms(Matrix * transforms)
{
	memcpy(boneDesc.Transforms, transforms, sizeof(Matrix) * MAX_MODEL_TRANSFORMS);
}

void ModelMesh::SetTransform(Transform * transform)
{
	this->transform->Set(transform);
}

///////////////////////////////////////////////////////////////////////////////

ModelMeshPart::ModelMeshPart()
{
}

ModelMeshPart::~ModelMeshPart()
{
}

void ModelMeshPart::Update()
{
}

void ModelMeshPart::Render()
{
	shader->DrawIndexed(0, pass, indexCount, startIndex);
}

void ModelMeshPart::Binding(Model * model)
{
}

void ModelMeshPart::SetShader(Shader* shader)
{
	this->shader = shader;
}

 

#pragma once

class ModelBone
{
public:
	friend class Model;

private:
	ModelBone();
	~ModelBone();

public:
	int Index() { return index; }
	
	int ParentIndex() { return parentIndex; }
	ModelBone* Parent() { return parent; }

	wstring Name() { return name; }

	Matrix& Transform() { return transform; }
	void Transform(Matrix& matrix) { transform = matrix; }

	vector<ModelBone*>& Childs() { return childs; }

private:
	int index;
	wstring name;

	int parentIndex;
	ModelBone* parent;

	Matrix transform;
	vector<ModelBone*> childs;
};

///////////////////////////////////////////////////////////////////////////////

class ModelMesh
{
public:
	friend class Model;

private:
	ModelMesh();
	~ModelMesh();

	//vBuffer, iBuffer 생성, (MeshPart들의 Material 할당)
	void Binding(Model* model);

public:
	//pass 변경 시 하위 MeshPart들에게 모두 적용
	void Pass(UINT val);

	//Shader 변경 시 transform, perframe 다시 생성
	void SetShader(Shader* shader);

	//ModelRender에서 반복문 내부에서 호출될 함수
	void Update();
	
	//vBuffer, iBuffer, cBuffer 쉐이더로 밀어주기
	void Render();

	//Get
	int BoneIndex() { return boneIndex; }
	class ModelBone* Bone() { return bone; }
	
	//모델의 개별 Bone을 받아서 boneBuffer::Transforms[] 변수에 세팅해주는 역할
	void Transforms(Matrix* transforms);

	void SetTransform(Transform* transform);

private:
	struct BoneDesc
	{
		Matrix Transforms[MAX_MODEL_TRANSFORMS]; //Bone의 개별 위치
		
		UINT BoneIndex;
		float Padding[3];
	} boneDesc;

private:
	Shader* shader;

	Transform* transform = NULL; //모델의 대표 위치
	PerFrame* perframe = NULL; //VP

	int boneIndex; //메쉬가 참조할 Bone번호
	ModelBone* bone; //메쉬가 붙을 Bone

	//IA
	VertexBuffer* vertexBuffer;
	UINT vertexCount;
	Model::VertexModel* vertices;

	IndexBuffer* indexBuffer;
	UINT indexCount;
	UINT* indices;

	ConstantBuffer* boneBuffer;
	ID3DX11EffectConstantBuffer* sBoneBuffer;

	vector<class ModelMeshPart*> meshParts;
};

///////////////////////////////////////////////////////////////////////////////

class ModelMeshPart
{
public:
	friend class Model;
	friend class ModelMesh;

private:
	ModelMeshPart();
	~ModelMeshPart();

	void Update();
	void Render();

	//모델이 가진 Material을 MeshPart에 저장해주기
	void Binding(Model* model);

	//shader 멤버 변수에 저장
	void SetShader(Shader* shader);

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

private:
	Shader* shader;
	UINT pass = 0;

	wstring materialName;

	UINT startVertex;
	UINT vertexCount;

	UINT startIndex;
	UINT indexCount;
};

Framework(솔루션) -> ModelRender.cpp, h

더보기
#include "Framework.h"
#include "ModelRender.h"

ModelRender::ModelRender(Shader * shader)
	: shader(shader)
{
	model = new Model();

	transform = new Transform(shader);
}

ModelRender::~ModelRender()
{
	SafeDelete(model);
	SafeDelete(transform);
}

void ModelRender::Update()
{
	if (bRead == true)
	{
		bRead = false;

		for (ModelMesh* mesh : model->Meshes())
			mesh->SetShader(shader);

		UpdateTransforms();
	}

	for (ModelMesh* mesh : model->Meshes())
		mesh->Update();
}

void ModelRender::Render()
{
	static int index = -1;
	ImGui::InputInt("Index", &index);

	if (index >= model->MeshCount())
		index = -1;
	
	if (index < 0)
	{
		for (ModelMesh* mesh : model->Meshes())
		{
			mesh->SetTransform(transform);
			mesh->Render();
		}
	}
	else
	{
		ModelMesh* mesh = model->MeshByIndex(index);
		mesh->SetTransform(transform);
		mesh->Render();
	}

	
}

void ModelRender::ReadMesh(wstring file)
{
	bRead = true;

	model->ReadMesh(file);
}

void ModelRender::Pass(UINT pass)
{
	for (ModelMesh* mesh : model->Meshes())
		mesh->Pass(pass);
}

void ModelRender::UpdateTransforms()
{
	for (UINT i = 0; i < model->BoneCount(); i++)
	{
		ModelBone* bone = model->BoneByIndex(i);
		transforms[i] = bone->Transform();
	}

	for (ModelMesh* mesh : model->Meshes())
		mesh->Transforms(transforms);
}

 

#pragma once

class ModelRender
{
public:
	ModelRender(Shader* shader);
	~ModelRender();

	//ModelMesh::Update()
	void Update();

	//ModelMesh::Render()
	void Render();

public:
	void ReadMesh(wstring file); //model->Read();

	Transform* GetTransform() { return transform; } //모델 대표 위치 리턴
	Model* GetModel() { return model; }

	void Pass(UINT pass);

private:
	//모델이 가진 모든 bone을 transforms[]로 복사
	void UpdateTransforms();

private:
	bool bRead = false; //ReadFile이 수행된 후 true

	Shader* shader;
	Model* model;

	Transform* transform; //모델 대표 위치

	Matrix transforms[MAX_MODEL_TRANSFORMS]; //관계를 가진 개별Bone
};

ModelEditor(솔루션) -> ModelDemo.cpp. h

더보기
#include "stdafx.h"
#include "ModelDemo.h"
#include "Converter.h"

void ModelDemo::Initialize()
{
	shader = new Shader(L"17_Model.fxo");

	Tank();
	Kachujin();

	sky = new CubeSky(L"Environment/SnowCube1024.dds");
	
	planeShader = new Shader(L"15_Mesh.fxo");
	plane = new MeshPlane(planeShader, 6, 6);
	plane->GetTransform()->Scale(12, 1, 12);
	plane->DiffuseMap(L"Floor.png");
}

void ModelDemo::Destroy()
{
	SafeDelete(shader);
	SafeDelete(sky);

	SafeDelete(planeShader);
	SafeDelete(plane);
	
	SafeDelete(tank);
	SafeDelete(kachujin);
}

void ModelDemo::Update()
{
	static Vector3 LightDirection = Vector3(-1, -1, +1);
	ImGui::SliderFloat3("LightDirection", LightDirection, -1, 1);
	shader->AsVector("LightDirection")->SetFloatVector(LightDirection);
	planeShader->AsVector("LightDirection")->SetFloatVector(LightDirection);

	static UINT Pass = 0;
	ImGui::InputInt("Pass", (int*)&Pass);
	Pass %= 2;

	sky->Update();
	plane->Update();

	if (tank != NULL)
	{
		tank->Pass(Pass);
		tank->Update();
	}

	if (kachujin != NULL)
	{
		kachujin->Pass(Pass);
		kachujin->Update();
	}

}

void ModelDemo::Render()
{
	sky->Render();
	plane->Render();

	if (tank != NULL)
		tank->Render();

	if (kachujin != NULL)
		kachujin->Render();
}

void ModelDemo::Tank()
{
	tank = new ModelRender(shader);
	tank->ReadMesh(L"Tank/Tank");
}

void ModelDemo::Kachujin()
{
	kachujin = new ModelRender(shader);
	kachujin->ReadMesh(L"Kachujin/Mesh");

	kachujin->GetTransform()->Position(5, 0, 0);
	kachujin->GetTransform()->Scale(0.01f, 0.01f, 0.01f);
}

 

#pragma once
#include "Systems/IExecute.h"

class ModelDemo : public IExecute
{
public:
	virtual void Initialize() 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:
	void Tank();
	void Kachujin();

private:
	Shader* shader;
	ModelRender* tank = NULL;
	ModelRender* kachujin = NULL;

	CubeSky* sky;
	Shader* planeShader;
	MeshPlane* plane;
};

실행

 


보충

 

[1/2] ~ [2/2] 전체 흐름은 다음과 같이 순서를 가짐

1. ModelEditor 솔루션 안에 있는 ExportFile class 에서 해당 모델 파일(Fbx)을 바이너리 파일로 만들어 버림

2. Framework 솔루션 Model 필터안에 있는 3개의 Model 관련 클래스에서 바이너리 파일을 읽고 렌더링 할 수 있게 셋팅 및 쉐이더에 값 넘기는 코드 작성

3. ModelEditor 솔루션 ModelDemo를 통해서 확인을 하는데 해당 모델들은 ModelRender 으로 선언해서 모델을 출력

 

Model.cpp : 바이너리 파일을 읽고 값을 ModelMesh 클래스에 셋팅 

ModelMesh : Model 통해서만 접근이 가능하고 별도의 3가지 클래스가 내부적으로 선언

 -> ModelBone : Mesh의 월드 관련 

 -> ModelMesh : Mesh 관련 버퍼 및 출력 쉐이더에 값을 셋팅 관련

 -> ModelMeshPart : 마테리얼  관련

ModelRender : model, modelmesh 클래스통해서 mesh 바이너리 읽고 셋팅을 해서 최종적으로 렌더링 하는 클래스

'DirectX > DirectX 3D_(구)' 카테고리의 다른 글

19_ModelMaterial [2/2]  (0) 2021.07.19
19_ModelMaterial [1/2]  (0) 2021.07.17
18_ModelEditor [1/2]  (0) 2021.07.13
17_Framework (Transform, PerFrame, Renderer)  (0) 2021.07.13
17_Framework (Buffer + hlsl)  (0) 2021.07.07