Files
OpenVulkano/openVulkanoCpp/Scene/MeshWriter.cpp
2024-12-18 14:28:33 +02:00

162 lines
5.2 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "MeshWriter.hpp"
#include "Base/Utils.hpp"
#include "IO/MemMappedFile.hpp"
#include "Scene/Geometry.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/UsdEncoder.hpp"
#include "Scene/ObjEncoder.hpp"
#include "IO/Archive/ArchiveWriter.hpp"
#include "IO/Archive/ZipWriter.hpp"
#include <fstream>
#include <fmt/core.h>
#include <assimp/scene.h>
#include <assimp/Exporter.hpp>
#include <assimp/mesh.h>
#include <assimp/material.h>
namespace OpenVulkano::Scene
{
void MeshWriter::WriteAsOBJ(Geometry* geometry, const std::string& filePath)
{
std::ofstream file(filePath);
if (!file.is_open()) [[unlikely]]
throw std::runtime_error("Failed to open file '" + filePath + "' for writing!");
WriteObjContents(geometry, "", file);
file.close();
}
void MeshWriter::WriteAsUSD(Geometry* geometry, const std::string& filePath)
{
std::ofstream file(filePath);
if (!file.is_open()) [[unlikely]]
throw std::runtime_error("Failed to open file '" + filePath + "' for writing!");
WriteUsdContents(file, geometry);
file.close();
}
void MeshWriter::WriteObjAsZip(Geometry* geometry, const std::string& texturePath, const std::string& zipPath)
{
OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str());
{
std::stringstream objContents;
WriteObjContents(geometry, DEFAULT_OBJ_MATERIAL_NAME, objContents);
std::string objContentsStr = objContents.str();
FileDescription objDesc = FileDescription::MakeDescriptionForFile("model.obj", objContentsStr.size());
zipWriter.AddFile(objDesc, objContentsStr.data());
}
{
FileDescription mtlDesc = FileDescription::MakeDescriptionForFile("material.mtl", DEFAULT_OBJ_MATERIAL_CONTENTS.size());
zipWriter.AddFile(mtlDesc, DEFAULT_OBJ_MATERIAL_CONTENTS.data());
}
if (!texturePath.empty() && std::filesystem::exists(texturePath))
{
MemMappedFile textureFile(texturePath);
FileDescription texDesc = FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
zipWriter.AddFile(texDesc, textureFile.Data());
}
}
void MeshWriter::WriteAsUSDZ(Geometry* geometry, const std::string& texturePath, const std::string& usdzPath)
{
OpenVulkano::ZipWriter zipWriter(usdzPath, true);
{
std::stringstream usdFile;
WriteUsdContents(usdFile, geometry);
std::string usdFileStr = usdFile.str();
FileDescription usdDesc = FileDescription::MakeDescriptionForFile("geometry.usda", usdFileStr.size());
zipWriter.AddFile(usdDesc, usdFileStr.data());
}
if (!texturePath.empty() && std::filesystem::exists(texturePath))
{
MemMappedFile textureFile(texturePath);
FileDescription texDesc = FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
zipWriter.AddFile(texDesc, textureFile.Data());
}
}
void MeshWriter::WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath)
{
aiNode rootNode;
aiScene scene;
scene.mRootNode = &rootNode;
aiMesh mesh;
mesh.mNumVertices = geometry->vertexCount;
mesh.mMaterialIndex = 0;
mesh.mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
mesh.mNumUVComponents[0] = 2;
mesh.mVertices = new aiVector3D[geometry->vertexCount];
mesh.mNormals = new aiVector3D[geometry->vertexCount];
mesh.mTextureCoords[0] = new aiVector3D[geometry->vertexCount];
float scaling = 100; // fbx units are centimeters...
for (uint32_t i = 0; i < geometry->vertexCount; ++i)
{
const Vertex& vertex = geometry->vertices[i];
mesh.mVertices[i] = aiVector3D(vertex.position.x, vertex.position.y, vertex.position.z) * scaling;
mesh.mNormals[i] = aiVector3D(vertex.normal.x, vertex.normal.y, vertex.normal.z);
mesh.mTextureCoords[0][i] = aiVector3D(vertex.textureCoordinates.x, vertex.textureCoordinates.y, 0.0f);
}
mesh.mNumFaces = geometry->indexCount / 3;
mesh.mFaces = new aiFace[mesh.mNumFaces];
for (uint32_t i = 0; i < mesh.mNumFaces; ++i)
{
aiFace& face = mesh.mFaces[i];
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = geometry->GetIndex(i * 3 + 0);
face.mIndices[1] = geometry->GetIndex(i * 3 + 1);
face.mIndices[2] = geometry->GetIndex(i * 3 + 2);
}
aiMesh* meshes[1];
scene.mMeshes = meshes;
scene.mMeshes[0] = &mesh;
scene.mNumMeshes = 1;
unsigned int meshIndices[1];
scene.mRootNode->mMeshes = meshIndices;
scene.mRootNode->mMeshes[0] = 0;
scene.mRootNode->mNumMeshes = 1;
aiMaterial material;
aiMaterial* materials[1];
scene.mMaterials = materials;
scene.mMaterials[0] = &material;
scene.mNumMaterials = 1;
aiString externalPath(texturePath);
scene.mMaterials[0]->AddProperty(&externalPath, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
Assimp::Exporter exporter;
aiReturn result = exporter.Export(&scene, "fbx", fbxPath);
scene.mRootNode = nullptr;
rootNode.mMeshes = nullptr;
scene.mMeshes = nullptr;
scene.mMaterials = nullptr;
if (result != aiReturn_SUCCESS)
{
throw std::runtime_error("Unable to write a fbx file to " + fbxPath + ": " + exporter.GetErrorString());
}
}
}