Summary:
- Removed ReadEntireFile - ZipWriter now writes directly to a file when possible - Added GetIndex to geometry - Moved Usd and Obj generators to different files - Removed unused procedures - Deduplicated obj generators - Updated tests for ZipWriter
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "ZipWriter.hpp"
|
||||
#include "Base/Utils.hpp"
|
||||
#include "Math/CRC32.hpp"
|
||||
|
||||
#include <ctime>
|
||||
@@ -91,22 +92,6 @@ namespace
|
||||
static_assert(sizeof(EndOfCentralDirectoryHeader) == 22, "Well packed struct");
|
||||
static_assert(sizeof(NtfsExtraField) == 36, "Well packed struct");
|
||||
|
||||
std::vector<uint8_t> ReadEntireFile(const std::string& fname)
|
||||
{
|
||||
FILE *file = fopen(fname.c_str(), "rb");
|
||||
std::vector<uint8_t> buffer;
|
||||
if(file)
|
||||
{
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
buffer.resize(size);
|
||||
fread(buffer.data(), size, 1, file);
|
||||
fclose(file);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint32_t Cat(std::vector<uint8_t>& dest, T* thing)
|
||||
{
|
||||
@@ -157,6 +142,15 @@ namespace
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
ZipWriter::ZipWriter(const std::filesystem::path& filePath)
|
||||
{
|
||||
m_file = fopen(filePath.string().c_str(), "wb");
|
||||
if (!m_file)
|
||||
{
|
||||
throw std::runtime_error("Unable to open file for writing: " + filePath.string());
|
||||
}
|
||||
}
|
||||
|
||||
void ZipWriter::AddFile(const FileDescription& description, const void* buffer)
|
||||
{
|
||||
size_t fileSize = description.size;
|
||||
@@ -177,9 +171,10 @@ namespace OpenVulkano
|
||||
lfh.compressedSize = lfh.uncompressedSize = fileSize;
|
||||
lfh.fileNameLength = fileNameLength;
|
||||
|
||||
size_t headerOffset = Cat(m_headers, &lfh);
|
||||
Cat(m_headers, fileNameLength, fileName);
|
||||
Cat(m_headers, description.size, (uint8_t *)buffer);
|
||||
size_t headerOffset = ftell(m_file);
|
||||
fwrite(&lfh, sizeof(lfh), 1, m_file);
|
||||
fwrite(fileName, fileNameLength, 1, m_file);
|
||||
fwrite(buffer, fileSize, 1, m_file);
|
||||
|
||||
CentalDirectoryFileHeader cdfh;
|
||||
cdfh.fileLastModTime = dosTime;
|
||||
@@ -203,41 +198,28 @@ namespace OpenVulkano
|
||||
m_numFiles += 1;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ZipWriter::GetMemory()
|
||||
void ZipWriter::AddFile(const std::filesystem::path& fileName, const char* inArchiveName)
|
||||
{
|
||||
std::vector<uint8_t> buffer = m_headers;
|
||||
|
||||
auto data = Utils::ReadFile(fileName.string());
|
||||
auto desc = OpenVulkano::FileDescription::MakeDescriptionForFile(inArchiveName, data.Size());
|
||||
AddFile(desc, data.Data());
|
||||
}
|
||||
|
||||
void ZipWriter::Close()
|
||||
{
|
||||
int centralDirsOffset = 0;
|
||||
if (m_numFiles)
|
||||
{
|
||||
int centralDirsOffset = Cat(buffer, m_centralDirs);
|
||||
centralDirsOffset = ftell(m_file);
|
||||
fwrite(m_centralDirs.data(), m_centralDirs.size(), 1, m_file);
|
||||
m_centralDirs.clear();
|
||||
}
|
||||
|
||||
EndOfCentralDirectoryHeader eocd;
|
||||
eocd.centralDirectoryEntries = eocd.totalCentralDirectoryEntries = m_numFiles;
|
||||
eocd.centralDirectoryOffset = m_headers.size();
|
||||
eocd.centralDirectoryOffset = centralDirsOffset;
|
||||
|
||||
Cat(buffer, &eocd);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void ZipWriter::AddFile(const std::filesystem::path& fileName, const char* inArchiveName)
|
||||
{
|
||||
auto data = ReadEntireFile(fileName.string());
|
||||
auto desc = OpenVulkano::FileDescription::MakeDescriptionForFile(inArchiveName, data.size());
|
||||
AddFile(desc, data.data());
|
||||
}
|
||||
|
||||
bool ZipWriter::Write(const std::filesystem::path& archivePath)
|
||||
{
|
||||
FILE* file = fopen(archivePath.string().c_str(), "wb");
|
||||
if (file)
|
||||
{
|
||||
auto mem = GetMemory();
|
||||
fwrite(mem.data(), mem.size(), 1, file);
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
fwrite(&eocd, sizeof(eocd), 1, m_file);
|
||||
fclose(m_file);
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,15 @@ namespace OpenVulkano
|
||||
{
|
||||
class ZipWriter
|
||||
{
|
||||
std::vector<uint8_t> m_headers;
|
||||
std::vector<uint8_t> m_centralDirs;
|
||||
int m_numFiles = 0;
|
||||
FILE *m_file;
|
||||
|
||||
public:
|
||||
ZipWriter(const std::filesystem::path& filePath);
|
||||
|
||||
void AddFile(const FileDescription& description, const void* buffer);
|
||||
void AddFile(const std::filesystem::path& fileName, const char* inArchiveName);
|
||||
|
||||
bool Write(const std::filesystem::path& archivePath);
|
||||
std::vector<uint8_t> GetMemory();
|
||||
void Close();
|
||||
};
|
||||
}
|
||||
@@ -153,4 +153,29 @@ namespace OpenVulkano::Scene
|
||||
vertices = nullptr;
|
||||
indices = nullptr;
|
||||
}
|
||||
|
||||
uint32_t Geometry::GetIndex(int index) const
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
if (index >= indexCount)
|
||||
throw std::out_of_range("Index is out of range");
|
||||
|
||||
if (indexType == OpenVulkano::Scene::VertexIndexType::UINT16)
|
||||
{
|
||||
uint16_t* indices = GetIndices16();
|
||||
result = indices[index];
|
||||
}
|
||||
else if (indexType == OpenVulkano::Scene::VertexIndexType::UINT32)
|
||||
{
|
||||
uint32_t* indices = GetIndices32();
|
||||
result = indices[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid geometry index type");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace OpenVulkano
|
||||
|
||||
Vertex* GetVertices() const { return vertices; }
|
||||
void* GetIndices() const { return indices; }
|
||||
uint32_t GetIndex(int index) const;
|
||||
uint16_t* GetIndices16() const { return static_cast<uint16_t*>(indices); }
|
||||
uint32_t* GetIndices32() const { return static_cast<uint32_t*>(indices); }
|
||||
uint32_t GetIndexCount() const { return indexCount; }
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "MeshWriter.hpp"
|
||||
#include "Scene/Geometry.hpp"
|
||||
#include "Scene/Vertex.hpp"
|
||||
#include "Scene/UsdEncoder.hpp"
|
||||
#include "Scene/ObjEncoder.hpp"
|
||||
#include "IO/Archive/ArchiveWriter.hpp"
|
||||
#include "IO/Archive/ZipWriter.hpp"
|
||||
#include <fstream>
|
||||
@@ -22,268 +24,6 @@
|
||||
#include <usdc-reader.hh>
|
||||
#include <usdc-writer.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;
|
||||
}
|
||||
|
||||
std::string ReadEntireFile(const std::string& fname)
|
||||
{
|
||||
FILE *file = fopen(fname.c_str(), "rb");
|
||||
std::string buffer;
|
||||
if(file)
|
||||
{
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
buffer = std::string(size, ' ');
|
||||
fread(&buffer[0], size, 1, file);
|
||||
fclose(file);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void WriteGeometryWithoutTexturesUsingTinyusdz(OpenVulkano::Scene::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 (uint32_t i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const OpenVulkano::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 (uint32_t 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();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ConvertToUSDC(const std::string& contents)
|
||||
{
|
||||
std::vector<uint8_t> result;
|
||||
tinyusdz::Stage stage;
|
||||
std::string warn, err;
|
||||
assert(tinyusdz::LoadUSDAFromMemory((const uint8_t *)contents.data(), (const size_t)contents.size(), "", &stage, &warn, &err));
|
||||
bool ret = tinyusdz::usdc::SaveAsUSDCToMemory(stage, &result, &warn, &err); // As for now, this reports that it's not implemented...
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetUsdContents(OpenVulkano::Scene::Geometry* geometry, const std::string texturePath = "")
|
||||
{
|
||||
std::ostringstream file;
|
||||
std::ostringstream points, normals, indices, texCoords, faceCounts;
|
||||
points << std::fixed << std::setprecision(6);
|
||||
normals << std::fixed << std::setprecision(6);
|
||||
|
||||
for (size_t i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
points << "(" << v.position.x << ", " << v.position.y << ", " << v.position.z << ")";
|
||||
normals << "(" << v.normal.x << ", " << v.normal.y << ", " << v.normal.z << ")";
|
||||
if (i < geometry->vertexCount - 1)
|
||||
{
|
||||
points << ", ";
|
||||
normals << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < geometry->indexCount; ++i)
|
||||
{
|
||||
indices << GetIndexFromGeometry(geometry, i);
|
||||
if (i < geometry->indexCount - 1)
|
||||
{
|
||||
indices << ", ";
|
||||
}
|
||||
if ((i + 1) % 3 == 0)
|
||||
{
|
||||
faceCounts << "3";
|
||||
if (i < geometry->indexCount - 1)
|
||||
{
|
||||
faceCounts << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texCoords << std::fixed << std::setprecision(6);
|
||||
|
||||
for (size_t i = 0; i < geometry->indexCount; ++i)
|
||||
{
|
||||
const size_t vertexIndex = GetIndexFromGeometry(geometry, i);
|
||||
const auto& v = geometry->vertices[vertexIndex];
|
||||
texCoords << "(" << v.textureCoordinates.x << ", " << v.textureCoordinates.y << ")";
|
||||
if (i < geometry->indexCount - 1)
|
||||
{
|
||||
texCoords << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
file << R"(#usda 1.0
|
||||
(
|
||||
defaultPrim = "root"
|
||||
doc = "Exported from OpenVulkano"
|
||||
metersPerUnit = 1
|
||||
upAxis = "Z"
|
||||
)
|
||||
|
||||
def Xform "root" (
|
||||
customData = {
|
||||
dictionary Blender = {
|
||||
bool generated = 1
|
||||
}
|
||||
}
|
||||
)
|
||||
{
|
||||
def Xform "model"
|
||||
{
|
||||
custom string userProperties:blender:object_name = "model"
|
||||
float3 xformOp:rotateXYZ = (89.99999, -0, 0)
|
||||
float3 xformOp:scale = (1, 1, 1)
|
||||
double3 xformOp:translate = (0, 0, 0)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Mesh "model" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-0.5, -0.5, 0), (0.5, 0.5, 0)]
|
||||
int[] faceVertexCounts = [)"
|
||||
<< faceCounts.str() << R"(]
|
||||
int[] faceVertexIndices = [)"
|
||||
<< indices.str() << R"(]
|
||||
rel material:binding = </root/_materials/Material0>
|
||||
normal3f[] normals = [)"
|
||||
<< normals.str() << R"(] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [)"
|
||||
<< points.str() << R"(]
|
||||
texCoord2f[] primvars:st = [)"
|
||||
<< texCoords.str() << R"(] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
custom string userProperties:blender:data_name = "model"
|
||||
}
|
||||
}
|
||||
|
||||
def Scope "_materials"
|
||||
{
|
||||
def Material "Material0"
|
||||
{
|
||||
token outputs:surface.connect = </root/_materials/Material0/Principled_BSDF.outputs:surface>
|
||||
custom string userProperties:blender:data_name = "Material0"
|
||||
|
||||
def Shader "Principled_BSDF"
|
||||
{
|
||||
uniform token info:id = "UsdPreviewSurface"
|
||||
float inputs:clearcoat = 0
|
||||
float inputs:clearcoatRoughness = 0.03
|
||||
color3f inputs:diffuseColor.connect = </root/_materials/Material0/Image_Texture.outputs:rgb>
|
||||
float inputs:ior = 1.5
|
||||
float inputs:metallic = 0
|
||||
float inputs:opacity = 1
|
||||
float inputs:roughness = 1
|
||||
float inputs:specular = 0
|
||||
token outputs:surface
|
||||
}
|
||||
|
||||
def Shader "Image_Texture"
|
||||
{
|
||||
uniform token info:id = "UsdUVTexture"
|
||||
asset inputs:file = @./texture.png@
|
||||
token inputs:sourceColorSpace = "sRGB"
|
||||
float2 inputs:st.connect = </root/_materials/Material0/uvmap.outputs:result>
|
||||
token inputs:wrapS = "repeat"
|
||||
token inputs:wrapT = "repeat"
|
||||
float3 outputs:rgb
|
||||
}
|
||||
|
||||
def Shader "uvmap"
|
||||
{
|
||||
uniform token info:id = "UsdPrimvarReader_float2"
|
||||
string inputs:varname = "st"
|
||||
float2 outputs:result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
return file.str();
|
||||
}
|
||||
}
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
void MeshWriter::WriteAsOBJ(Geometry* geometry, const std::string& filePath)
|
||||
@@ -293,43 +33,8 @@ namespace OpenVulkano::Scene
|
||||
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;
|
||||
}
|
||||
|
||||
auto [objContents, mtlContents] = GetObjContents(geometry, "");
|
||||
file << objContents;
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -345,64 +50,27 @@ namespace OpenVulkano::Scene
|
||||
|
||||
void MeshWriter::WriteObjAsZip(Geometry* geometry, const std::string& zipPath, const std::string& texturePath)
|
||||
{
|
||||
std::stringstream mtlContent;
|
||||
std::string materialName = "Material0";
|
||||
mtlContent << "newmtl " << materialName << "\n";
|
||||
mtlContent << "Ka 1.000 1.000 1.000\n"; // Ambient
|
||||
mtlContent << "Kd 1.000 1.000 1.000\n"; // Diffuse
|
||||
mtlContent << "Ks 0.000 0.000 0.000\n"; // Specular
|
||||
if (!texturePath.empty())
|
||||
{
|
||||
mtlContent << "map_Ka texture.png\n"; // Ambient map
|
||||
mtlContent << "map_Kd texture.png\n"; // Texture map
|
||||
}
|
||||
|
||||
std::stringstream objContent;
|
||||
objContent << "# OBJ file generated by OpenVulkanoCpp\n";
|
||||
objContent << "mtllib material.mtl\n";
|
||||
objContent << "usemtl " << materialName << "\n";
|
||||
for (int i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
objContent << fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z);
|
||||
}
|
||||
for (int i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
objContent << fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z);
|
||||
}
|
||||
for (int i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
objContent << fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y);
|
||||
}
|
||||
for (int i = 0; i < geometry->indexCount; i += 3)
|
||||
{
|
||||
uint32_t i0 = GetIndexFromGeometry(geometry, i) + 1;
|
||||
uint32_t i1 = GetIndexFromGeometry(geometry, i + 1) + 1;
|
||||
uint32_t i2 = GetIndexFromGeometry(geometry, i + 2) + 1;
|
||||
objContent << fmt::format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2);
|
||||
}
|
||||
|
||||
OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str());
|
||||
|
||||
auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContent.str().size());
|
||||
zipWriter.AddFile(objDesc, objContent.str().data());
|
||||
auto [objContents, mtlContents] = GetObjContents(geometry, texturePath);
|
||||
|
||||
auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContent.str().size());
|
||||
zipWriter.AddFile(mtlDesc, mtlContent.str().data());
|
||||
auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContents.size());
|
||||
zipWriter.AddFile(objDesc, objContents.data());
|
||||
|
||||
auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContents.size());
|
||||
zipWriter.AddFile(mtlDesc, mtlContents.data());
|
||||
|
||||
if (!texturePath.empty() && std::filesystem::exists(texturePath))
|
||||
{
|
||||
auto textureFileSize = std::filesystem::file_size(texturePath);
|
||||
auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFileSize);
|
||||
zipWriter.AddFile(texDesc, ReadEntireFile(texturePath).c_str());
|
||||
auto textureFile = Utils::ReadFile(texturePath);
|
||||
auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
|
||||
zipWriter.AddFile(texDesc, textureFile.Data());
|
||||
}
|
||||
}
|
||||
|
||||
void MeshWriter::WriteAsUSDZ(Geometry* geometry, const std::string& usdzPath, const std::string& texturePath)
|
||||
{
|
||||
OpenVulkano::ZipWriter zipWriter;
|
||||
OpenVulkano::ZipWriter zipWriter(usdzPath);
|
||||
|
||||
std::string usd = GetUsdContents(geometry, texturePath);
|
||||
auto usdDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("geometry.usda", usd.size());
|
||||
@@ -410,14 +78,11 @@ namespace OpenVulkano::Scene
|
||||
|
||||
if (!texturePath.empty() && std::filesystem::exists(texturePath))
|
||||
{
|
||||
auto textureFileSize = std::filesystem::file_size(texturePath);
|
||||
auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFileSize);
|
||||
zipWriter.AddFile(texDesc, ReadEntireFile(texturePath).c_str());
|
||||
auto textureFile = Utils::ReadFile(texturePath);
|
||||
auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
|
||||
zipWriter.AddFile(texDesc, textureFile.Data());
|
||||
}
|
||||
|
||||
if(!zipWriter.Write(usdzPath))
|
||||
{
|
||||
throw std::runtime_error("Unable to write to USDZ file " + usdzPath);
|
||||
}
|
||||
zipWriter.Close();
|
||||
}
|
||||
}
|
||||
69
openVulkanoCpp/Scene/ObjEncoder.hpp
Normal file
69
openVulkanoCpp/Scene/ObjEncoder.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 <utility>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fmt/core.h>
|
||||
#include "Scene/Geometry.hpp"
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
// Returns [objContents, mtlContents]
|
||||
std::pair<std::string, std::string> GetObjContents(Geometry* geometry, const std::string& texturePath)
|
||||
{
|
||||
std::pair<std::string, std::string> result;
|
||||
|
||||
bool useTexture = texturePath.size() != 0;
|
||||
|
||||
std::stringstream objContent;
|
||||
objContent << "# OBJ file generated by OpenVulkanoCpp\n";
|
||||
|
||||
if (useTexture)
|
||||
{
|
||||
std::stringstream mtlContent;
|
||||
std::string materialName = "Material0";
|
||||
mtlContent << "newmtl " << materialName << R"(
|
||||
Ka 1.000 1.000 1.000
|
||||
Kd 1.000 1.000 1.000
|
||||
Ks 0.000 0.000 0.000
|
||||
map_Ka texture.png
|
||||
map_Kd texture.png
|
||||
)";
|
||||
objContent << "mtllib material.mtl\nusemtl " << materialName << "\n";
|
||||
|
||||
result.second = mtlContent.str();
|
||||
}
|
||||
|
||||
for (int i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
objContent << fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z);
|
||||
}
|
||||
for (int i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
objContent << fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z);
|
||||
}
|
||||
for (int i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
objContent << fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y);
|
||||
}
|
||||
for (int i = 0; i < geometry->indexCount; i += 3)
|
||||
{
|
||||
uint32_t i0 = geometry->GetIndex(i + 0) + 1;
|
||||
uint32_t i1 = geometry->GetIndex(i + 1) + 1;
|
||||
uint32_t i2 = geometry->GetIndex(i + 2) + 1;
|
||||
objContent << fmt::format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2);
|
||||
}
|
||||
|
||||
result.first = objContent.str();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
158
openVulkanoCpp/Scene/UsdEncoder.hpp
Normal file
158
openVulkanoCpp/Scene/UsdEncoder.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 <sstream>
|
||||
|
||||
#include "Scene/Geometry.hpp"
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
std::string GetUsdContents(OpenVulkano::Scene::Geometry* geometry, const std::string texturePath = "")
|
||||
{
|
||||
std::ostringstream result;
|
||||
std::ostringstream points, normals, indices, texCoords, faceCounts;
|
||||
points << std::fixed << std::setprecision(6);
|
||||
normals << std::fixed << std::setprecision(6);
|
||||
|
||||
for (size_t i = 0; i < geometry->vertexCount; ++i)
|
||||
{
|
||||
const auto& v = geometry->vertices[i];
|
||||
points << "(" << v.position.x << ", " << v.position.y << ", " << v.position.z << ")";
|
||||
normals << "(" << v.normal.x << ", " << v.normal.y << ", " << v.normal.z << ")";
|
||||
if (i < geometry->vertexCount - 1)
|
||||
{
|
||||
points << ", ";
|
||||
normals << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < geometry->indexCount; ++i)
|
||||
{
|
||||
indices << geometry->GetIndex(i);
|
||||
if (i < geometry->indexCount - 1)
|
||||
{
|
||||
indices << ", ";
|
||||
}
|
||||
if ((i + 1) % 3 == 0)
|
||||
{
|
||||
faceCounts << "3";
|
||||
if (i < geometry->indexCount - 1)
|
||||
{
|
||||
faceCounts << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texCoords << std::fixed << std::setprecision(6);
|
||||
|
||||
for (size_t i = 0; i < geometry->indexCount; ++i)
|
||||
{
|
||||
const size_t vertexIndex = geometry->GetIndex(i);
|
||||
const auto& v = geometry->vertices[vertexIndex];
|
||||
texCoords << "(" << v.textureCoordinates.x << ", " << v.textureCoordinates.y << ")";
|
||||
if (i < geometry->indexCount - 1)
|
||||
{
|
||||
texCoords << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
result << R"(#usda 1.0
|
||||
(
|
||||
defaultPrim = "root"
|
||||
doc = "Exported from OpenVulkano"
|
||||
metersPerUnit = 1
|
||||
upAxis = "Y"
|
||||
)
|
||||
|
||||
def Xform "root" (
|
||||
customData = {
|
||||
dictionary Blender = {
|
||||
bool generated = 1
|
||||
}
|
||||
}
|
||||
)
|
||||
{
|
||||
def Xform "model"
|
||||
{
|
||||
custom string userProperties:blender:object_name = "model"
|
||||
float3 xformOp:rotateXYZ = (90, -0, 0)
|
||||
float3 xformOp:scale = (1, 1, 1)
|
||||
double3 xformOp:translate = (0, 0, 0)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
|
||||
|
||||
def Mesh "model" (
|
||||
active = true
|
||||
prepend apiSchemas = ["MaterialBindingAPI"]
|
||||
)
|
||||
{
|
||||
uniform bool doubleSided = 1
|
||||
float3[] extent = [(-0.5, -0.5, 0), (0.5, 0.5, 0)]
|
||||
int[] faceVertexCounts = [)"
|
||||
<< faceCounts.str() << R"(]
|
||||
int[] faceVertexIndices = [)"
|
||||
<< indices.str() << R"(]
|
||||
rel material:binding = </root/_materials/Material0>
|
||||
normal3f[] normals = [)"
|
||||
<< normals.str() << R"(] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
point3f[] points = [)"
|
||||
<< points.str() << R"(]
|
||||
texCoord2f[] primvars:st = [)"
|
||||
<< texCoords.str() << R"(] (
|
||||
interpolation = "faceVarying"
|
||||
)
|
||||
uniform token subdivisionScheme = "none"
|
||||
custom string userProperties:blender:data_name = "model"
|
||||
}
|
||||
}
|
||||
|
||||
def Scope "_materials"
|
||||
{
|
||||
def Material "Material0"
|
||||
{
|
||||
token outputs:surface.connect = </root/_materials/Material0/Principled_BSDF.outputs:surface>
|
||||
custom string userProperties:blender:data_name = "Material0"
|
||||
|
||||
def Shader "Principled_BSDF"
|
||||
{
|
||||
uniform token info:id = "UsdPreviewSurface"
|
||||
float inputs:clearcoat = 0
|
||||
float inputs:clearcoatRoughness = 0.03
|
||||
color3f inputs:diffuseColor.connect = </root/_materials/Material0/Image_Texture.outputs:rgb>
|
||||
float inputs:ior = 1.5
|
||||
float inputs:metallic = 0
|
||||
float inputs:opacity = 1
|
||||
float inputs:roughness = 1
|
||||
float inputs:specular = 0
|
||||
token outputs:surface
|
||||
}
|
||||
|
||||
def Shader "Image_Texture"
|
||||
{
|
||||
uniform token info:id = "UsdUVTexture"
|
||||
asset inputs:file = @./texture.png@
|
||||
token inputs:sourceColorSpace = "sRGB"
|
||||
float2 inputs:st.connect = </root/_materials/Material0/uvmap.outputs:result>
|
||||
token inputs:wrapS = "repeat"
|
||||
token inputs:wrapT = "repeat"
|
||||
float3 outputs:rgb
|
||||
}
|
||||
|
||||
def Shader "uvmap"
|
||||
{
|
||||
uniform token info:id = "UsdPrimvarReader_float2"
|
||||
string inputs:varname = "st"
|
||||
float2 outputs:result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
return result.str();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user