Merge pull request 'MeshWriter that can save both in .usd and .obj formats' (#120) from mesh_writer into master
Reviewed-on: https://git.madvoxel.net/OpenVulkano/OpenVulkano/pulls/120 Reviewed-by: Georg Hagen <georg.hagen@madvoxel.com>
This commit is contained in:
154
openVulkanoCpp/Scene/MeshWriter.cpp
Normal file
154
openVulkanoCpp/Scene/MeshWriter.cpp
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* 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 <fstream>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#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!");
|
||||||
|
|
||||||
|
// Vertices
|
||||||
|
for (int i = 0; i < geometry->vertexCount; ++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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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<int> 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)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
20
openVulkanoCpp/Scene/MeshWriter.hpp
Normal file
20
openVulkanoCpp/Scene/MeshWriter.hpp
Normal 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user