Initial add of pxr compat API.

This commit is contained in:
Syoyo Fujita
2021-09-19 22:54:34 +09:00
parent d88d66882c
commit dcb5f18887
11 changed files with 261 additions and 44 deletions

View File

@@ -23,6 +23,8 @@ option(TINYUSDZ_WITH_AUDIO "Build with Audio support(WAV and MP3)" ON)
option(TINYUSDZ_WITH_PYTHON "Build with Python binding through pybind11" OFF)
option(TINYUSDZ_WITH_PXR_COMPAT_API "Build with pxr compatible API" ON)
option(TINYUSDZ_WITH_BLENDER_ADDON "Build with Python module for Blender(`TINYUSDZ_WITH_PYTHON` is force set to ON" OFF)
# -- EXR --
@@ -94,6 +96,10 @@ set(TINYUSDZ_SOURCES
${PROJECT_SOURCE_DIR}/src/pprinter.cc
)
if (TINYUSDZ_WITH_PXR_COMPAT_API)
list(APPEND TINYUSDZ_SOURCES ${PROJECT_SOURCE_DIR}/src/pxr-compat.cc)
endif ()
set(TINYUSDZ_C_API_SOURCES
${PROJECT_SOURCE_DIR}/src/c-tinyusd.cc
)

View File

@@ -130,6 +130,7 @@ For Windows native build, we assume `ninja.exe` is installed on your system(You
* OpenSubdiv code is included in TinyUSDZ repo. If you want to use external OpenSubdiv repo, specity the path to OpenSubdiv using `osd_DIR` cmake environment variable.
* `TINYUSDZ_WITH_AUDIO` : Support loading audio(mp3 and wav).
* `TINYUSDZ_WITH_EXR` : Support loading EXR format HDR texture through TinyEXR.
* `TINYUSDZ_WITH_PXR_COMPAT_API` : Build with pxr compatible API.
#### clang-cl on Windows

View File

@@ -12,6 +12,7 @@
#include "matrix.h"
#include "trackball.h"
#define PAR_SHAPES_IMPLEMENTATION
#include "par_shapes.h" // For meshing
const float kPI = 3.141592f;
@@ -48,8 +49,10 @@ bool ConvertToRenderMesh(const tinyusdz::GeomSphere& sphere, DrawGeomMesh* dst)
// TODO: Animated radius
float radius = 1.0;
if (auto p = tinyusdz::primvar::as_basic<double>(&sphere.radius)) {
radius = (*p);
if (sphere.radius.IsTimeSampled()) {
// TODO
} else {
radius = sphere.radius.Get();
}
// scale by radius
@@ -57,47 +60,47 @@ bool ConvertToRenderMesh(const tinyusdz::GeomSphere& sphere, DrawGeomMesh* dst)
dst->vertices[i] = par_mesh->points[i] * radius;
}
std::vector<int> facevarying_indices;
std::vector<uint32_t> facevertex_indices;
std::vector<float> facevarying_normals;
std::vector<float> facevarying_texcoords;
// Make uv and normal facevarying
// ntriangles = slices * 2 + (stacks - 2) * slices * 2
for (size_t i = 0; i < par_mesh->ntriangles; i++) {
PAR_SHAPES_T vidx0 = triangles[3 * i + 0];
PAR_SHAPES_T vidx1 = triangles[3 * i + 1];
PAR_SHAPES_T vidx2 = triangles[3 * i + 2];
PAR_SHAPES_T vidx0 = par_mesh->triangles[3 * i + 0];
PAR_SHAPES_T vidx1 = par_mesh->triangles[3 * i + 1];
PAR_SHAPES_T vidx2 = par_mesh->triangles[3 * i + 2];
facevarying_indices.push_back(vidx0);
facevarying_indices.push_back(vidx1);
facevarying_indices.push_back(vidx2);
facevertex_indices.push_back(vidx0);
facevertex_indices.push_back(vidx1);
facevertex_indices.push_back(vidx2);
facevarying_normals.push_back(par_mesh->normals[3 * idx0 + 0]);
facevarying_normals.push_back(par_mesh->normals[3 * idx0 + 1]);
facevarying_normals.push_back(par_mesh->normals[3 * idx0 + 2]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx0 + 0]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx0 + 1]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx0 + 2]);
facevarying_normals.push_back(par_mesh->normals[3 * idx1 + 0]);
facevarying_normals.push_back(par_mesh->normals[3 * idx1 + 1]);
facevarying_normals.push_back(par_mesh->normals[3 * idx1 + 2]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx1 + 0]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx1 + 1]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx1 + 2]);
facevarying_normals.push_back(par_mesh->normals[3 * idx2 + 0]);
facevarying_normals.push_back(par_mesh->normals[3 * idx2 + 1]);
facevarying_normals.push_back(par_mesh->normals[3 * idx2 + 2]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx2 + 0]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx2 + 1]);
facevarying_normals.push_back(par_mesh->normals[3 * vidx2 + 2]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * idx0 + 0]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * idx0 + 1]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx0 + 0]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx0 + 1]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * idx1 + 0]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * idx1 + 1]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx1 + 0]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx1 + 1]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * idx2 + 0]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * idx2 + 1]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx2 + 0]);
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx2 + 1]);
}
par_shapes_free_mesh(par_mesh);
dst->facevarying_indices = facevarying_indices;
dst->facevertex_indices = facevertex_indices;
return true;
@@ -156,7 +159,7 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
if (f_count == 3) {
for (size_t f = 0; f < f_count; f++) {
dst->facevarying_indices.push_back(
dst->facevertex_indices.push_back(
mesh.faceVertexIndices[face_offset + f]);
if (facevarying_normals.size()) {
@@ -187,11 +190,11 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
size_t f1 = f + 1;
size_t f2 = f + 2;
dst->facevarying_indices.push_back(
dst->facevertex_indices.push_back(
mesh.faceVertexIndices[face_offset + f0]);
dst->facevarying_indices.push_back(
dst->facevertex_indices.push_back(
mesh.faceVertexIndices[face_offset + f1]);
dst->facevarying_indices.push_back(
dst->facevertex_indices.push_back(
mesh.faceVertexIndices[face_offset + f2]);
if (facevarying_normals.size()) {
@@ -308,7 +311,7 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
std::cout << "num points = " << dst->vertices.size() / 3 << "\n";
std::cout << "num triangulated faces = "
<< dst->facevarying_indices.size() / 3 << "\n";
<< dst->facevertex_indices.size() / 3 << "\n";
return true;
}
@@ -468,7 +471,7 @@ bool Render(const RenderScene& scene, const Camera& cam, AOV* output) {
// Intersector functor.
nanort::TriangleIntersector<> triangle_intersector(
mesh.vertices.data(), mesh.facevarying_indices.data(),
mesh.vertices.data(), mesh.facevertex_indices.data(),
sizeof(float) * 3);
nanort::TriangleIntersection<> isect; // stores isect info
@@ -483,9 +486,9 @@ bool Render(const RenderScene& scene, const Camera& cam, AOV* output) {
float3 v1;
float3 v2;
size_t vid0 = mesh.facevarying_indices[3 * isect.prim_id + 0];
size_t vid1 = mesh.facevarying_indices[3 * isect.prim_id + 1];
size_t vid2 = mesh.facevarying_indices[3 * isect.prim_id + 2];
size_t vid0 = mesh.facevertex_indices[3 * isect.prim_id + 0];
size_t vid1 = mesh.facevertex_indices[3 * isect.prim_id + 1];
size_t vid2 = mesh.facevertex_indices[3 * isect.prim_id + 2];
v0[0] = mesh.vertices[3 * vid0 + 0];
v0[1] = mesh.vertices[3 * vid0 + 1];
@@ -633,7 +636,7 @@ bool RenderLines(int start_y, int end_y, const RenderScene& scene,
// Intersector functor.
nanort::TriangleIntersector<> triangle_intersector(
mesh.vertices.data(), mesh.facevarying_indices.data(),
mesh.vertices.data(), mesh.facevertex_indices.data(),
sizeof(float) * 3);
nanort::TriangleIntersection<> isect; // stores isect info
@@ -647,9 +650,9 @@ bool RenderLines(int start_y, int end_y, const RenderScene& scene,
float3 v1;
float3 v2;
size_t vid0 = mesh.facevarying_indices[3 * isect.prim_id + 0];
size_t vid1 = mesh.facevarying_indices[3 * isect.prim_id + 1];
size_t vid2 = mesh.facevarying_indices[3 * isect.prim_id + 2];
size_t vid0 = mesh.facevertex_indices[3 * isect.prim_id + 0];
size_t vid1 = mesh.facevertex_indices[3 * isect.prim_id + 1];
size_t vid2 = mesh.facevertex_indices[3 * isect.prim_id + 2];
v0[0] = mesh.vertices[3 * vid0 + 0];
v0[1] = mesh.vertices[3 * vid0 + 1];
@@ -779,13 +782,13 @@ bool RenderScene::Setup() {
DrawGeomMesh& draw_mesh = draw_meshes[i];
nanort::TriangleMesh<float> triangle_mesh(
draw_mesh.vertices.data(), draw_mesh.facevarying_indices.data(),
draw_mesh.vertices.data(), draw_mesh.facevertex_indices.data(),
sizeof(float) * 3);
nanort::TriangleSAHPred<float> triangle_pred(
draw_mesh.vertices.data(), draw_mesh.facevarying_indices.data(),
draw_mesh.vertices.data(), draw_mesh.facevertex_indices.data(),
sizeof(float) * 3);
bool ret = draw_mesh.accel.Build(draw_mesh.facevarying_indices.size() / 3,
bool ret = draw_mesh.accel.Build(draw_mesh.facevertex_indices.size() / 3,
triangle_mesh, triangle_pred);
if (!ret) {
std::cerr << "Failed to build BVH\n";

View File

@@ -10,6 +10,7 @@
#include <cmath>
#include <map>
#include <limits>
#include <memory>
#include <iostream>
@@ -21,6 +22,10 @@
#include "nonstd/optional.hpp"
#include "nonstd/variant.hpp"
#define any_CONFIG_NO_EXCEPTIONS (1)
#include "nonstd/any.hpp"
#include "nonstd/string_view.hpp"
using namespace nonstd::literals; // _sv
@@ -269,8 +274,6 @@ class Path {
}
}
bool IsValid() const { return valid; }
private:
std::string prim_part; // full path
std::string prop_part; // full path
@@ -689,6 +692,7 @@ struct GetDim<std::vector<T>> {
};
#endif
#if 0
template <class T>
class PrimValue {
private:
@@ -786,6 +790,7 @@ class PrimValue<std::vector<std::vector<std::vector<T>>>> {
};
// TODO: Privide generic multidimensional array type?
#endif
//
// TimeSample datatype
@@ -1607,6 +1612,7 @@ struct GPrim {
std::map<std::string, Property> props;
bool _valid{true}; // default behavior is valid(allow empty GPrim)
// child nodes
std::vector<GPrim> children;
@@ -2501,4 +2507,9 @@ class Value {
};
#endif
struct Value {
nonstd::any value;
};
} // namespace tinyusdz

29
src/pxr-compat.cc Normal file
View File

@@ -0,0 +1,29 @@
#include "pxr-compat.hh"
#include "tinyusdz.hh"
namespace pxr {
UsdStageRefPtr UsdStage::Open(const std::string &filepath, InitialLoadSet loadset) {
(void)filepath;
(void)loadset;
// TODO:
return std::shared_ptr<UsdStage>(nullptr);
};
UsdStageRefPtr UsdStage::CreateNew(const std::string &filepath, InitialLoadSet loadset) {
(void)filepath;
(void)loadset;
// TODO:
return std::shared_ptr<UsdStage>(nullptr);
};
UsdPrim UsdStage::GetPrimAtPath(const SdfPath &path) {
(void)path;
return UsdPrim();
};
} // namespace pxr

120
src/pxr-compat.hh Normal file
View File

@@ -0,0 +1,120 @@
// SPDX-License-Identifier: Apache 2.0
//
// Experimental pxr USD compatible API
//
#pragma once
#include <memory>
#include <string>
#include "prim-types.hh"
#if defined(PXR_STATIC)
#define USD_API
#else
#if defined(USD_EXRPORTS)
#if defined(_WIN32)
#if defined(_MSC_VER)
#define USD_API __declspec(dllexport)
#else
// assume gcc or clang
#define USD_API __attribute__((dllexport))
#endif
#else
#define USD_API
#endif
#else // import
#if defined(_WIN32)
#if defined(_MSC_VER)
#define USD_API __declspec(dllimport)
#else
// assume gcc or clang
#define USD_API __attribute__((dllimport))
#endif
#else
#define USD_API
#endif
#endif
#endif
#define PXR_INTERNAL_NS pxr
namespace pxr {
//namespace Sdf {
struct SdfLayer;
// pxr USD uses special pointer class(shared_ptr + alpha) for Handle, but we simply use shared_ptr.
using SdfLayerHandle = std::shared_ptr<SdfLayer>;
//} // namespae Sdf
//namespace Usd {
struct UsdStage;
using UsdStagePtr = std::weak_ptr<UsdStage>;
using UsdStageRefPtr = std::shared_ptr<UsdStage>;
typedef UsdStagePtr UsdStageWeakPtr;
// prim could be invalid(empty)
struct UsdPrim
{
UsdPrim() : _prim(nullptr) {}
UsdPrim(tinyusdz::GPrim *prim) : _prim(prim) {}
bool IsValid() const {
if (!_prim) {
return false;
}
// TODO: if (IsConcrete(_type))
return true;
}
explicit operator bool() {
return IsValid();
}
tinyusdz::GPrim *_prim{nullptr};
};
struct SdfPath
{
std::string path;
};
struct UsdStage
{
enum InitialLoadSet
{
LoadAll,
LoadNone
};
USD_API static UsdStageRefPtr CreateNew(const std::string &filepath, InitialLoadSet = LoadAll);
USD_API static UsdStageRefPtr CreateInMemory(InitialLoadSet = LoadAll);
USD_API static UsdStageRefPtr Open(const std::string &filepath, InitialLoadSet = LoadAll);
USD_API void Save();
USD_API void SaveSessionLayers();
USD_API bool Export(const std::string &filename, bool addSourceFileComments=true) const;
USD_API bool ExportToString(std::string *result, bool addSourceFileComments=true) const;
// returns invalid(empty) prim if corresponding path does not exit in the stage.
USD_API UsdPrim GetPrimAtPath(const SdfPath &path);
};
//} // namespace Usd;
} // namespace pxr

View File

@@ -1,9 +1,18 @@
set(TEST_TARGET_NAME unit-test-tinyusdz)
add_executable(${TEST_TARGET_NAME}
set(TEST_SOURCES
unit-main.cc
unit-prim-types.cc
)
if (TINYUSDZ_WITH_PXR_COMPAT_API)
list(APPEND TEST_SOURCES unit-pxr-compat-api.cc)
endif ()
add_executable(${TEST_TARGET_NAME}
${TEST_SOURCES}
)
add_sanitizers(${TEST_TARGET_NAME})
if (WIN32)
@@ -19,3 +28,8 @@ target_include_directories(${TEST_TARGET_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/src
set_target_properties(${TEST_TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
if (TINYUSDZ_WITH_PXR_COMPAT_API)
target_compile_definitions(${TEST_TARGET_NAME} PRIVATE "TINYUSDZ_WITH_PXR_COMPAT_API")
endif (TINYUSDZ_WITH_OPENSUBDIV)

View File

@@ -2,7 +2,16 @@
#include "unit-prim-types.h"
#if defined(TINYUSDZ_WITH_PXR_COMPAT_API)
#include "unit-pxr-compat-api.h"
#endif
TEST_LIST = {
{ "prim_type_test", prim_type_test },
#if defined(TINYUSDZ_WITH_PXR_COMPAT_API)
{ "pxr_compat_api_test", pxr_compat_api_test },
#endif
{ nullptr, nullptr }
};

View File

@@ -7,6 +7,7 @@
using namespace tinyusdz;
void prim_type_test(void) {
#if 0
{
PrimValue<float> pf;
TEST_CHECK(pf.array_dim() == 0);
@@ -30,5 +31,6 @@ void prim_type_test(void) {
TEST_CHECK(v.array_dim() == 3);
TEST_CHECK(v.type_name() == "float[][][]");
}
#endif
}

View File

@@ -0,0 +1,19 @@
#define TEST_NO_MAIN
#include "acutest.h"
#include "unit-pxr-compat-api.h"
#include "pxr-compat.hh"
using namespace PXR_INTERNAL_NS;
void pxr_compat_api_test(void) {
{
auto ref = UsdStage::CreateNew("creat.usda");
}
{
auto ref = UsdStage::Open("input.usda");
}
}

View File

@@ -0,0 +1,3 @@
#pragma once
void pxr_compat_api_test(void);