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

 

DirectX에서 FBXModel을 Import하고 Save할 때 원래 생각해놓고 구현해놓았던 방식대로

 

정상적으로 Import가 되지 않으면 매우 곤란하다.

 

이번에는 만약, Import 하였을 시, Mesh와 Matarial의 개수가 일치하지 않을 때,

 

각 Mesh에 Matarial을 밀어넣어줄 수 있는 코드를 작성한다.

 

우선 데이터 구조상,

 

Model에서 Matarial과 Mesh값, Name값을 알아야 한다.

 

이전에 작성하였던 ModelExporter에서 동작하는 동작사항을 일부 수정해서 가져와 사용해야 한다는 의미이다.

 

또한, Model이 가지고있던 데이터에 접근하여 수정해야 하고,

 

MeshData값을 ModelMesh가 가지고 있어야 한다.

(프레임워크 상 MeshData는 ModelMesh가 아닌, Model이 가지고 있고, ModelMesh는 MeshData만 가지고 있다.)

 

ModelMesh에 Model의 이름, Matarial을 가지고있는데

 

데이터 순서상 MeshData를 가지고 있어야 따로 정리할 필요 없이, 대입연산만으로 처리가 가능하기 때문이다.

 

우선은 Model에 ModelExporter가 가지고있던, SAVE함수들을 끌어온다.

(만약 수정한다면, ModelExproter를 Model에 합쳐버리는게 안전성이 더 높아질 수 도 있다. 아니면, SAVE함수목록을 따로 작성해야 할 것 이다.)

void Model::SaveMateirals()
{
    string savePath = "Models/Materials/" + name + "/";
    string file = name + ".mats";

    BinaryWriter* writer = new BinaryWriter(savePath + file);

    writer->UInt(materials.size());

    for (Material* material : materials)
    {
        string path = savePath + material->GetName() + ".mat";
        material->Save(path);

        writer->String(path);
    }

    delete writer;
}

void Model::SaveMeshes()
{
    string path = "Models/Meshes/" + name + ".mesh";

    CreateFolders(path);

    BinaryWriter* writer = new BinaryWriter(path);

    writer->UInt(meshes.size());
    for (ModelMesh* mesh : meshes)
    {
        writer->String(mesh->GetName());
        writer->UInt(mesh->GetData().materialIndex);

        writer->UInt(mesh->GetData().vertices.size());
        writer->Byte(mesh->GetData().vertices.data(),
            sizeof(ModelVertex) * mesh->GetData().vertices.size());

        writer->UInt(mesh->GetData().indices.size());
        writer->Byte(mesh->GetData().indices.data(),
            sizeof(UINT) * mesh->GetData().indices.size());
    }

    writer->UInt(nodes.size());
    for (NodeData node : nodes)
    {
        writer->Int(node.index);
        writer->String(node.name);
        writer->Int(node.parent);
        writer->Matrix(node.transform);
    }

    writer->UInt(bones.size());
    for (BoneData bone : bones)
    {
        writer->Int(bone.index);
        writer->String(bone.name);
        writer->Matrix(bone.offset);
    }

    delete writer;
}

 

Bone데이터와 node데이터, Mesh데이터를 세이브 할수 있도록 정의한다.

 

단, 원래 ModelExporter에서 Save할 때 에는, Delete시 Save하게 만들었음 으로,

 

저장되어있는 데이터를 날리는 delete를 없애주어야 한다.

 

그렇지 않으면 원래 데이터를 save하였을 때, bone또는 node데이터가 날아가서 오류가 터질것이다.

 

ModelMesh부분에서 생성시, Mesh가 만들어졌을 시에 데이터가 잘 입력되도록 정의준다.

ModelMesh::ModelMesh(string name) : name(name)
{
    data.name = name;
}

ModelMesh::~ModelMesh()
{
    delete mesh;
}

void ModelMesh::Render()
{
    material->Set();
    mesh->Draw();
}

void ModelMesh::CreateMesh(void* vertices, UINT vertexCount, void* indices, UINT indexCount)
{
    mesh = new Mesh<ModelVertex>();

    mesh->GetVertices().resize(vertexCount);
    memcpy(mesh->GetVertices().data(), vertices, sizeof(ModelVertex) * vertexCount);

    mesh->GetIndices().resize(indexCount);
    memcpy(mesh->GetIndices().data(), indices, sizeof(UINT) * indexCount);

    mesh->CreateMesh();

    data.vertices = mesh->GetVertices();
    data.indices = mesh->GetIndices();
}

 

그리고 모델에 ImGui로 Mesh를 Setting해주는 함수를 넣으면 된다.

 

void Model::MeshSetting()
{
    ImGui::SliderInt("Mesh", &selectMeshNum, 0, GetMeshNum());
    if (ImGui::Button("AddMaterial"))
    {
        UINT materialIndex = GetMaterialNum();
       GetMesh(selectMeshNum)->SetMaterial(AddMaterial(), materialIndex);
    }

    if (ImGui::Button("SaveModelData"))
    {
        SaveMateirals();
        SaveMeshes();
    }
}

데이터 결과물,

 

우리는 이제, Mesh간 Materail을 구현하고 저장하고 새로 지정할 수 있게되었다.

728x90