MeshWriter that can save both in .usd and .obj formats

This commit is contained in:
Vladyslav Baranovskyi
2024-09-04 21:24:31 +03:00
parent 96b6a5634b
commit fa3a7a7fb7
2 changed files with 173 additions and 0 deletions

View File

@@ -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 <fmt/core.h>
#include <fstream>
#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<uint16_t *>(geometry->indices);
result = indices[index];
}
else if (geometry->indexType == OpenVulkano::Scene::VertexIndexType::UINT32)
{
uint32_t *indices = static_cast<uint32_t *>(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<tinyusdz::value::point3f> pts(geometry->vertexCount);
std::vector<int> indices(geometry->indexCount);
tinyusdz::Attribute uvAttr;
std::vector<tinyusdz::value::texcoord2f> 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<int> 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();
}
}

View File

@@ -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 <string>
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);
};
}