현재진행상황
하이어라이키 만들기
메쉬 만들기
머테리얼 만들기
본정보 받아와 스켈레톤 만들기
현재 내용이 지속적으로 추가되면서 이해하지 못한 부분도 있기때문에 지속적으로 복습이 필요함.
아래의 코드는 내용정리를 위한것.
ASSIMP의 라이브러리는 따로 첨부 X
Main.h
#pragma once
//메인에는 씬만 구성
class Main : public Scene
{
private:
Camera* Cam;
Grid* grid;
Actor* temp;
string file;
Assimp::Importer importer;
const aiScene* scene;
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 MakeHierarchy(aiNode* node, GameObject* node2);
void MakeMesh(aiNode* node, GameObject* node2);
void MakeMaterial();
Matrix ToMatrix(aiMatrix4x4& value)
{
return Matrix
(
value.a1, value.b1, value.c1, value.d1,
value.a2, value.b2, value.c2, value.d2,
value.a3, value.b3, value.c3, value.d3,
value.a4, value.b4, value.c4, value.d4
);
};
void ReadBoneData(aiMesh* mesh, vector<class VertexWeights>& vertexWeights);
};
#define MAX_WEIGHTS 4 // 매크로 값
struct VertexWeights // 구조체 생성
{
UINT boneIdx[MAX_WEIGHTS]; // 배열 4개 선언
float boneWeights[MAX_WEIGHTS]; // 배열 4개 선언
VertexWeights() // 생성자
{
ZeroMemory(boneIdx, sizeof(UINT) * MAX_WEIGHTS); // 배열을 초기화
ZeroMemory(boneWeights, sizeof(float) * MAX_WEIGHTS); // 배열을 초기화
}
void AddData(UINT boneId, float weight) // 데이터 추가 함수
{
for (UINT i = 0; i < MAX_WEIGHTS; i++)
{
if (boneWeights[i] == 0.0f) // 가중치가 0인 요소를 찾았으면
{
boneIdx[i] = boneId; // 인덱스 배열에 아이디 저장
boneWeights[i] = weight; // 가중치 배열에 가중치 저장
return;
}
}
}
void Normalize() // 정규화
{
float total = 0.0f; // total 변수 초기화
for (UINT i = 0; i < MAX_WEIGHTS; i++) // 정해둔 영향권(4곳) 만큼 반복진행
{
if (boneWeights[i] != 0.0f) // 가중치가 0이아니라면
{
total += boneWeights[i]; // 토탈에 전부 더해준다
}
}
for (UINT i = 0; i < MAX_WEIGHTS; i++) // 정해둔 영향권(4곳) 만큼 반복진행
{
if (boneWeights[i] != 0.0f) // 가중치가 0이아니라면
{
boneWeights[i] /= total; // 해당배열의값을 total로 나누어 일정비율로 만든다.
}
}
// 즉 정규화 작업은 4개의 가중치를 모두더했을때 1이라는 값이 되도록
// 각각 일정비율화 시키는 것입니다.
}
};
Main.cpp
#include "stdafx.h"
#include "Main.h"
Main::Main()
{
}
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();
grid = Grid::Create();
temp = Actor::Create();
}
void Main::Release()
{
}
void Main::Update()
{
ImGui::Begin("Hierarchy");
Cam->RenderHierarchy();
temp->RenderHierarchy();
grid->RenderHierarchy();
ImGui::End();
if (GUI->FileImGui("ModelImporter", "ModelImporter",
".fbx,.obj,.x", "../Assets"))
{
file = ImGuiFileDialog::Instance()->GetCurrentFileName();
string path = "../Assets/" + file;
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
scene = importer.ReadFile
(
path,
aiProcess_ConvertToLeftHanded
| aiProcess_Triangulate
| aiProcess_GenUVCoords
| aiProcess_GenNormals
| aiProcess_CalcTangentSpace
);
assert(scene != NULL and "Import Error");
temp->ReleaseMember();
temp->skeleton = new Skeleton();
MakeMaterial();
GameObject* empty = GameObject::Create("empty");
temp->AddChild(empty);
temp->Update();
MakeHierarchy(scene->mRootNode, empty);
{
int tok = file.find_last_of(".");
string checkPath = "../Contents/Skeleton/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string filePath = file.substr(0, tok) + "/";
temp->skeleton->file = filePath + file.substr(0, tok) + ".skel";
temp->skeleton->BonesUpdate(temp);
temp->skeleton->SaveFile(temp->skeleton->file);
}
MakeMesh(scene->mRootNode, empty);
importer.FreeScene();
}
temp->skeleton->BonesUpdate(temp);
Camera::ControlMainCam();
Cam->Update();
grid->Update();
temp->Update();
}
void Main::LateUpdate()
{
}
void Main::PreRender()
{
}
void Main::Render()
{
Cam->Set();
grid->Render();
temp->Render();
}
void Main::ResizeScreen()
{
}
void Main::MakeHierarchy(aiNode* node, GameObject* node2)
{
Matrix tempMat = ToMatrix(node->mTransformation);
Vector3 s, r, t; Quaternion q;
tempMat.Decompose(s, q, t);
r = Util::QuaternionToYawPtichRoll(q);
//if(node2->parent)
//node2->parent->Update();
node2->scale = s;
node2->rotation = r;
node2->SetLocalPos(t);
temp->Update();
temp->skeleton->bonesOffset[node2->boneIndex]
= node2->W.Invert();
//MakeMesh(node, node2);
for (int i = 0; i < node->mNumChildren; i++)
{
GameObject* child = GameObject::Create(node->mChildren[i]->mName.C_Str());
node2->AddChild(child);
MakeHierarchy(node->mChildren[i], child);
}
}
void Main::MakeMesh(aiNode* node, GameObject* node2)
{
//
//루트 노드에 담겨있는 메쉬 갯수만큼 반복
for (int i = 0; i < node->mNumMeshes; i++)
{
int index = node->mMeshes[i];
aiMesh* mesh = scene->mMeshes[index];
aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex];
string mtlFile = mtl->GetName().C_Str();
int tok = file.find_last_of(".");
string filePath = file.substr(0, tok) + "/";
mtlFile = filePath + mtlFile + ".mtl";
GameObject* Current = node2;
//메쉬가 두개 이상일때
if (i != 0)
{
Current =
GameObject::Create(node2->name + "meshObject" + to_string(i));
node2->AddChild(Current);
}
Current->shader = RESOURCE->shaders.Load("4.Cube.hlsl");
Current->material =new Material();
Current->material->LoadFile(mtlFile);
Current->mesh = make_shared<Mesh>();
Current->mesh->byteWidth = sizeof(VertexModel);
Current->mesh->primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
Current->mesh->vertexType = VertexType::MODEL;
Current->mesh->vertexCount = mesh->mNumVertices;
Current->mesh->vertices = new VertexModel[mesh->mNumVertices];
//Current->mesh->indexCount =
vector<UINT> indexList;
vector<VertexWeights> VertexWeights;
VertexWeights.resize(mesh->mNumVertices);
//VertexWeights.shrink_to_fit();
ReadBoneData(mesh, VertexWeights);
for (int j = 0; j < mesh->mNumVertices; j++)
{
VertexModel* vertex = (VertexModel*)Current->mesh->vertices;
//aiVector3D
//텍스쳐 좌표가 있다면
if (mesh->HasTextureCoords(0))
{
vertex[j].uv.x =mesh->mTextureCoords[0][j].x;
vertex[j].uv.y =mesh->mTextureCoords[0][j].y;
}
if (mesh->HasNormals())
{
vertex[j].normal.x = mesh->mNormals[j].x;
vertex[j].normal.y = mesh->mNormals[j].y;
vertex[j].normal.z = mesh->mNormals[j].z;
}
if (mesh->HasPositions())
{
vertex[j].position.x = mesh->mVertices[j].x;
vertex[j].position.y = mesh->mVertices[j].y;
vertex[j].position.z = mesh->mVertices[j].z;
}
if (mesh->HasTangentsAndBitangents())
{
vertex[j].tangent.x = mesh->mTangents[j].x;
vertex[j].tangent.y = mesh->mTangents[j].y;
vertex[j].tangent.z = mesh->mTangents[j].z;
}
//본데이터가 있을때
if (!VertexWeights.empty())
{
VertexWeights[j].Normalize();
vertex[j].indices.x = (float)VertexWeights[j].boneIdx[0];
vertex[j].indices.y = (float)VertexWeights[j].boneIdx[1];
vertex[j].indices.z = (float)VertexWeights[j].boneIdx[2];
vertex[j].indices.w = (float)VertexWeights[j].boneIdx[3];
vertex[j].weights.x = VertexWeights[j].boneWeights[0];
vertex[j].weights.y = VertexWeights[j].boneWeights[1];
vertex[j].weights.z = VertexWeights[j].boneWeights[2];
vertex[j].weights.w = VertexWeights[j].boneWeights[3];
}
}
for (int j = 0; j < mesh->mNumFaces; j++)
{
for (int k = 0; k < mesh->mFaces[j].mNumIndices; k++)
{
indexList.push_back(mesh->mFaces[j].mIndices[k]);
}
}
Current->mesh->indexCount = indexList.size();
Current->mesh->indices = new UINT[indexList.size()];
copy(indexList.begin(), indexList.end(),
stdext::checked_array_iterator<UINT*>
(Current->mesh->indices, indexList.size()));
Current->mesh->Reset();
{
int tok = file.find_last_of(".");
string checkPath = "../Contents/Mesh/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string filePath = file.substr(0, tok) + "/";
string meshFile = mesh->mName.C_Str();
Current->mesh->file = filePath + meshFile + ".mesh";
Current->mesh->SaveFile(Current->mesh->file);
}
}
for (UINT i = 0; i < node->mNumChildren; i++)
{
MakeMesh(node->mChildren[i],node2->children[node->mChildren[i]->mName.C_Str()]);
}
}
void Main::MakeMaterial()
{
for (int i = 0; i < scene->mNumMaterials; i++)
{
aiMaterial* srcMtl = scene->mMaterials[i];
Material* destMtl = new Material();
aiColor3D tempColor;
destMtl->file = srcMtl->GetName().C_Str();
//ambient
srcMtl->Get(AI_MATKEY_COLOR_AMBIENT, tempColor);
destMtl->ambient.x = tempColor.r;
destMtl->ambient.y = tempColor.g;
destMtl->ambient.z = tempColor.b;
//diffuse
srcMtl->Get(AI_MATKEY_COLOR_DIFFUSE, tempColor);
destMtl->diffuse.x = tempColor.r;
destMtl->diffuse.y = tempColor.g;
destMtl->diffuse.z = tempColor.b;
//specular
srcMtl->Get(AI_MATKEY_COLOR_SPECULAR, tempColor);
destMtl->specular.x = tempColor.r;
destMtl->specular.y = tempColor.g;
destMtl->specular.z = tempColor.b;
//emissive
srcMtl->Get(AI_MATKEY_COLOR_EMISSIVE, tempColor);
destMtl->emissive.x = tempColor.r;
destMtl->emissive.y = tempColor.g;
destMtl->emissive.z = tempColor.b;
//Shininess
srcMtl->Get(AI_MATKEY_SHININESS, destMtl->shininess);
//opacity
srcMtl->Get(AI_MATKEY_OPACITY, destMtl->opacity);
//Normal
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_NORMALS, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->ambient.w = 1.0f;
destMtl->normalMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->normalMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
//Diffuse
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_DIFFUSE, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->diffuse.w = 1.0f;
destMtl->diffuseMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->diffuseMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
//specular
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_SPECULAR, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->specular.w = 1.0f;
destMtl->specularMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->specularMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
//emissive
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_EMISSIVE, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->emissive.w = 1.0f;
destMtl->emissiveMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->emissiveMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Material/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string filePath = file.substr(0, tok) + "/";
destMtl->file = filePath + destMtl->file + ".mtl";
destMtl->SaveFile(destMtl->file);
}
}
void Main::ReadBoneData(aiMesh* mesh, vector<class VertexWeights>& vertexWeights) // 본데이터 읽어오는 함수
{
//메쉬가 가지고 있는 본 개수 만큼
for (UINT i = 0; i < mesh->mNumBones; i++)
{
//현재본이 하이어라이키에서 몇번째 인덱스인가?
string boneName = mesh->mBones[i]->mName.C_Str();
int boneIndex = temp->Find(boneName)->boneIndex;
for (UINT j = 0; j < mesh->mBones[i]->mNumWeights; j++) // 가중치 넣어주기
{
UINT vertexID = mesh->mBones[i]->mWeights[j].mVertexId;
vertexWeights[vertexID].AddData(boneIndex, mesh->mBones[i]->mWeights[j].mWeight);
}
}
}
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR param, int command)
{
App.SetAppName(L"ObjLoader");
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;
}
'공부 > DirectX3D' 카테고리의 다른 글
[DirectX3D] 환경 맵핑(Environment Mapping) (0) | 2023.08.08 |
---|---|
[DirectX3D] DxTex 큐브맵(CubeMap) 만들기 (0) | 2023.07.29 |
[DirectX3D/ASSIMP] ASSIMP 구조 (0) | 2023.06.21 |
[DirectX3D / Graphics] 조명효과 (Ambient . Diffuse . Specular . Phong Reflection) (1) | 2023.06.07 |
[DirectX3D] 레이 캐스팅 ( Ray Casting ) & 레이 트레이싱 ( Ray Tracing) (feat.충돌) (0) | 2023.05.31 |
댓글