From e6036680231a36e0793794f33ef7ef70e36a1a27 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Thu, 6 Feb 2025 11:28:14 +0200 Subject: [PATCH] STL exporting using assimp --- openVulkanoCpp/Scene/Export/MeshWriter.cpp | 88 ++++++++++++++++++++++ openVulkanoCpp/Scene/Export/MeshWriter.hpp | 1 + 2 files changed, 89 insertions(+) diff --git a/openVulkanoCpp/Scene/Export/MeshWriter.cpp b/openVulkanoCpp/Scene/Export/MeshWriter.cpp index c748015..399c1ca 100644 --- a/openVulkanoCpp/Scene/Export/MeshWriter.cpp +++ b/openVulkanoCpp/Scene/Export/MeshWriter.cpp @@ -183,6 +183,94 @@ namespace OpenVulkano::Scene } #else throw std::runtime_error("Unable to convert the scene to FBX: Assimp is not available!"); +#endif + } + + void MeshWriter::WriteAsSTL(Geometry* geometry, const std::string& filePath, bool binary) + { +#if __has_include("assimp/Exporter.hpp") + aiNode rootNode; + + aiScene scene; + scene.mRootNode = &rootNode; + + aiMesh mesh; + mesh.mNumVertices = geometry->vertexCount; + mesh.mMaterialIndex = 0; + mesh.mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + std::unique_ptr vertices = std::make_unique(geometry->vertexCount); + mesh.mVertices = vertices.get(); + + std::unique_ptr normals = std::make_unique(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 faces = std::make_unique(mesh.mNumFaces); + mesh.mFaces = faces.get(); + + std::unique_ptr indices = std::make_unique(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; + + Assimp::Exporter exporter; + const char* formatId = binary ? "stlb" : "stl"; + aiReturn result = exporter.Export(&scene, 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; + + if (result != aiReturn_SUCCESS) + { + throw std::runtime_error("Unable to write STL file to " + filePath + ": " + exporter.GetErrorString()); + } +#else + throw std::runtime_error("Unable to export to STL: Assimp is not available!"); #endif } } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/Export/MeshWriter.hpp b/openVulkanoCpp/Scene/Export/MeshWriter.hpp index ba24bce..3b9255b 100644 --- a/openVulkanoCpp/Scene/Export/MeshWriter.hpp +++ b/openVulkanoCpp/Scene/Export/MeshWriter.hpp @@ -19,5 +19,6 @@ namespace OpenVulkano::Scene static void WriteObjAsZip(Geometry* geometry, const std::string& texturePath, const std::string& zipPath); 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); }; } \ No newline at end of file