Moved InitFromFile() from Geometry to MeshLoader, added MeshLoader function for USD files, added tinyusdz library
This commit is contained in:
1
3rdParty/CMakeLists.txt
vendored
1
3rdParty/CMakeLists.txt
vendored
@@ -40,3 +40,4 @@ if(ENABLE_TEST)
|
|||||||
add_subdirectory(catch2)
|
add_subdirectory(catch2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(tinyusdz)
|
||||||
22
3rdParty/tinyusdz/CMakeLists.txt
vendored
Normal file
22
3rdParty/tinyusdz/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
include(Utils)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
message("-- Building TinyUSDZ")
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
tinyusdz
|
||||||
|
GIT_REPOSITORY https://github.com/syoyo/tinyusdz.git
|
||||||
|
GIT_TAG v0.8.0rc8
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
CMAKE_ARGS
|
||||||
|
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/INSTALL
|
||||||
|
-DCMAKE_BUILD_TYPE:STRING=Release
|
||||||
|
-DTINYUSDZ_BUILD_TESTS:BOOL=OFF
|
||||||
|
-DTINYUSDZ_BUILD_EXAMPLES:BOOL=OFF
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(tinyusdz)
|
||||||
|
|
||||||
|
function (LinkTinyUSDZ TARGET)
|
||||||
|
target_include_directories(${TARGET} PRIVATE ${tinyusdz_SOURCE_DIR}/src)
|
||||||
|
target_link_libraries(${TARGET} PRIVATE tinyusdz_static)
|
||||||
|
endfunction ()
|
||||||
@@ -53,6 +53,7 @@ add_subdirectory(3rdParty)
|
|||||||
|
|
||||||
# Then generate the OpenVulkano Library
|
# Then generate the OpenVulkano Library
|
||||||
add_subdirectory(openVulkanoCpp)
|
add_subdirectory(openVulkanoCpp)
|
||||||
|
LinkTinyUSDZ(openVulkanoCpp)
|
||||||
|
|
||||||
if(ENABLE_TEST AND NOT IOS)
|
if(ENABLE_TEST AND NOT IOS)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|||||||
@@ -5,16 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "Vertex.hpp"
|
|
||||||
#include "Base/Utils.hpp"
|
#include "Base/Utils.hpp"
|
||||||
#include "Base/Logger.hpp"
|
#include "Base/Logger.hpp"
|
||||||
#if __has_include("assimp/Importer.hpp")
|
|
||||||
#include <assimp/Importer.hpp>
|
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <assimp/mesh.h>
|
|
||||||
#include <assimp/postprocess.h>
|
|
||||||
#define ASSIMP_AVAILABLE
|
|
||||||
#endif
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace OpenVulkano::Scene
|
namespace OpenVulkano::Scene
|
||||||
@@ -126,68 +118,6 @@ namespace OpenVulkano::Scene
|
|||||||
renderGeo = nullptr;
|
renderGeo = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Geometry::InitFromFile(const std::string& file)
|
|
||||||
{
|
|
||||||
#ifdef ASSIMP_AVAILABLE
|
|
||||||
Assimp::Importer importer;
|
|
||||||
|
|
||||||
const uint32_t flags = aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_GenNormals |
|
|
||||||
aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials | aiProcess_GenUVCoords | aiProcess_TransformUVCoords |
|
|
||||||
aiProcess_ConvertToLeftHanded | aiProcess_PreTransformVertices | aiProcess_OptimizeGraph;
|
|
||||||
|
|
||||||
const aiScene* scene = importer.ReadFile(file, flags);
|
|
||||||
if (!scene) throw std::runtime_error("Failed to load file \"" + file + "\" Error: " + importer.GetErrorString());
|
|
||||||
if (!scene->HasMeshes()) throw std::runtime_error("File \"" + file + "\" does not have any meshes");
|
|
||||||
if (scene->mNumMeshes > 1) Logger::DATA->warn("File {0} contains more than one mesh. Only first one will be loaded", file);
|
|
||||||
Init(scene->mMeshes[0]);
|
|
||||||
importer.FreeScene();
|
|
||||||
#else
|
|
||||||
throw std::runtime_error("ASSIMP not available!");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Geometry::Init(aiMesh* mesh)
|
|
||||||
{
|
|
||||||
#ifdef ASSIMP_AVAILABLE
|
|
||||||
aabb.Reset();
|
|
||||||
Init(mesh->mNumVertices, mesh->mNumFaces * 3); // Reserve the space for the data
|
|
||||||
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
|
|
||||||
{
|
|
||||||
vertices[i].Set(mesh->mVertices[i]);
|
|
||||||
if (mesh->HasNormals()) vertices[i].SetNormal(mesh->mNormals[i]);
|
|
||||||
if (mesh->HasTangentsAndBitangents())
|
|
||||||
{
|
|
||||||
vertices[i].SetTangentAndBiTangent(mesh->mTangents[i], mesh->mBitangents[i]);
|
|
||||||
}
|
|
||||||
if (mesh->HasTextureCoords(0)) vertices[i].SetTextureCoordinates(mesh->mTextureCoords[0][i]);
|
|
||||||
if (mesh->HasVertexColors(0)) vertices[i].SetColor(mesh->mColors[0][i]);
|
|
||||||
aabb.Grow(vertices[i].position);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
|
|
||||||
{
|
|
||||||
const aiFace face = mesh->mFaces[i];
|
|
||||||
if (face.mNumIndices != 3) throw std::runtime_error("Mesh is not a triangle mesh!");
|
|
||||||
for (unsigned int j = 0; j < face.mNumIndices; j++)
|
|
||||||
{
|
|
||||||
if (indexType == VertexIndexType::UINT16)
|
|
||||||
{
|
|
||||||
static_cast<uint16_t*>(indices)[i * face.mNumIndices + j] = static_cast<uint16_t>(face.mIndices[j]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static_cast<uint32_t*>(indices)[i * face.mNumIndices + j] = face.mIndices[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO load bones
|
|
||||||
//TODO load materials
|
|
||||||
#else
|
|
||||||
throw std::runtime_error("ASSIMP not available!");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Geometry::SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset) const
|
void Geometry::SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset) const
|
||||||
{
|
{
|
||||||
for(uint32_t i = 0; i < size; i++)
|
for(uint32_t i = 0; i < size; i++)
|
||||||
|
|||||||
@@ -9,14 +9,11 @@
|
|||||||
#include "Base/ICloseable.hpp"
|
#include "Base/ICloseable.hpp"
|
||||||
#include "Math/AABB.hpp"
|
#include "Math/AABB.hpp"
|
||||||
#include "Base/Utils.hpp"
|
#include "Base/Utils.hpp"
|
||||||
|
#include "Vertex.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class aiMesh;
|
|
||||||
|
|
||||||
namespace OpenVulkano
|
namespace OpenVulkano
|
||||||
{
|
{
|
||||||
struct Vertex;
|
|
||||||
|
|
||||||
namespace Scene
|
namespace Scene
|
||||||
{
|
{
|
||||||
enum class VertexIndexType
|
enum class VertexIndexType
|
||||||
@@ -26,6 +23,7 @@ namespace OpenVulkano
|
|||||||
|
|
||||||
class Geometry : public ICloseable
|
class Geometry : public ICloseable
|
||||||
{
|
{
|
||||||
|
friend class MeshLoader;
|
||||||
public:
|
public:
|
||||||
uint32_t vertexCount = 0, indexCount = 0;
|
uint32_t vertexCount = 0, indexCount = 0;
|
||||||
Vertex* vertices = nullptr;
|
Vertex* vertices = nullptr;
|
||||||
@@ -42,15 +40,6 @@ namespace OpenVulkano
|
|||||||
Geometry& operator=(Geometry&& other) noexcept;
|
Geometry& operator=(Geometry&& other) noexcept;
|
||||||
~Geometry();
|
~Geometry();
|
||||||
|
|
||||||
static Geometry* LoadFromFile(const std::string& file)
|
|
||||||
{
|
|
||||||
Geometry* mesh = new Geometry();
|
|
||||||
mesh->InitFromFile(file);
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitFromFile(const std::string& file);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Creates the arrays for the vertices and indices. They will not be filled!
|
* \brief Creates the arrays for the vertices and indices. They will not be filled!
|
||||||
* \param vertexCount The amount of vertices that will be used
|
* \param vertexCount The amount of vertices that will be used
|
||||||
@@ -58,8 +47,6 @@ namespace OpenVulkano
|
|||||||
*/
|
*/
|
||||||
void Init(uint32_t vertexCount, uint32_t indexCount);
|
void Init(uint32_t vertexCount, uint32_t indexCount);
|
||||||
|
|
||||||
void Init(aiMesh* mesh);
|
|
||||||
|
|
||||||
void SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset = 0) const;
|
void SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset = 0) const;
|
||||||
|
|
||||||
void Close() override;
|
void Close() override;
|
||||||
|
|||||||
168
openVulkanoCpp/Scene/MeshLoader.cpp
Normal file
168
openVulkanoCpp/Scene/MeshLoader.cpp
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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 "MeshLoader.hpp"
|
||||||
|
#include "Base/Logger.hpp"
|
||||||
|
#if __has_include("assimp/Importer.hpp")
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/postprocess.h>
|
||||||
|
#define ASSIMP_AVAILABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tinyusdz.hh"
|
||||||
|
#include "tydra/attribute-eval.hh"
|
||||||
|
#include "tydra/render-data.hh"
|
||||||
|
#include "tydra/scene-access.hh"
|
||||||
|
#include "tydra/shader-network.hh"
|
||||||
|
#include "usdShade.hh"
|
||||||
|
#include "pprinter.hh"
|
||||||
|
#include "prim-pprint.hh"
|
||||||
|
#include "value-pprint.hh"
|
||||||
|
#include "value-types.hh"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static bool ends_with(std::string_view str, std::string_view suffix)
|
||||||
|
{
|
||||||
|
return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace OpenVulkano::Scene
|
||||||
|
{
|
||||||
|
void MeshLoader::parseAssimpFile(Geometry *geometry, const std::string& file)
|
||||||
|
{
|
||||||
|
#ifdef ASSIMP_AVAILABLE
|
||||||
|
Assimp::Importer importer;
|
||||||
|
|
||||||
|
const uint32_t flags = aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_GenNormals |
|
||||||
|
aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials | aiProcess_GenUVCoords | aiProcess_TransformUVCoords |
|
||||||
|
aiProcess_ConvertToLeftHanded | aiProcess_PreTransformVertices | aiProcess_OptimizeGraph;
|
||||||
|
|
||||||
|
const aiScene* scene = importer.ReadFile(file, flags);
|
||||||
|
if (!scene) throw std::runtime_error("Failed to load file \"" + file + "\" Error: " + importer.GetErrorString());
|
||||||
|
if (!scene->HasMeshes()) throw std::runtime_error("File \"" + file + "\" does not have any meshes");
|
||||||
|
if (scene->mNumMeshes > 1) Logger::DATA->warn("File {0} contains more than one mesh. Only first one will be loaded", file);
|
||||||
|
aiMesh *mesh = scene->mMeshes[0];
|
||||||
|
|
||||||
|
geometry->aabb.Reset();
|
||||||
|
geometry->Init(mesh->mNumVertices, mesh->mNumFaces * 3); // Reserve the space for the data
|
||||||
|
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
|
||||||
|
{
|
||||||
|
geometry->vertices[i].Set(mesh->mVertices[i]);
|
||||||
|
if (mesh->HasNormals()) geometry->vertices[i].SetNormal(mesh->mNormals[i]);
|
||||||
|
if (mesh->HasTangentsAndBitangents())
|
||||||
|
{
|
||||||
|
geometry->vertices[i].SetTangentAndBiTangent(mesh->mTangents[i], mesh->mBitangents[i]);
|
||||||
|
}
|
||||||
|
if (mesh->HasTextureCoords(0)) geometry->vertices[i].SetTextureCoordinates(mesh->mTextureCoords[0][i]);
|
||||||
|
if (mesh->HasVertexColors(0)) geometry->vertices[i].SetColor(mesh->mColors[0][i]);
|
||||||
|
geometry->aabb.Grow(geometry->vertices[i].position);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
|
||||||
|
{
|
||||||
|
const aiFace face = mesh->mFaces[i];
|
||||||
|
if (face.mNumIndices != 3) throw std::runtime_error("Mesh is not a triangle mesh!");
|
||||||
|
for (unsigned int j = 0; j < face.mNumIndices; j++)
|
||||||
|
{
|
||||||
|
if (geometry->indexType == VertexIndexType::UINT16)
|
||||||
|
{
|
||||||
|
static_cast<uint16_t*>(geometry->indices)[i * face.mNumIndices + j] = static_cast<uint16_t>(face.mIndices[j]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_cast<uint32_t*>(geometry->indices)[i * face.mNumIndices + j] = face.mIndices[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO load bones
|
||||||
|
//TODO load materials
|
||||||
|
importer.FreeScene();
|
||||||
|
#else
|
||||||
|
throw std::runtime_error("ASSIMP not available!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshLoader::parseUSDFile(Geometry *geometry, const std::string& file)
|
||||||
|
{
|
||||||
|
tinyusdz::Stage stage;
|
||||||
|
std::string warning, err;
|
||||||
|
|
||||||
|
auto result = tinyusdz::LoadUSDFromFile(file, &stage, &warning, &err);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to load USD file: " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &prim : stage.root_prims())
|
||||||
|
{
|
||||||
|
if (prim.type_name() == "Xform")
|
||||||
|
{
|
||||||
|
for (auto& child : prim.children())
|
||||||
|
{
|
||||||
|
auto mesh = child.as<tinyusdz::GeomMesh>();
|
||||||
|
if (child.prim_type_name() == "Mesh" && mesh)
|
||||||
|
{
|
||||||
|
const auto& points = mesh->get_points();
|
||||||
|
const auto& indices = mesh->get_faceVertexIndices();
|
||||||
|
|
||||||
|
geometry->Init(static_cast<uint32_t>(points.size()), static_cast<uint32_t>(indices.size()));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < geometry->vertexCount; ++i)
|
||||||
|
{
|
||||||
|
auto point = points[i];
|
||||||
|
OpenVulkano::Math::Vector3f p;
|
||||||
|
p.x = point.x;
|
||||||
|
p.y = point.y;
|
||||||
|
p.z = point.z;
|
||||||
|
geometry->vertices[i].position = p;
|
||||||
|
geometry->aabb.Grow(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry->indexType == VertexIndexType::UINT16)
|
||||||
|
{
|
||||||
|
uint16_t* indices16 = static_cast<uint16_t*>(geometry->indices);
|
||||||
|
for (uint32_t i = 0; i < geometry->indexCount; ++i)
|
||||||
|
{
|
||||||
|
indices16[i] = static_cast<uint16_t>(indices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t* indices32 = static_cast<uint32_t*>(geometry->indices);
|
||||||
|
for (uint32_t i = 0; i < geometry->indexCount; ++i)
|
||||||
|
{
|
||||||
|
indices32[i] = indices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("No mesh found inside a xform in USD file: " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry* MeshLoader::LoadFromFile(const std::string& file)
|
||||||
|
{
|
||||||
|
Geometry* geometry = new Geometry();
|
||||||
|
|
||||||
|
if (ends_with(file, ".usd") || ends_with(file, ".usda") || ends_with(file, ".usdc") || ends_with(file, ".usdz"))
|
||||||
|
{
|
||||||
|
parseUSDFile(geometry, file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parseAssimpFile(geometry, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
openVulkanoCpp/Scene/MeshLoader.hpp
Normal file
21
openVulkanoCpp/Scene/MeshLoader.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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 "Scene/Geometry.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace OpenVulkano::Scene
|
||||||
|
{
|
||||||
|
class MeshLoader
|
||||||
|
{
|
||||||
|
static void parseAssimpFile(Geometry *geometry, const std::string& file);
|
||||||
|
static void parseUSDFile(Geometry *geometry, const std::string& file);
|
||||||
|
public:
|
||||||
|
static Geometry* LoadFromFile(const std::string& file);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user