#include #include #include #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(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; using MeshMap = std::map; using MaterialMap = std::map; using PreviewSurfaceMap = std::map>; using UVTextureMap = std::map>; using PrimvarReader_float2Map = std::map>; #if 0 template static bool TraverseRec(const std::string &path_prefix, const tinyusdz::Prim &prim, uint32_t depth, std::map &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()) { if (const T *pv = prim.as()) { std::cout << "Path : <" << prim_abs_path << "> is " << tinyusdz::value::TypeTraits::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 static bool TraverseShaderRec(const std::string &path_prefix, const tinyusdz::Prim &prim, uint32_t depth, std::map &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()) { // Concrete Shader object(e.g. UsdUVTexture) is stored in .data. if (const T *s = ps->value.as()) { std::cout << "Path : <" << prim_abs_path << "> is " << tinyusdz::value::TypeTraits::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. `/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()) { (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 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()) { // 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 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(); if (sp) { // this should be true though. if (const tinyusdz::UsdPreviewSurface *surf = sp->value.as()) { // 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 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(); if (sp) { // this should be true though. if (const tinyusdz::UsdUVTexture *tex = sp->value.as()) { 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 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(); if (sp) { // this should be true though. if (const tinyusdz::UsdPrimvarReader_float2 *preader = sp->value.as()) { 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 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(); if (sp) { // this should be true though. if (const tinyusdz::UsdPrimvarReader_float2 *preader = sp->value.as()) { 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()) { std::cout << "inputs:varname = " << (*pv) << "\n"; } } } } else { std::cerr << "Err: " << shader.error() << "\n"; } } return 0; }