728x90
시작전에 Model 파일을 추출 저장 하기위한 솔루션 하나를 생성
그럼 아래와 같이 3개의 솔루션이 나오고 시작 프로그램을 ModelEditor로 걸고 종속성도 수정
ModelEditor(솔루션) -> stdafx.h
더보기
#pragma once
#include "Framework.h"
#pragma comment(lib, "../Debug/Framework.lib")
//모델 변환 하는 파일들
//디자인이 만든 모델 파일을 불러옴 (fbx, obj)
#include "Assimp/Importer.hpp"
//소스로 불러올때 다양한 옵션을 줄 수 있음 (좌표계, UV 읽어오는 순서)
#include "Assimp/postprocess.h"
//postprocess를 통해 불러온 값 (RootNode -> (Bone, Tree형태) , Meshes, Material, Animations 등 -> 배열 형태로 들어옴)
#include "Assimp/scene.h"
#pragma comment(lib, "Assimp/assimp-vc140-mt.lib")
ModelEditor(솔루션) -> Types, h
더보기
#pragma once
#include "stdafx.h"
struct asBone
{
int Index;
string Name;
int Parent;
Matrix Transform;
};
struct asMeshPart
{
string MaterialName;
//DPCall에서 사용하기 위함
UINT StartVertex;
UINT VertexCount;
UINT StartIndex;
UINT IndexCount;
};
struct asMesh
{
int BoneIndex;
vector<Model::VertexModel> Vertices;
vector<UINT> indices;
vector<asMeshPart*> MeshParts;
};
ModelEditor(솔루션) -> Converter.cpp, h
더보기
#include "stdafx.h"
#include "Converter.h"
#include "Types.h"
#include "Utilities/BinaryFile.h"
Converter::Converter()
{
importer = new Assimp::Importer();
}
Converter::~Converter()
{
SafeDelete(importer);
}
//파일 읽기
void Converter::ReadFile(wstring file)
{
this->file = L"../../_Assets/" + file;
//aiProcess_ConvertToLeftHanded -> 왼손좌표계, CW
//aiProcess_Triangulate -> 삼각형으로 그려주게 만듬
//aiProcess_GenUVCoords -> UV에 맞게 다시 계산
//aiProcess_GenNormals -> 법선 백터이 있으면 가져옴
//aiProcess_CalcTangentSpace -> 탄젠트를 가져옴
scene = importer->ReadFile
(
String::ToString(this->file),
aiProcess_ConvertToLeftHanded | aiProcess_Triangulate | aiProcess_GenUVCoords
| aiProcess_GenNormals | aiProcess_CalcTangentSpace
);
if (scene == NULL)
{
string str = importer->GetErrorString();
MessageBoxA(D3D::GetDesc().Handle, str.c_str(), "Assimp Error", MB_OK);
exit(-1);
}
}
//파일 추출
void Converter::ExportMesh(wstring savePath)
{
ReadBoneData(scene->mRootNode, -1, -1);
WriteMeshData(L"../../_Models/" + savePath + L".mesh");
//file test
{
FILE* file;
fopen_s(&file, "../BoneData.csv", "w");
for (asBone* bone : bones)
{
fprintf(file, "%d,%d,%s\n", bone->Index, bone->Parent, bone->Name.c_str());
}
fclose(file);
}
}
void Converter::ReadBoneData(aiNode * node, int index, int parent)
{
asBone* bone = new asBone();
bone->Index = index;
bone->Parent = parent;
bone->Name = node->mName.C_Str();
Matrix transform(node->mTransformation[0]);
//열 -> 행 변경
D3DXMatrixTranspose(&bone->Transform, &transform);
Matrix matParent;
if (parent < 0)
D3DXMatrixIdentity(&matParent); //초기 부모값
else
matParent = bones[parent]->Transform;
//핵심 코드 (읽어온 상대 위치 * 부모위치)
bone->Transform = bone->Transform * matParent;
//본 추가
bones.push_back(bone);
ReadMeshData(node, index);
//재귀함수
for (UINT i = 0; i < node->mNumChildren; i++)
ReadBoneData(node->mChildren[i], bones.size(), index );
}
void Converter::ReadMeshData(aiNode * node, int index)
{
if (node->mNumMeshes < 1) return;
//Model은 1개의 Mesh 덩어리를 만들기 위해 여러개의 MeshPart로 분할 저장되어 있음
asMesh* mesh = new asMesh();
mesh->BoneIndex = index; //Mesh덩어리가 붙어야 있어야 할 본 번호
//Mesh 덩어리가 가진 Mesh Part 개수 만큼 반복
for (UINT i = 0; i < node->mNumMeshes; i++)
{
//현재 본에 붙어있는 매쉬 번호
UINT index = node->mMeshes[i];
//번호를 통해 실제 ai 메쉬파트 정보 가져옴
aiMesh* srcMesh = scene->mMeshes[index];
UINT startVertex = mesh->Vertices.size();
UINT startIndex = mesh->indices.size();
//aiMesh가 가진 정점의 개수 만큼 돌면서 -> ps, uv, noraml만 저장
for (UINT v = 0; v < srcMesh->mNumVertices; v++)
{
Model::VertexModel vertex;
memcpy(&vertex.Postition, &srcMesh->mVertices[v], sizeof(Vector3));
if (srcMesh->HasTextureCoords(0))
memcpy(&vertex.UV, &srcMesh->mTextureCoords[0][v], sizeof(Vector2));
if(srcMesh->HasNormals())
memcpy(&vertex.Normal, &srcMesh->mNormals[v], sizeof(Vector3));
mesh->Vertices.push_back(vertex);
}
//face의 인덱스는 0부터 출발하므로 +startVertex를 수행함
for (UINT f = 0; f < srcMesh->mNumFaces; f++)
{
aiFace& face = srcMesh->mFaces[f];
for (UINT k = 0; k < face.mNumIndices; k++)
mesh->indices.push_back(face.mIndices[k] + startVertex);
}
//마테리얼
aiMaterial* material = scene->mMaterials[srcMesh->mMaterialIndex];
asMeshPart* meshPart = new asMeshPart();
meshPart->MaterialName = material->GetName().C_Str();
meshPart->StartVertex = startVertex;
meshPart->StartIndex = startIndex;
meshPart->VertexCount = srcMesh->mNumVertices;
meshPart->IndexCount = srcMesh->mNumFaces * srcMesh->mFaces->mNumIndices;
mesh->MeshParts.push_back(meshPart);
}
}
void Converter::WriteMeshData(wstring savePath)
{
Path::CreateFolders(Path::GetDirectoryName(savePath));
BinaryWriter* w = new BinaryWriter(savePath);
//Save Bone
w->UInt(bones.size());
for (asBone* bone : bones)
{
w->Int(bone->Index);
w->String(bone->Name);
w->Int(bone->Parent);
w->Matrix(bone->Transform);
}
//Save Mesh
w->UInt(meshes.size());
for (asMesh* meshData : meshes)
{
w->Int(meshData->BoneIndex);
w->UInt(meshData->Vertices.size());
w->Byte(&meshData->Vertices[0], sizeof(Model::VertexModel) * meshData->Vertices.size());
w->UInt(meshData->indices.size());
w->Byte(&meshData->indices[0], sizeof(UINT) * meshData->indices.size());
w->UInt(meshData->MeshParts.size());
for (asMeshPart* part : meshData->MeshParts)
{
w->String(part->MaterialName);
w->UInt(part->StartVertex);
w->UInt(part->VertexCount);
w->UInt(part->StartIndex);
w->UInt(part->IndexCount);
}
}
SafeDelete(w);
}
#pragma once
class Converter
{
public:
Converter();
~Converter();
void ReadFile(wstring file);
public:
void ExportMesh(wstring savePath); //저장할 매쉬정보
private:
void ReadBoneData(aiNode* node, int index, int parent);
void ReadMeshData(aiNode* node, int index);
void WriteMeshData(wstring savePath); //바이너리 파일로 만들기
private:
wstring file;
Assimp::Importer* importer;
const aiScene* scene; //읽어 오기만
vector<struct asBone*> bones;
vector<struct asMesh*> meshes;
};
ModelEditor(솔루션) -> Converter.cpp, h
더보기
#include "stdafx.h"
#include "ExportFile.h"
#include "Converter.h"
void ExportFile::Initialize()
{
Tank(); // 한번 실행하면 주석처리
}
void ExportFile::Tank()
{
Converter* conv = new Converter;
conv->ReadFile(L"Tank/Tank.fbx");
conv->ExportMesh(L"Tank/Tank");
SafeDelete(conv);
}
#pragma once
#include "Systems/IExecute.h"
class ExportFile : 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();
};
Framework(솔루션) -> Model.cpp, h
더보기
#pragma once
class Model
{
public:
struct VertexModel;
public:
struct VertexModel
{
Vector3 Postition;
Vector2 UV;
Vector3 Normal;
Vector3 Tangent;// NormalMapping
Vector4 BlendIndices; //애니메이션용 Animation Skinning
Vector4 BlendWeights;
VertexModel()
{
Postition = 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);
}
};
};
실행 결과물
ModelEditor 솔루션 : 오로지 모델의 파일을 추출해서 bin파일 형식등 쓰기 편하게 만들려고 하는 목적
Converter : 파일을 추출, 읽기, 저장 등 사용 하기 위한 클래스
ExportFile : UnitTest에 있는 MeshDemo 처럼 Main클래스에 사용 하는 클래스
Model : ModelEditor 통해서 만들어진 모델 파일을 사용하기 위한 클래스
'DirectX > DirectX 3D_(구)' 카테고리의 다른 글
19_ModelMaterial [1/2] (0) | 2021.07.17 |
---|---|
18_ModelEditor [2/2] (0) | 2021.07.14 |
17_Framework (Transform, PerFrame, Renderer) (0) | 2021.07.13 |
17_Framework (Buffer + hlsl) (0) | 2021.07.07 |
16_CubeMap [ 1 / 2 ] (수정) (0) | 2021.07.06 |