From fa3a7a7fb7825467a89eb34bbd2fea9acdb366d9 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Wed, 4 Sep 2024 21:24:31 +0300 Subject: [PATCH 1/2] MeshWriter that can save both in .usd and .obj formats --- openVulkanoCpp/Scene/MeshWriter.cpp | 153 ++++++++++++++++++++++++++++ openVulkanoCpp/Scene/MeshWriter.hpp | 20 ++++ 2 files changed, 173 insertions(+) create mode 100644 openVulkanoCpp/Scene/MeshWriter.cpp create mode 100644 openVulkanoCpp/Scene/MeshWriter.hpp diff --git a/openVulkanoCpp/Scene/MeshWriter.cpp b/openVulkanoCpp/Scene/MeshWriter.cpp new file mode 100644 index 0000000..4ec8ce5 --- /dev/null +++ b/openVulkanoCpp/Scene/MeshWriter.cpp @@ -0,0 +1,153 @@ +/* + * 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 "Scene/Geometry.hpp" +#include "Scene/Vertex.hpp" +#include +#include +#include "tinyusdz.hh" +#include "pprinter.hh" +#include "prim-pprint.hh" +#include "value-pprint.hh" + +namespace +{ + uint32_t GetIndexFromGeometry(OpenVulkano::Scene::Geometry *geometry, int index) + { + uint32_t result = 0; + + if (geometry->indexType == OpenVulkano::Scene::VertexIndexType::UINT16) + { + uint16_t *indices = static_cast(geometry->indices); + result = indices[index]; + } + else if (geometry->indexType == OpenVulkano::Scene::VertexIndexType::UINT32) + { + uint32_t *indices = static_cast(geometry->indices); + result = indices[index]; + } + else + { + throw std::runtime_error("Invalid geometry index type"); + } + + return result; + } +} + +namespace OpenVulkano::Scene +{ + void MeshWriter::WriteAsOBJ(Geometry *geometry, const std::string &filePath) + { + std::ofstream file(filePath); + + if (!file.is_open()) + throw std::runtime_error("Failed to open file '" + filePath + "' for writing!"); + + for (int i = 0; i < geometry->vertexCount; ++i) + { + OpenVulkano::Vertex v = geometry->vertices[i]; + std::string line; + + line = fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z); + file << line; + + line = fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z); + file << line; + + line = fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y); + file << line; + + // NOTE(vb): There aren't specd way to encode colors... + } + + for (int i = 0; i < geometry->indexCount; i += 3) + { + uint32_t i0 = GetIndexFromGeometry(geometry, i + 0) + 1; + uint32_t i1 = GetIndexFromGeometry(geometry, i + 1) + 1; + uint32_t i2 = GetIndexFromGeometry(geometry, i + 2) + 1; + std::string line = fmt::format("f {}/{}/{} {}/{}/{} {}/{}/{}\n", + i0, i0, i0, + i1, i1, i1, + i2, i2, i2 + ); + file << line; + } + + file.close(); + } + + void MeshWriter::WriteAsUSD(Geometry *geometry, const std::string &filePath) + { + tinyusdz::Stage stage; + tinyusdz::Xform xform; + tinyusdz::GeomMesh mesh; + mesh.name = "TheMesh"; + + std::vector pts(geometry->vertexCount); + std::vector indices(geometry->indexCount); + tinyusdz::Attribute uvAttr; + std::vector uvs(geometry->vertexCount); + + for (int i = 0; i < geometry->vertexCount; ++i) + { + Vertex v = geometry->vertices[i]; + tinyusdz::value::point3f p; + p.x = v.position.x; + p.y = v.position.y; + p.z = v.position.z; + pts[i] = p; + uvs[i] = { v.textureCoordinates.x, v.textureCoordinates.y }; + } + + mesh.points.set_value(pts); + uvAttr.set_value(uvs); + + std::vector counts; + for (int i = 0; i < geometry->indexCount / 3; ++i) + { + counts.push_back(3); // NOTE(vb): This value is kind of arbitrary, but the array must be in the mesh! + } + mesh.faceVertexCounts.set_value(counts); + + for (int i = 0; i < geometry->indexCount; ++i) + { + uint32_t index = GetIndexFromGeometry(geometry, i); + indices[i] = index; + } + mesh.faceVertexIndices.set_value(indices); + + uvAttr.metas().interpolation = tinyusdz::Interpolation::FaceVarying; + tinyusdz::Property uvProp(uvAttr); + mesh.props.emplace("primvars:UVMap", uvProp); + + tinyusdz::Prim xformPrim(xform); + tinyusdz::Prim meshPrim(mesh); + std::string err; + if (!xformPrim.add_child(std::move(meshPrim), true, &err)) + { + throw std::runtime_error("Failed to construct scene: " + err); + } + if (!stage.add_root_prim(std::move(xformPrim))) + { + throw std::runtime_error("Failed to add prim to stage root: " + stage.get_error()); + } + stage.metas().defaultPrim = tinyusdz::value::token(xformPrim.element_name()); + stage.metas().comment = "Generated by OpenVulkanoCpp"; + if (!stage.commit()) + { + throw std::runtime_error("Failed to commit stage: " + stage.get_error()); + } + + std::ofstream file(filePath); + if (!file.is_open()) + throw std::runtime_error("Failed to open file '" + filePath + "' for writing!"); + std::string scene = to_string(stage); + file << scene << "\n"; + file.close(); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Scene/MeshWriter.hpp b/openVulkanoCpp/Scene/MeshWriter.hpp new file mode 100644 index 0000000..42bb7d3 --- /dev/null +++ b/openVulkanoCpp/Scene/MeshWriter.hpp @@ -0,0 +1,20 @@ +/* + * 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/. + */ + +#pragma once + +#include + +namespace OpenVulkano::Scene +{ + class Geometry; + class MeshWriter + { + public: + static void WriteAsOBJ(Geometry *geometry, const std::string &filePath); + static void WriteAsUSD(Geometry *geometry, const std::string &filePath); + }; +} \ No newline at end of file From 83c3a775eec846f87a703da553bd30ad916f850e Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Mon, 9 Sep 2024 21:52:17 +0300 Subject: [PATCH 2/2] Code style changes, minor reorderings --- openVulkanoCpp/Scene/MeshWriter.cpp | 69 +++++++++++++++-------------- openVulkanoCpp/Scene/MeshWriter.hpp | 4 +- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/openVulkanoCpp/Scene/MeshWriter.cpp b/openVulkanoCpp/Scene/MeshWriter.cpp index 4ec8ce5..fccd8ca 100644 --- a/openVulkanoCpp/Scene/MeshWriter.cpp +++ b/openVulkanoCpp/Scene/MeshWriter.cpp @@ -7,16 +7,16 @@ #include "MeshWriter.hpp" #include "Scene/Geometry.hpp" #include "Scene/Vertex.hpp" -#include #include -#include "tinyusdz.hh" -#include "pprinter.hh" -#include "prim-pprint.hh" -#include "value-pprint.hh" +#include +#include +#include +#include +#include namespace { - uint32_t GetIndexFromGeometry(OpenVulkano::Scene::Geometry *geometry, int index) + uint32_t GetIndexFromGeometry(OpenVulkano::Scene::Geometry* geometry, int index) { uint32_t result = 0; @@ -41,47 +41,54 @@ namespace namespace OpenVulkano::Scene { - void MeshWriter::WriteAsOBJ(Geometry *geometry, const std::string &filePath) + void MeshWriter::WriteAsOBJ(Geometry* geometry, const std::string& filePath) { std::ofstream file(filePath); if (!file.is_open()) throw std::runtime_error("Failed to open file '" + filePath + "' for writing!"); + // Vertices for (int i = 0; i < geometry->vertexCount; ++i) { - OpenVulkano::Vertex v = geometry->vertices[i]; + const OpenVulkano::Vertex& v = geometry->vertices[i]; std::string line; - line = fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z); file << line; - - line = fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z); - file << line; - - line = fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y); - file << line; - - // NOTE(vb): There aren't specd way to encode colors... } + // Normals + for (int i = 0; i < geometry->vertexCount; ++i) + { + const OpenVulkano::Vertex& v = geometry->vertices[i]; + std::string line; + line = fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z); + file << line; + } + + // TexCoords + for (int i = 0; i < geometry->vertexCount; ++i) + { + const OpenVulkano::Vertex& v = geometry->vertices[i]; + std::string line; + line = fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y); + file << line; + } + + // Indices for (int i = 0; i < geometry->indexCount; i += 3) { uint32_t i0 = GetIndexFromGeometry(geometry, i + 0) + 1; uint32_t i1 = GetIndexFromGeometry(geometry, i + 1) + 1; uint32_t i2 = GetIndexFromGeometry(geometry, i + 2) + 1; - std::string line = fmt::format("f {}/{}/{} {}/{}/{} {}/{}/{}\n", - i0, i0, i0, - i1, i1, i1, - i2, i2, i2 - ); + std::string line = fmt::format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2); file << line; } file.close(); } - void MeshWriter::WriteAsUSD(Geometry *geometry, const std::string &filePath) + void MeshWriter::WriteAsUSD(Geometry* geometry, const std::string& filePath) { tinyusdz::Stage stage; tinyusdz::Xform xform; @@ -95,23 +102,17 @@ namespace OpenVulkano::Scene for (int i = 0; i < geometry->vertexCount; ++i) { - Vertex v = geometry->vertices[i]; - tinyusdz::value::point3f p; - p.x = v.position.x; - p.y = v.position.y; - p.z = v.position.z; - pts[i] = p; + const Vertex& v = geometry->vertices[i]; + pts[i].x = v.position.x; + pts[i].y = v.position.y; + pts[i].z = v.position.z; uvs[i] = { v.textureCoordinates.x, v.textureCoordinates.y }; } mesh.points.set_value(pts); uvAttr.set_value(uvs); - std::vector counts; - for (int i = 0; i < geometry->indexCount / 3; ++i) - { - counts.push_back(3); // NOTE(vb): This value is kind of arbitrary, but the array must be in the mesh! - } + std::vector counts(geometry->indexCount / 3, 3); // NOTE(vb): The value 3 is kind of arbitrary, but this array must be in the mesh! mesh.faceVertexCounts.set_value(counts); for (int i = 0; i < geometry->indexCount; ++i) diff --git a/openVulkanoCpp/Scene/MeshWriter.hpp b/openVulkanoCpp/Scene/MeshWriter.hpp index 42bb7d3..940cc97 100644 --- a/openVulkanoCpp/Scene/MeshWriter.hpp +++ b/openVulkanoCpp/Scene/MeshWriter.hpp @@ -14,7 +14,7 @@ namespace OpenVulkano::Scene class MeshWriter { public: - static void WriteAsOBJ(Geometry *geometry, const std::string &filePath); - static void WriteAsUSD(Geometry *geometry, const std::string &filePath); + static void WriteAsOBJ(Geometry* geometry, const std::string& filePath); + static void WriteAsUSD(Geometry* geometry, const std::string& filePath); }; } \ No newline at end of file