프로그래밍 공부
작성일
2023. 11. 15. 15:14
작성자
WDmil
728x90

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만큼 이동해서 정의된다고 볼 수 있다.

 

 

728x90