WriteAsFBX and WriteAsSTL refactoring

This commit is contained in:
Vladyslav Baranovskyi
2025-02-06 20:34:43 +02:00
parent e603668023
commit dc460cb106
2 changed files with 90 additions and 140 deletions

View File

@@ -90,180 +90,90 @@ namespace OpenVulkano::Scene
}
}
void MeshWriter::WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath)
{
#if __has_include("assimp/Exporter.hpp")
aiNode rootNode;
void MeshWriter::SetupAssimpScene(Geometry* geometry, aiScene& scene, aiNode& rootNode, aiMesh& mesh,
bool withTexCoords, float scaling)
{
mesh.mVertices = nullptr;
mesh.mNormals = nullptr;
mesh.mTangents = nullptr;
mesh.mBitangents = nullptr;
mesh.mFaces = nullptr;
for(unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh.mTextureCoords[i] = nullptr;
mesh.mNumUVComponents[i] = 0;
}
for(unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
mesh.mColors[i] = nullptr;
}
aiScene scene;
rootNode.mName = aiString("RootNode");
rootNode.mChildren = nullptr;
rootNode.mNumChildren = 0;
scene.mRootNode = &rootNode;
aiMesh mesh;
mesh.mName = aiString("Mesh");
mesh.mNumVertices = geometry->vertexCount;
mesh.mMaterialIndex = 0;
mesh.mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
mesh.mNumUVComponents[0] = 2;
std::unique_ptr<aiVector3D[]> vertices = std::make_unique<aiVector3D[]>(geometry->vertexCount);
mesh.mVertices = vertices.get();
mesh.mVertices = new aiVector3D[geometry->vertexCount];
mesh.mNormals = new aiVector3D[geometry->vertexCount];
std::unique_ptr<aiVector3D[]> normals = std::make_unique<aiVector3D[]>(geometry->vertexCount);
mesh.mNormals = normals.get();
if (withTexCoords)
{
mesh.mNumUVComponents[0] = 2;
mesh.mTextureCoords[0] = new aiVector3D[geometry->vertexCount];
}
std::unique_ptr<aiVector3D[]> texCoords = std::make_unique<aiVector3D[]>(geometry->vertexCount);
mesh.mTextureCoords[0] = texCoords.get();
float scaling = 100; // fbx units are centimeters...
for (uint32_t i = 0; i < geometry->vertexCount; ++i)
for (int 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);
if (withTexCoords)
{
mesh.mTextureCoords[0][i] = aiVector3D(vertex.textureCoordinates.x, vertex.textureCoordinates.y, 0.0f);
}
}
mesh.mNumFaces = geometry->indexCount / 3;
std::unique_ptr<aiFace[]> faces = std::make_unique<aiFace[]>(mesh.mNumFaces);
mesh.mFaces = faces.get();
mesh.mFaces = new aiFace[mesh.mNumFaces];
std::unique_ptr<unsigned int[]> indices = std::make_unique<unsigned int[]>(geometry->indexCount);
size_t lastUsedIndex = 0;
for (uint32_t i = 0; i < mesh.mNumFaces; ++i)
for (unsigned int i = 0; i < mesh.mNumFaces; ++i)
{
aiFace& face = mesh.mFaces[i];
face.mNumIndices = 3;
face.mIndices = &indices[lastUsedIndex];
face.mIndices[0] = geometry->GetIndex(i * 3 + 0);
face.mIndices[1] = geometry->GetIndex(i * 3 + 1);
face.mIndices[2] = geometry->GetIndex(i * 3 + 2);
lastUsedIndex += face.mNumIndices;
mesh.mFaces[i].mNumIndices = 3;
mesh.mFaces[i].mIndices = new unsigned int[3];
mesh.mFaces[i].mIndices[0] = geometry->GetIndex(i * 3 + 0);
mesh.mFaces[i].mIndices[1] = geometry->GetIndex(i * 3 + 1);
mesh.mFaces[i].mIndices[2] = geometry->GetIndex(i * 3 + 2);
}
aiMesh* meshes[1] = { &mesh };
scene.mMeshes = meshes;
scene.mNumMeshes = 1;
scene.mMeshes = new aiMesh*[1] { &mesh };
unsigned int meshIndices[1];
scene.mRootNode->mMeshes = meshIndices;
scene.mRootNode->mMeshes[0] = 0;
scene.mRootNode->mNumMeshes = 1;
aiMaterial material;
aiMaterial* materials[1] = { &material };
scene.mMaterials = materials;
scene.mNumMaterials = 1;
scene.mMaterials = new aiMaterial*[1] { new aiMaterial() };
aiString externalPath(texturePath);
scene.mMaterials[0]->AddProperty(&externalPath, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
Assimp::Exporter exporter;
aiReturn result = exporter.Export(&scene, "fbx", fbxPath);
mesh.mVertices = nullptr;
mesh.mNormals = nullptr;
mesh.mTextureCoords[0] = nullptr;
for (uint32_t i = 0; i < mesh.mNumFaces; ++i)
{
aiFace& face = mesh.mFaces[i];
face.mIndices = nullptr;
}
mesh.mFaces = nullptr;
rootNode.mMeshes = nullptr;
scene.mRootNode = 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());
}
#else
throw std::runtime_error("Unable to convert the scene to FBX: Assimp is not available!");
#endif
rootNode.mNumMeshes = 1;
rootNode.mMeshes = new unsigned int[1] { 0 };
}
void MeshWriter::WriteAsSTL(Geometry* geometry, const std::string& filePath, bool binary)
{
#if __has_include("assimp/Exporter.hpp")
aiNode rootNode;
std::unique_ptr<aiScene> scene(new aiScene());
std::unique_ptr<aiNode> rootNode(new aiNode());
std::unique_ptr<aiMesh> mesh(new aiMesh());
aiScene scene;
scene.mRootNode = &rootNode;
aiMesh mesh;
mesh.mNumVertices = geometry->vertexCount;
mesh.mMaterialIndex = 0;
mesh.mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
std::unique_ptr<aiVector3D[]> vertices = std::make_unique<aiVector3D[]>(geometry->vertexCount);
mesh.mVertices = vertices.get();
std::unique_ptr<aiVector3D[]> normals = std::make_unique<aiVector3D[]>(geometry->vertexCount);
mesh.mNormals = normals.get();
for (int 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);
mesh.mNormals[i] = aiVector3D(vertex.normal.x, vertex.normal.y, vertex.normal.z);
}
mesh.mNumFaces = geometry->indexCount / 3;
std::unique_ptr<aiFace[]> faces = std::make_unique<aiFace[]>(mesh.mNumFaces);
mesh.mFaces = faces.get();
std::unique_ptr<unsigned int[]> indices = std::make_unique<unsigned int[]>(geometry->indexCount);
size_t lastUsedIndex = 0;
for (int i = 0; i < mesh.mNumFaces; ++i)
{
aiFace& face = mesh.mFaces[i];
face.mNumIndices = 3;
face.mIndices = &indices[lastUsedIndex];
face.mIndices[0] = geometry->GetIndex(i * 3 + 0);
face.mIndices[1] = geometry->GetIndex(i * 3 + 1);
face.mIndices[2] = geometry->GetIndex(i * 3 + 2);
lastUsedIndex += face.mNumIndices;
}
aiMesh* meshes[1] = { &mesh };
scene.mMeshes = meshes;
scene.mNumMeshes = 1;
unsigned int meshIndices[1];
scene.mRootNode->mMeshes = meshIndices;
scene.mRootNode->mMeshes[0] = 0;
scene.mRootNode->mNumMeshes = 1;
// STL doesn't use materials, but Assimp requires at least one
aiMaterial material;
aiMaterial* materials[1] = { &material };
scene.mMaterials = materials;
scene.mNumMaterials = 1;
SetupAssimpScene(geometry, *scene, *rootNode, *mesh, false, 1.0f);
Assimp::Exporter exporter;
const char* formatId = binary ? "stlb" : "stl";
aiReturn result = exporter.Export(&scene, formatId, filePath);
aiReturn result = exporter.Export(scene.get(), formatId, filePath);
mesh.mVertices = nullptr;
mesh.mNormals = nullptr;
for (int i = 0; i < mesh.mNumFaces; ++i)
{
aiFace& face = mesh.mFaces[i];
face.mIndices = nullptr;
}
mesh.mFaces = nullptr;
rootNode.mMeshes = nullptr;
scene.mRootNode = nullptr;
scene.mMeshes = nullptr;
scene.mMaterials = nullptr;
scene->mRootNode = nullptr;
scene->mMeshes = nullptr;
if (result != aiReturn_SUCCESS)
{
@@ -273,4 +183,35 @@ namespace OpenVulkano::Scene
throw std::runtime_error("Unable to export to STL: Assimp is not available!");
#endif
}
void MeshWriter::WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath)
{
#if __has_include("assimp/Exporter.hpp")
std::unique_ptr<aiScene> scene(new aiScene());
std::unique_ptr<aiNode> rootNode(new aiNode());
std::unique_ptr<aiMesh> mesh(new aiMesh());
SetupAssimpScene(geometry, *scene, *rootNode, *mesh, true, 100.0f);
if (!texturePath.empty())
{
aiString externalPath(texturePath);
scene->mMaterials[0]->AddProperty(&externalPath, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
}
Assimp::Exporter exporter;
aiReturn result = exporter.Export(scene.get(), "fbx", fbxPath);
scene->mRootNode = nullptr;
scene->mMeshes = nullptr;
if (result != aiReturn_SUCCESS)
{
throw std::runtime_error("Unable to write a fbx file to " + fbxPath + ": " + exporter.GetErrorString());
}
#else
throw std::runtime_error("Unable to convert the scene to FBX: Assimp is not available!");
#endif
}
#endif
}

View File

@@ -8,6 +8,10 @@
#include <string>
#if __has_include("assimp/Exporter.hpp")
#include <assimp/scene.h>
#endif
namespace OpenVulkano::Scene
{
class Geometry;
@@ -20,5 +24,10 @@ namespace OpenVulkano::Scene
static void WriteAsUSDZ(Geometry* geometry, const std::string& texturePath, const std::string& usdzPath);
static void WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath);
static void WriteAsSTL(Geometry* geometry, const std::string& filePath, bool binary);
private:
#if __has_include("assimp/Exporter.hpp")
static void SetupAssimpScene(Geometry* geometry, aiScene& scene, aiNode& rootNode, aiMesh& mesh,
bool withTexCoords, float scaling);
#endif
};
}