diff --git a/openVulkanoCpp/Scene/Export/MeshWriter.cpp b/openVulkanoCpp/Scene/Export/MeshWriter.cpp index 19f0fc1..7cab2ec 100644 --- a/openVulkanoCpp/Scene/Export/MeshWriter.cpp +++ b/openVulkanoCpp/Scene/Export/MeshWriter.cpp @@ -24,6 +24,82 @@ #include #endif +namespace +{ +#if __has_include("assimp/Exporter.hpp") + void SetupAssimpScene(OpenVulkano::Scene::Geometry* geometry, aiScene& scene, aiNode& rootNode, aiMesh& mesh, + std::unique_ptr& indices, 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; + } + + rootNode.mName = aiString("RootNode"); + rootNode.mChildren = nullptr; + rootNode.mNumChildren = 0; + scene.mRootNode = &rootNode; + + mesh.mName = aiString("Mesh"); + mesh.mNumVertices = geometry->vertexCount; + mesh.mMaterialIndex = 0; + mesh.mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + mesh.mVertices = new aiVector3D[geometry->vertexCount]; + mesh.mNormals = new aiVector3D[geometry->vertexCount]; + + if (withTexCoords) + { + mesh.mNumUVComponents[0] = 2; + mesh.mTextureCoords[0] = new aiVector3D[geometry->vertexCount]; + } + + for (int i = 0; i < geometry->vertexCount; ++i) + { + const OpenVulkano::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); + if (withTexCoords) + { + mesh.mTextureCoords[0][i] = aiVector3D(vertex.textureCoordinates.x, vertex.textureCoordinates.y, 0.0f); + } + } + + mesh.mNumFaces = geometry->indexCount / 3; + mesh.mFaces = new aiFace[mesh.mNumFaces]; + indices = std::make_unique(geometry->indexCount); + + for (unsigned int i = 0; i < geometry->indexCount; ++i) + { + indices[i] = geometry->GetIndex(i); + } + + for (unsigned int i = 0; i < mesh.mNumFaces; ++i) + { + mesh.mFaces[i].mNumIndices = 3; + mesh.mFaces[i].mIndices = &indices[i * 3]; + } + + scene.mNumMeshes = 1; + scene.mMeshes = new aiMesh*[1] { &mesh }; + + scene.mNumMaterials = 1; + scene.mMaterials = new aiMaterial*[1] { new aiMaterial() }; + + rootNode.mNumMeshes = 1; + rootNode.mMeshes = new unsigned int[1] { 0 }; + } +#endif +} + namespace OpenVulkano::Scene { void MeshWriter::WriteAsOBJ(Geometry* geometry, const std::string& filePath) @@ -90,92 +166,63 @@ namespace OpenVulkano::Scene } } + void MeshWriter::WriteAsSTL(Geometry* geometry, const std::string& filePath, bool binary) + { +#if __has_include("assimp/Exporter.hpp") + std::unique_ptr scene(new aiScene()); + std::unique_ptr rootNode(new aiNode()); + std::unique_ptr mesh(new aiMesh()); + std::unique_ptr indices; + + SetupAssimpScene(geometry, *scene, *rootNode, *mesh, indices, false, 1.0f); + + Assimp::Exporter exporter; + const char* formatId = binary ? "stlb" : "stl"; + aiReturn result = exporter.Export(scene.get(), formatId, filePath); + + scene->mRootNode = nullptr; + scene->mMeshes = nullptr; + for (uint32_t i = 0; i < mesh->mNumFaces; ++i) + { + aiFace& face = mesh->mFaces[i]; + face.mIndices = 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 + } + void MeshWriter::WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath) { #if __has_include("assimp/Exporter.hpp") - aiNode rootNode; + std::unique_ptr scene(new aiScene()); + std::unique_ptr rootNode(new aiNode()); + std::unique_ptr mesh(new aiMesh()); + std::unique_ptr indices; - aiScene scene; - scene.mRootNode = &rootNode; + SetupAssimpScene(geometry, *scene, *rootNode, *mesh, indices, true, 100.0f); - aiMesh mesh; - mesh.mNumVertices = geometry->vertexCount; - mesh.mMaterialIndex = 0; - mesh.mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - mesh.mNumUVComponents[0] = 2; - - 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(); - - std::unique_ptr texCoords = std::make_unique(geometry->vertexCount); - mesh.mTextureCoords[0] = texCoords.get(); - - float scaling = 100; // fbx units are centimeters... - for (uint32_t i = 0; i < geometry->vertexCount; ++i) + if (!texturePath.empty()) { - 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); + aiString externalPath(texturePath); + scene->mMaterials[0]->AddProperty(&externalPath, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0)); } - 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 (uint32_t 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; - - aiMaterial material; - aiMaterial* materials[1] = { &material }; - scene.mMaterials = materials; - 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); + aiReturn result = exporter.Export(scene.get(), "fbx", fbxPath); - mesh.mVertices = nullptr; - mesh.mNormals = nullptr; - mesh.mTextureCoords[0] = nullptr; - for (uint32_t i = 0; i < mesh.mNumFaces; ++i) + scene->mRootNode = nullptr; + scene->mMeshes = nullptr; + for (uint32_t i = 0; i < mesh->mNumFaces; ++i) { - aiFace& face = mesh.mFaces[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) { 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