FBX내부에 모델의 뼈대 데이터가 존재하면 뼈대 데이터를 받아올 수 있게 전처리를 진행한다.
먼저, 전에 데이터를 받아오기위해 만든 ModelData.h를 수정해보자.
새로운 struct인 NodeData를 생성한다.
struct NodeData
{
int index;
string name;
int parent;
Matrix transform;
};
현재 Node의 번호와, 이름, 부모관계, 모델기준 상대World좌표. 를 받아온다.
그리고, ModelExporter를 수정해서, nodes를 받아올 수 있도록 수정작업을 진행한다.
class ModelExporter
{
public:
ModelExporter(string name, string file);
~ModelExporter();
void ExportMaterial();
void ExportMesh();
private:
//Material
void ReadMaterial();// 머티리얼 읽기.
void WriterMaterial(); // 머티얼 써서 저장하기.
string CreateTexture(string file); // 텍스처 파일을 생성하기
// Mesh
void ReadNode(aiNode* node, int index, int parent); // 지정된 Ndoe값을 읽어오기
void ReadMesh(aiNode* node); // 메쉬읽기
void WriteMesh();
private:
Assimp::Importer* importer;
const aiScene* scene;
//aiScene 는 상수로 사용해야한다. 무조건.
string name;
vector<Material*> materials;
vector<MeshData*> meshes;
vector<NodeData*> nodes;
};
그리고, assimp를 사용해서 데이터를 읽어오는 함수를 정의한다.
void ModelExporter::ExportMesh()
{
ReadNode(scene->mRootNode, -1, -1);
// rootnode가-1임을 기억하자.
ReadMesh(scene->mRootNode);
WriteMesh();
}
여기서 rootnode가 -1이라면, 상속되는 종류의 node가 존재하지 않음을 의미한다.
메인뼈대 라는 의미.
void ModelExporter::ReadNode(aiNode* node, int index, int parent)
{
NodeData* nodeData = new NodeData();
nodeData->index = index;
nodeData->parent = parent;
nodeData->name = node->mName.C_Str();
Matrix matrix(node->mTransformation[0]);
nodeData->transform = XMMatrixTranspose(matrix); // 메트릭스 변환해야함.
nodes.push_back(nodeData);
FOR(node->mNumChildren)
ReadNode(node->mChildren[i], nodes.size(), index);
}
ReadNode이다. 가져온 데이터의 데이터와, 번호, 부모값을 가져온다음.
이름값과 함께 node를 저장하는 vector인 nodes에 저장해준다.
저장할 때 에는, node값을 다음과 같이 마지막에 정의해준다.
writer->UInt(nodes.size());
for (NodeData* node : nodes)
{
writer->Int(node->index);
writer->String(node->name);
writer->Int(node->parent);
writer->Matrix(node->transform);
delete node;
}
nodes.clear();
delete writer;
}
저장시 순서대로 저장하고, 읽을때 에도 순서대로 읽을 수있게 한다.
size = reader->UInt();
nodes.resize(size);
for (NodeData& node : nodes)
{
node.index = reader->Int();
node.name = reader->String();
node.parent = reader->Int();
node.transform = reader->Matrix();
}
// 사용이 끝난 BinaryReader를 삭제합니다.
delete reader;
MakeBoneTransforms();
}
void Model::MakeBoneTransforms()
{
boneTransforms.reserve(nodes.size());
for (NodeData node: nodes)
{
Matrix parent;
int parentIndex = node.parent;
if (parentIndex < 0)
parent = XMMatrixIdentity();
else
parent = boneTransforms[parentIndex];
boneTransforms.push_back(node.transform * parent);
nodeTransforms[node.name] = boneTransforms.back();
}
}
Mash값을 읽을 때, node에 데이터를 저장하고, 해당되는 node를 이름값과 함께, Transforms에 데이터를 저장해준다.
Transform에는 node형태의 데이터에 대한 Matrix값이 저장되기 때문에, Matrix값이 저장될 vector와 map형태를 사용한다.
vector<Matrix> boneTransforms;
map<string, Matrix> nodeTransforms;
즉, 정의된 Map에 따라. Parent값을 연동해서 부모값에 대한 Matrix가 추가되어서 이동되도록 곱해준다음 넣어준다.
이후에 상속되는 Matrix는, 부모의 Matrix만큼 이동해서 정의된다고 볼 수 있다.
'서울게임아카데미 교육과정 6개월 국비과정' 카테고리의 다른 글
20231117 33일차 모델의 애니메이션 리깅출력하기 (0) | 2023.11.17 |
---|---|
20231116 32일차 모델의 애니메이션 리깅저장하기1 (0) | 2023.11.16 |
20231114 30일차 함수포인터를 활용한 인벤토리 구축2 (0) | 2023.11.14 |
20231113 29일차 함수포인터를 활용한 인벤토리 구축. (0) | 2023.11.13 |
20231110 28일차 DepthStencilState, 함수포인터 (0) | 2023.11.10 |