assimp/contrib/tinyusdz/tinyusdz_repo/examples/tydra_api/tydra-api-main.cc

424 lines
14 KiB
C++

#include <algorithm>
#include <iostream>
#include <sstream>
#include "tinyusdz.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"
static std::string GetFileExtension(const std::string &filename) {
if (filename.find_last_of('.') != std::string::npos)
return filename.substr(filename.find_last_of('.') + 1);
return "";
}
static std::string str_tolower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
// static_cast<int(*)(int)>(std::tolower) // wrong
// [](int c){ return std::tolower(c); } // wrong
// [](char c){ return std::tolower(c); } // wrong
[](unsigned char c) { return std::tolower(c); } // correct
);
return s;
}
// key = Full absolute prim path(e.g. `/bora/dora`)
using XformMap = std::map<std::string, const tinyusdz::Xform *>;
using MeshMap = std::map<std::string, const tinyusdz::GeomMesh *>;
using MaterialMap = std::map<std::string, const tinyusdz::Material *>;
using PreviewSurfaceMap =
std::map<std::string, std::pair<const tinyusdz::Shader *, const tinyusdz::UsdPreviewSurface *>>;
using UVTextureMap = std::map<std::string, std::pair<const tinyusdz::Shader *, const tinyusdz::UsdUVTexture *>>;
using PrimvarReader_float2Map =
std::map<std::string, std::pair<const tinyusdz::Shader *, const tinyusdz::UsdPrimvarReader_float2 *>>;
#if 0
template <typename T>
static bool TraverseRec(const std::string &path_prefix,
const tinyusdz::Prim &prim, uint32_t depth,
std::map<std::string, const T *> &itemmap) {
if (depth > 1024 * 128) {
// Too deep
return false;
}
std::string prim_abs_path = path_prefix + "/" + prim.local_path().full_path_name();
if (prim.is<tinyusdz::Material>()) {
if (const T *pv = prim.as<T>()) {
std::cout << "Path : <" << prim_abs_path << "> is "
<< tinyusdz::value::TypeTraits<T>::type_name() << ".\n";
itemmap[prim_abs_path] = pv;
}
}
for (const auto &child : prim.children()) {
if (!TraverseRec(prim_abs_path, child, depth + 1, itemmap)) {
return false;
}
}
return true;
}
template <typename T>
static bool TraverseShaderRec(const std::string &path_prefix,
const tinyusdz::Prim &prim, uint32_t depth,
std::map<std::string, const T *> &itemmap) {
if (depth > 1024 * 128) {
// Too deep
return false;
}
std::string prim_abs_path = path_prefix + "/" + prim.local_path().full_path_name();
// First test if Shader prim.
if (const tinyusdz::Shader *ps = prim.as<tinyusdz::Shader>()) {
// Concrete Shader object(e.g. UsdUVTexture) is stored in .data.
if (const T *s = ps->value.as<T>()) {
std::cout << "Path : <" << prim_abs_path << "> is "
<< tinyusdz::value::TypeTraits<T>::type_name() << ".\n";
itemmap[prim_abs_path] = s;
}
}
for (const auto &child : prim.children()) {
if (!TraverseShaderRec(prim_abs_path, child, depth + 1, itemmap)) {
return false;
}
}
return true;
}
static void TraverseMaterial(const tinyusdz::Stage &stage, MaterialMap &m) {
for (const auto &prim : stage.GetRootPrims()) {
TraverseRec(/* root */ "", prim, 0, m);
}
}
static void TraversePreviewSurface(const tinyusdz::Stage &stage,
PreviewSurfaceMap &m) {
for (const auto &prim : stage.GetRootPrims()) {
TraverseShaderRec(/* root */ "", prim, 0, m);
}
}
static void TraverseUVTexture(const tinyusdz::Stage &stage, UVTextureMap &m) {
for (const auto &prim : stage.GetRootPrims()) {
TraverseShaderRec(/* root */ "", prim, 0, m);
}
}
static void TraversePrimvarReader_float2(const tinyusdz::Stage &stage,
PrimvarReader_float2Map &m) {
for (const auto &prim : stage.GetRootPrims()) {
TraverseShaderRec(/* root */ "", prim, 0, m);
}
}
#endif
int main(int argc, char **argv) {
if (argc < 2) {
std::cout << "Need USD file with Material/Shader(e.g. `<tinyusdz>/models/texturescube.usda`\n" << std::endl;
return EXIT_FAILURE;
}
std::string filepath = argv[1];
std::string warn;
std::string err;
std::string ext = str_tolower(GetFileExtension(filepath));
tinyusdz::Stage stage;
if (ext.compare("usdc") == 0) {
bool ret = tinyusdz::LoadUSDCFromFile(filepath, &stage, &warn, &err);
if (!warn.empty()) {
std::cerr << "WARN : " << warn << "\n";
}
if (!err.empty()) {
std::cerr << "ERR : " << err << "\n";
// return EXIT_FAILURE;
}
if (!ret) {
std::cerr << "Failed to load USDC file: " << filepath << "\n";
return EXIT_FAILURE;
}
} else if (ext.compare("usda") == 0) {
bool ret = tinyusdz::LoadUSDAFromFile(filepath, &stage, &warn, &err);
if (!warn.empty()) {
std::cerr << "WARN : " << warn << "\n";
}
if (!err.empty()) {
std::cerr << "ERR : " << err << "\n";
// return EXIT_FAILURE;
}
if (!ret) {
std::cerr << "Failed to load USDA file: " << filepath << "\n";
return EXIT_FAILURE;
}
} else if (ext.compare("usdz") == 0) {
// std::cout << "usdz\n";
bool ret = tinyusdz::LoadUSDZFromFile(filepath, &stage, &warn, &err);
if (!warn.empty()) {
std::cerr << "WARN : " << warn << "\n";
}
if (!err.empty()) {
std::cerr << "ERR : " << err << "\n";
// return EXIT_FAILURE;
}
if (!ret) {
std::cerr << "Failed to load USDZ file: " << filepath << "\n";
return EXIT_FAILURE;
}
} else {
// try to auto detect format.
bool ret = tinyusdz::LoadUSDFromFile(filepath, &stage, &warn, &err);
if (!warn.empty()) {
std::cerr << "WARN : " << warn << "\n";
}
if (!err.empty()) {
std::cerr << "ERR : " << err << "\n";
// return EXIT_FAILURE;
}
if (!ret) {
std::cerr << "Failed to load USD file: " << filepath << "\n";
return EXIT_FAILURE;
}
}
std::string s = stage.ExportToString();
std::cout << s << "\n";
std::cout << "--------------------------------------"
<< "\n";
// Visit all Prims in the Stage.
auto prim_visit_fun = [](const tinyusdz::Path &abs_path, const tinyusdz::Prim &prim, const int32_t level, void *userdata, std::string *err) -> bool {
(void)err;
std::cout << tinyusdz::pprint::Indent(level) << "[" << level << "] (" << prim.data().type_name() << ") " << prim.local_path().prim_part() << " : AbsPath " << tinyusdz::to_string(abs_path) << "\n";
// Use as() or is() for Prim specific processing.
if (const tinyusdz::Material *pm = prim.as<tinyusdz::Material>()) {
(void)pm;
std::cout << tinyusdz::pprint::Indent(level) << " Got Material!\n";
// return false + `err` empty if you want to terminate traversal earlier.
//return false;
}
return true;
};
void *userdata = nullptr;
tinyusdz::tydra::VisitPrims(stage, prim_visit_fun, userdata);
std::cout << "--------------------------------------"
<< "\n";
// Compute Xform of each Prim at time t.
{
tinyusdz::tydra::XformNode xformnode;
double t = tinyusdz::value::TimeCode::Default();
tinyusdz::value::TimeSampleInterpolationType tinterp = tinyusdz::value::TimeSampleInterpolationType::Held; // Held or Linear
if (!tinyusdz::tydra::BuildXformNodeFromStage(stage, &xformnode, t, tinterp)) {
std::cerr << "BuildXformNodeFromStage error.\n";
} else {
std::cout << tinyusdz::tydra::DumpXformNode(xformnode) << "\n";
}
}
// Mapping hold the pointer to concrete Prim object,
// So stage content should not be changed(no Prim addition/deletion).
XformMap xformmap;
MeshMap meshmap;
MaterialMap matmap;
PreviewSurfaceMap surfacemap;
UVTextureMap texmap;
PrimvarReader_float2Map preadermap;
// Collect and make full path <-> Prim/Shader mapping
tinyusdz::tydra::ListPrims(stage, xformmap);
tinyusdz::tydra::ListPrims(stage, meshmap);
tinyusdz::tydra::ListPrims(stage, matmap);
tinyusdz::tydra::ListShaders(stage, surfacemap);
tinyusdz::tydra::ListShaders(stage, texmap);
tinyusdz::tydra::ListShaders(stage, preadermap);
//
// Query example
//
for (const auto &item : matmap) {
nonstd::expected<const tinyusdz::Prim*, std::string> mat = stage.GetPrimAtPath(tinyusdz::Path(item.first, /* prop name */""));
if (mat) {
std::cout << "Found Material <" << item.first << "> from Stage:\n";
if (const tinyusdz::Material *mp = mat.value()->as<tinyusdz::Material>()) { // this should be true though.
std::cout << tinyusdz::to_string(*mp) << "\n";
}
} else {
std::cerr << "Err: " << mat.error() << "\n";
}
}
for (const auto &item : surfacemap) {
// Returned Prim is Shader class
nonstd::expected<const tinyusdz::Prim*, std::string> shader = stage.GetPrimAtPath(tinyusdz::Path(item.first, /* prop name */""));
if (shader) {
std::cout << "Found Shader(UsdPreviewSurface) <" << item.first << "> from Stage:\n";
const tinyusdz::Shader *sp = shader.value()->as<tinyusdz::Shader>();
if (sp) { // this should be true though.
if (const tinyusdz::UsdPreviewSurface *surf = sp->value.as<tinyusdz::UsdPreviewSurface>()) {
// Print Shader
std::cout << tinyusdz::to_string(*sp) << "\n";
}
}
} else {
std::cerr << "Err: " << shader.error() << "\n";
}
}
for (const auto &item : texmap) {
// Returned Prim is Shader class
nonstd::expected<const tinyusdz::Prim*, std::string> shader = stage.GetPrimAtPath(tinyusdz::Path(item.first, /* prop name */""));
if (shader) {
std::cout << "Found Shader(UsdUVTexture) <" << item.first << "> from Stage:\n";
const tinyusdz::Shader *sp = shader.value()->as<tinyusdz::Shader>();
if (sp) { // this should be true though.
if (const tinyusdz::UsdUVTexture *tex = sp->value.as<tinyusdz::UsdUVTexture>()) {
std::cout << tinyusdz::to_string(*sp);
}
}
} else {
std::cerr << "Err: " << shader.error() << "\n";
}
}
for (const auto &item : preadermap) {
// Returned Prim is Shader class
nonstd::expected<const tinyusdz::Prim*, std::string> shader = stage.GetPrimAtPath(tinyusdz::Path(item.first, /* prop name */""));
if (shader) {
std::cout << "Found Shader(UsdPrimvarReader_float2) <" << item.first << "> from Stage:\n";
const tinyusdz::Shader *sp = shader.value()->as<tinyusdz::Shader>();
if (sp) { // this should be true though.
if (const tinyusdz::UsdPrimvarReader_float2 *preader = sp->value.as<tinyusdz::UsdPrimvarReader_float2>()) {
std::cout << tinyusdz::to_string(*sp) << "\n";
}
}
} else {
std::cerr << "Err: " << shader.error() << "\n";
}
}
//
// -- Querying Parent Prim
//
for (const auto &item : surfacemap) {
// Usually Parent is Material
std::string err;
if (const tinyusdz::Prim *p = tinyusdz::tydra::GetParentPrim(stage, tinyusdz::Path(item.first, /* property */""), &err)) {
std::cout << "Input path = " << tinyusdz::to_string(item.first) << "\n";
std::cout << "Parent prim = " << tinyusdz::prim::print_prim(*p) << "\n";
} else {
std::cerr << err;
}
}
std::cout << "GetProperty example -------------\n";
for (const auto &item : xformmap) {
std::string err;
tinyusdz::Property prop;
if (tinyusdz::tydra::GetProperty(*item.second, "xformOp:transform", &prop, &err)) {
std::cout << "Property value = " << print_prop(prop, "xformOp:transform", 0) << "\n";
} else {
std::cerr << err;
}
}
//
// Find bound Material
//
std::cout << "FindBoundMaterial example -------------\n";
for (const auto &item : meshmap) {
// FindBoundMaterial seaches bound material for parent GPrim.
tinyusdz::Path matPath;
const tinyusdz::Material *material{nullptr};
std::string err;
bool ret = tinyusdz::tydra::FindBoundMaterial(stage, tinyusdz::Path(item.first, ""), /* suffix */"", &matPath, &material, &err);
if (ret) {
std::cout << item.first << " has bound Material. Material Path = " << matPath << "\n";
std::cout << "mat = " << material << "\n";
if (material) {
std::cout << to_string(*material, /* indent */1) << "\n";
}
} else {
std::cout << "Bound material not found for Prim path : " << item.first << "\n";
}
}
//
// Shader attribute evaluation example.
//
std::cout << "EvaluateAttribute example -------------\n";
for (const auto &item : preadermap) {
// Returned Prim is Shader class
nonstd::expected<const tinyusdz::Prim*, std::string> shader = stage.GetPrimAtPath(tinyusdz::Path(item.first, /* prop name */""));
if (shader) {
std::cout << "Shader(UsdPrimvarReader_float2) <" << item.first << "> from Stage:\n";
const tinyusdz::Shader *sp = shader.value()->as<tinyusdz::Shader>();
if (sp) { // this should be true though.
if (const tinyusdz::UsdPrimvarReader_float2 *preader = sp->value.as<tinyusdz::UsdPrimvarReader_float2>()) {
tinyusdz::tydra::TerminalAttributeValue tav;
std::string err;
bool ret = tinyusdz::tydra::EvaluateAttribute(stage, *shader.value(), "inputs:varname", &tav, &err);
if (!ret) {
std::cout << "Resolving `inputs:varname` failed: " << err << "\n";
}
std::cout << "type = " << tav.type_name() << "\n";
if (auto pv = tav.as<tinyusdz::value::token>()) {
std::cout << "inputs:varname = " << (*pv) << "\n";
}
}
}
} else {
std::cerr << "Err: " << shader.error() << "\n";
}
}
return 0;
}