720 lines
22 KiB
C++
720 lines
22 KiB
C++
// All-in-one TinyUSDZ core
|
|
#include "tinyusdz.hh"
|
|
|
|
// Import to_string() and operator<< features
|
|
#include <iostream>
|
|
|
|
#include "pprinter.hh"
|
|
#include "prim-pprint.hh"
|
|
#include "value-pprint.hh"
|
|
|
|
// Tydra is a collection of APIs to access/convert USD Prim data
|
|
// (e.g. Can get Attribute by name)
|
|
// See <tinyusdz>/examples/tydra_api for more Tydra API examples.
|
|
#include "tydra/scene-access.hh"
|
|
|
|
//
|
|
// create a Scene
|
|
//
|
|
void CreateScene(tinyusdz::Stage *stage) {
|
|
// TinyUSDZ API does not use mutex, smart pointers(e.g. shared_ptr) and C++
|
|
// exception. Also threading is opional in TinyUSDZ and currently
|
|
// multi-threading is not used. `value::token` implementation is simply copy
|
|
// string for each instances(like C++11 ABI std::string). (on the contrary,
|
|
// pxrUSD's token implementation uses string-to-id, which requires mutex lock
|
|
// to make stringId unique. But we think this is inefficient on modern
|
|
// multi-core CPU, since they locks the mutex every `token` value
|
|
// instanciation)
|
|
//
|
|
// TinyUSDZ's API is not fully multi-thread safe, thus if you want to
|
|
// manipulate a scene(Stage) in multi-threaded context, The app must take care
|
|
// of resource locks in the app layer.
|
|
|
|
std::string err;
|
|
|
|
//
|
|
// Create simple material with UsdPrevieSurface.
|
|
//
|
|
tinyusdz::Material mat;
|
|
mat.name = "mat";
|
|
|
|
tinyusdz::Shader shader; // Shader container
|
|
shader.name = "defaultPBR";
|
|
{
|
|
tinyusdz::UsdPreviewSurface surfaceShader; // Concrete Shader node object
|
|
|
|
//
|
|
// Asssign actual shader object to Shader::value.
|
|
// Also do not forget set its shader node type name through Shader::info_id
|
|
//
|
|
shader.info_id = tinyusdz::kUsdPreviewSurface; // "UsdPreviewSurface" token
|
|
|
|
//
|
|
// Currently no shader network/connection API.
|
|
// Manually construct it.
|
|
//
|
|
surfaceShader.outputsSurface.set_authored(
|
|
true); // Author `token outputs:surface`
|
|
|
|
surfaceShader.metallic = 0.3f;
|
|
// TODO: UsdUVTexture, UsdPrimvarReader***, UsdTransform2d
|
|
|
|
// Connect to UsdPreviewSurface's outputs:surface by setting targetPath.
|
|
//
|
|
// token outputs:surface = </mat/defaultPBR.outputs:surface>
|
|
mat.surface.set(tinyusdz::Path(/* prim path */ "/mat/defaultPBR",
|
|
/* prop path */ "outputs:surface"));
|
|
|
|
//
|
|
// Shaer::value is `value::Value` type, so can use '=' to assign Shader
|
|
// object.
|
|
//
|
|
shader.value = std::move(surfaceShader);
|
|
}
|
|
|
|
tinyusdz::Prim shaderPrim(shader);
|
|
tinyusdz::Prim matPrim(mat);
|
|
|
|
// matPrim.children().emplace_back(std::move(shaderPrim)); // no uniqueness
|
|
// check
|
|
|
|
// Use add_child() to ensure child Prim has unique name.
|
|
if (!matPrim.add_child(std::move(shaderPrim),
|
|
/* rename Prim name if_required */ true, &err)) {
|
|
std::cerr << "Failed to constrcut Scene: " << err << "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
//
|
|
// To construct Prim, first create concrete Prim object(e.g. Xform, GeomMesh),
|
|
// then add it to tinyusdz::Prim.
|
|
//
|
|
//
|
|
tinyusdz::Xform xform;
|
|
{
|
|
xform.name = "root"; // Prim's name(elementPath)
|
|
|
|
{
|
|
tinyusdz::XformOp op;
|
|
op.op_type = tinyusdz::XformOp::OpType::Transform;
|
|
tinyusdz::value::matrix4d a0;
|
|
tinyusdz::value::matrix4d b0;
|
|
|
|
tinyusdz::Identity(&a0);
|
|
tinyusdz::Identity(&b0);
|
|
|
|
a0.m[1][1] = 2.1;
|
|
|
|
// column major, so [3][0], [3][1], [3][2] = translate X, Y, Z
|
|
b0.m[3][0] = 1.0;
|
|
b0.m[3][1] = 3.1;
|
|
b0.m[3][2] = 5.1;
|
|
|
|
tinyusdz::value::matrix4d transform = a0 * b0;
|
|
|
|
op.set_value(transform);
|
|
|
|
// `xformOpOrder`(token[]) is represented as std::vector<XformOp>
|
|
xform.xformOps.push_back(op);
|
|
}
|
|
|
|
{
|
|
// `xformOp:***` attribute is represented as XformOp class
|
|
tinyusdz::XformOp op;
|
|
op.op_type = tinyusdz::XformOp::OpType::Translate;
|
|
tinyusdz::value::double3 translate;
|
|
translate[0] = 1.0;
|
|
translate[1] = 2.0;
|
|
translate[2] = 3.0;
|
|
op.set_value(translate);
|
|
|
|
// `xformOpOrder`(token[]) is represented as std::vector<XformOp>
|
|
xform.xformOps.push_back(op);
|
|
}
|
|
|
|
{
|
|
// .suffix will be prepended to `xformOp:translate`
|
|
// 'xformOp:translate:move'
|
|
tinyusdz::XformOp op;
|
|
op.op_type = tinyusdz::XformOp::OpType::Translate;
|
|
op.suffix = "move";
|
|
tinyusdz::value::double3 translate;
|
|
|
|
// TimeSamples value can be added with `set_timesample`
|
|
// NOTE: TimeSamples data will be automatically sorted by time when using
|
|
// it.
|
|
translate[0] = 0.0;
|
|
translate[1] = 0.0;
|
|
translate[2] = 0.0;
|
|
op.set_timesample(0.0, translate);
|
|
|
|
translate[0] = 1.0;
|
|
translate[1] = 0.1;
|
|
translate[2] = 0.3;
|
|
op.set_timesample(1.0, translate);
|
|
|
|
xform.xformOps.push_back(op);
|
|
}
|
|
}
|
|
|
|
tinyusdz::GeomMesh mesh;
|
|
{
|
|
mesh.name = "quad";
|
|
|
|
{
|
|
std::vector<tinyusdz::value::point3f> pts;
|
|
pts.push_back({0.0f, 0.0f, 0.0f});
|
|
pts.push_back({1.0f, 0.0f, 0.0f});
|
|
pts.push_back({1.0f, 1.0f, 0.0f});
|
|
pts.push_back({0.0f, 1.0f, 0.0f});
|
|
|
|
mesh.points.set_value(pts);
|
|
}
|
|
|
|
{
|
|
// quad plane composed of 2 triangles.
|
|
std::vector<int> indices;
|
|
std::vector<int> counts;
|
|
counts.push_back(3);
|
|
counts.push_back(3);
|
|
mesh.faceVertexCounts.set_value(counts);
|
|
|
|
indices.push_back(0);
|
|
indices.push_back(1);
|
|
indices.push_back(2);
|
|
|
|
indices.push_back(0);
|
|
indices.push_back(2);
|
|
indices.push_back(3);
|
|
|
|
mesh.faceVertexIndices.set_value(indices);
|
|
}
|
|
|
|
// primvar and custom attribute can be added to generic Property container
|
|
// `props`(map<std::string, Property>)
|
|
{
|
|
// primvar is simply an attribute with prefix `primvars:`
|
|
//
|
|
// texCoord2f[] primvars:uv = [ ... ] ( interpolation = "vertex" )
|
|
// int[] primvars:uv:indices = [ ... ]
|
|
//
|
|
{
|
|
tinyusdz::Attribute uvAttr;
|
|
std::vector<tinyusdz::value::texcoord2f> uvs;
|
|
|
|
uvs.push_back({0.0f, 0.0f});
|
|
uvs.push_back({1.0f, 0.0f});
|
|
uvs.push_back({1.0f, 1.0f});
|
|
uvs.push_back({0.0f, 1.0f});
|
|
|
|
// Fast path. Set the value directly to Attribute.
|
|
uvAttr.set_value(uvs);
|
|
|
|
// or we can first build primvar::PrimVar
|
|
// tinyusdz::primvar::PrimVar uvVar;
|
|
// uvVar.set_value(uvs);
|
|
// uvAttr.set_var(std::move(uvVar));
|
|
|
|
// Currently `interpolation` is described in Attribute metadataum.
|
|
// You can set builtin(predefined) Attribute Metadatum(e.g.
|
|
// `interpolation`, `hidden`) through `metas()`.
|
|
uvAttr.metas().interpolation = tinyusdz::Interpolation::Vertex;
|
|
|
|
tinyusdz::Property uvProp(uvAttr);
|
|
|
|
mesh.props.emplace("primvars:uv", uvProp);
|
|
|
|
// ----------------------
|
|
|
|
tinyusdz::Attribute uvIndexAttr;
|
|
std::vector<int> uvIndices;
|
|
|
|
// FIXME: Validate
|
|
uvIndices.push_back(0);
|
|
uvIndices.push_back(1);
|
|
uvIndices.push_back(3);
|
|
uvIndices.push_back(2);
|
|
|
|
tinyusdz::primvar::PrimVar uvIndexVar;
|
|
uvIndexVar.set_value(uvIndices);
|
|
uvIndexAttr.set_var(std::move(uvIndexVar));
|
|
// Or you can use this approach(if you want to keep a copy of PrimVar
|
|
// data)
|
|
// uvIndexAttr.set_var(uvIndexVar);
|
|
|
|
tinyusdz::Property uvIndexProp(uvIndexAttr);
|
|
mesh.props.emplace("primvars:uv:indices", uvIndexProp);
|
|
}
|
|
|
|
// `custom uniform double myvalue = 3.0 ( hidden = 0 )`
|
|
{
|
|
tinyusdz::Attribute attrib;
|
|
double myvalue = 3.0;
|
|
tinyusdz::primvar::PrimVar var;
|
|
var.set_value(myvalue);
|
|
attrib.set_var(std::move(var));
|
|
attrib.variability() = tinyusdz::Variability::Uniform;
|
|
|
|
attrib.metas().hidden = false;
|
|
|
|
// NOTE: `custom` keyword would be deprecated in the future USD syntax,
|
|
// so you can set it false.
|
|
tinyusdz::Property prop(attrib, /* custom*/ true);
|
|
|
|
mesh.props.emplace("myvalue", prop);
|
|
}
|
|
|
|
// Add Primvar through GeomPrimvar;
|
|
{
|
|
tinyusdz::GeomPrimvar uvPrimvar;
|
|
|
|
uvPrimvar.set_name("my_uv");
|
|
std::vector<tinyusdz::value::texcoord2f> uvs;
|
|
|
|
uvs.push_back({0.0f, 0.0f});
|
|
uvs.push_back({1.0f, 0.0f});
|
|
uvs.push_back({1.0f, 1.0f});
|
|
uvs.push_back({0.0f, 1.0f});
|
|
|
|
uvPrimvar.set_value(uvs);
|
|
uvPrimvar.set_interpolation(tinyusdz::Interpolation::Vertex);
|
|
|
|
std::vector<int> uvIndices;
|
|
uvIndices.push_back(0);
|
|
uvIndices.push_back(1);
|
|
uvIndices.push_back(3);
|
|
uvIndices.push_back(2);
|
|
|
|
uvPrimvar.set_indices(uvIndices);
|
|
|
|
// primvar name is extracted from Primvar::name
|
|
std::string err;
|
|
if (!mesh.set_primvar(uvPrimvar, &err)) {
|
|
std::cerr << "Failed to add Primar: " << err << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Material binding(`rel material:binding` is done by manually setup
|
|
// targetPath.
|
|
tinyusdz::Relationship materialBinding;
|
|
materialBinding.set(
|
|
tinyusdz::Path(/* prim path */ "/mat/defaultPBR", /* prop path */ ""));
|
|
|
|
mesh.materialBinding = materialBinding;
|
|
|
|
// TODO: Explicitly author MaterialBindingAPI apiSchema in Mesh Prim.
|
|
}
|
|
|
|
tinyusdz::GeomSphere sphere1;
|
|
{
|
|
sphere1.name = "sphere";
|
|
|
|
sphere1.radius = 3.14;
|
|
}
|
|
|
|
tinyusdz::GeomSphere sphere2;
|
|
{
|
|
sphere2.name =
|
|
"sphere"; // name will be modified to be unique at add_child().
|
|
sphere2.radius = 1.05;
|
|
}
|
|
|
|
//
|
|
// Create Scene(Stage) hierarchy.
|
|
// You can add child Prim to parent Prim's `children()`.
|
|
//
|
|
// [Xform]
|
|
// |
|
|
// +- [Mesh]
|
|
// +- [Sphere0]
|
|
// +- [Sphere1]
|
|
//
|
|
// [Material]
|
|
// |
|
|
// +- [Shader]
|
|
//
|
|
|
|
// Prim's elementName is read from concrete Prim class(GeomMesh::name,
|
|
// Xform::name, ...)
|
|
tinyusdz::Prim meshPrim(mesh);
|
|
{
|
|
// `references`, `paylaod`
|
|
|
|
{
|
|
tinyusdz::Reference ref;
|
|
ref.asset_path = tinyusdz::value::AssetPath("submesh-000.usd");
|
|
|
|
std::vector<tinyusdz::Reference> referencesList;
|
|
referencesList.push_back(ref);
|
|
|
|
meshPrim.metas().references =
|
|
std::make_pair(tinyusdz::ListEditQual::Append, referencesList);
|
|
}
|
|
|
|
{
|
|
tinyusdz::Payload pl;
|
|
pl.asset_path = tinyusdz::value::AssetPath("submesh-payload-000.usd");
|
|
|
|
std::vector<tinyusdz::Payload> payloadList;
|
|
payloadList.push_back(pl);
|
|
|
|
meshPrim.metas().payload =
|
|
std::make_pair(tinyusdz::ListEditQual::Append, payloadList);
|
|
}
|
|
}
|
|
|
|
tinyusdz::Prim spherePrim(sphere1);
|
|
{
|
|
// variantSet is maniuplated in Prim.
|
|
// Currently we don't provide easy API for variantSet.
|
|
// Need to add variantSet information manually for a while.
|
|
tinyusdz::VariantSelectionMap vsmap;
|
|
|
|
// List of variantSet in the Prim.
|
|
std::vector<std::string> variantSetList;
|
|
variantSetList.push_back("colorVariant");
|
|
|
|
// key = variantSet name, value = default Variant selection
|
|
vsmap.emplace("colorVariant", "red");
|
|
|
|
spherePrim.metas().variants = vsmap;
|
|
spherePrim.metas().variantSets =
|
|
std::make_pair(tinyusdz::ListEditQual::Append, variantSetList);
|
|
|
|
// VariantSet is composed of metas + properties + childPrims
|
|
tinyusdz::VariantSet variantSet;
|
|
|
|
tinyusdz::Variant redVariant;
|
|
redVariant.metas().comment = "red color";
|
|
tinyusdz::value::color3f redColor({1.0f, 0.0f, 0.0f});
|
|
tinyusdz::Attribute redColorAttr;
|
|
redColorAttr.set_value(redColor);
|
|
redVariant.properties().emplace("mycolor", redColorAttr);
|
|
// TODO: Add example to add childPrims under Variant
|
|
// redVariant.primChildren().emplace(...)
|
|
|
|
tinyusdz::Variant greenVariant;
|
|
greenVariant.metas().comment = "green color";
|
|
tinyusdz::value::color3f greenColor({0.0f, 1.0f, 0.0f});
|
|
tinyusdz::Attribute greenColorAttr;
|
|
greenColorAttr.set_value(greenColor);
|
|
greenVariant.properties().emplace("mycolor", greenColorAttr);
|
|
|
|
variantSet.name = "red";
|
|
variantSet.variantSet.emplace("red", redVariant);
|
|
|
|
variantSet.name = "green";
|
|
variantSet.variantSet.emplace("green", greenVariant);
|
|
|
|
spherePrim.variantSets().emplace("colorVariant", variantSet);
|
|
}
|
|
|
|
tinyusdz::Prim spherePrim2(sphere2);
|
|
|
|
tinyusdz::Prim xformPrim(xform);
|
|
|
|
// xformPrim.children().emplace_back(std::move(meshPrim));
|
|
// xformPrim.children().emplace_back(std::move(spherePrim));
|
|
|
|
// Use add_child() to ensure child Prim has unique name.
|
|
if (!xformPrim.add_child(std::move(meshPrim),
|
|
/* rename Prim name if_required */ true, &err)) {
|
|
std::cerr << "Failed to constrcut Scene: " << err << "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
if (!xformPrim.add_child(std::move(spherePrim),
|
|
/* rename Prim name if_required */ true, &err)) {
|
|
std::cerr << "Failed to constrcut Scene: " << err << "\n";
|
|
}
|
|
|
|
#if 1
|
|
// Must set rename Prim arg `true`, otherwise `add_child` fails since
|
|
// spherePrim2 does not have valid & unique Prim name.
|
|
if (!xformPrim.add_child(std::move(spherePrim2),
|
|
/* rename Prim name if_required */ true, &err)) {
|
|
std::cerr << "Failed to constrcut Scene: " << err << "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
if (xformPrim.children().size() != 3) {
|
|
std::cerr << "Internal error. num child Prims must be 3, but got "
|
|
<< xformPrim.children().size() << "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
// If you want to specify the appearance/traversal order of child Prim(e.g.
|
|
// Showing Prim tree in GUI, Ascii output), set "primChildren"(token[])
|
|
// metadata xfromPrim.metas().primChildren.size() must be identical to
|
|
// xformPrim.children().size()
|
|
xformPrim.metas().primChildren.push_back(
|
|
tinyusdz::value::token(xformPrim.children()[1].element_name()));
|
|
xformPrim.metas().primChildren.push_back(
|
|
tinyusdz::value::token(xformPrim.children()[0].element_name()));
|
|
xformPrim.metas().primChildren.push_back(
|
|
tinyusdz::value::token(xformPrim.children()[2].element_name()));
|
|
#else
|
|
// You can replace(or add if corresponding Prim does not exist) existing child
|
|
// Prim using replace_child()
|
|
if (!xformPrim.replace_child("sphere", std::move(spherePrim2), &err)) {
|
|
std::cerr << "Failed to constrcut Scene: " << err << "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
if (xformPrim.children().size() != 2) {
|
|
std::cerr << "Internal error. num child Prims must be 2, but got "
|
|
<< xformPrim.children().size() << "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
#endif
|
|
|
|
///
|
|
/// Add subLayers
|
|
///
|
|
std::vector<tinyusdz::SubLayer> sublayers;
|
|
tinyusdz::SubLayer slayer0;
|
|
slayer0.assetPath = tinyusdz::value::AssetPath("sublayer-000.usd");
|
|
sublayers.push_back(slayer0);
|
|
stage->metas().subLayers = sublayers;
|
|
stage->metas().defaultPrim =
|
|
tinyusdz::value::token(xformPrim.element_name()); // token
|
|
|
|
if (!stage->add_root_prim(std::move(xformPrim))) {
|
|
std::cerr << "Failed to add Prim to Stage root: " << stage->get_error()
|
|
<< "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
if (!stage->add_root_prim(std::move(matPrim))) {
|
|
std::cerr << "Failed to add Prim to Stage root: " << stage->get_error()
|
|
<< "\n";
|
|
exit(-1);
|
|
}
|
|
|
|
// You can replace(or add if given Prim name does not exist in the Stage) root
|
|
// Prim using `replace_root_prim`.
|
|
#if 0
|
|
{
|
|
tinyusdz::Scope scope;
|
|
tinyusdz::Prim scopePrim(scope);
|
|
if (!stage->replace_root_prim(/* root Prim name */"root", std::move(scopePrim))) {
|
|
std::cerr << "Failed to replace Prim to Stage root: " << stage->get_error() << "\n";
|
|
exit(-1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// You can add Stage metadatum through Stage::metas()
|
|
stage->metas().comment = "Generated by TinyUSDZ api_tutorial.";
|
|
|
|
{
|
|
// Dictionary(alias to CustomDataType) is similar to VtDictionary.
|
|
// it is a map<string, MetaVariable>
|
|
// MetaVariable is similar to Value, but accepts limited variation of
|
|
// types(double, token, string, float3[], ...)
|
|
tinyusdz::Dictionary customData;
|
|
|
|
tinyusdz::MetaVariable metavar;
|
|
double mycustom = 1.3;
|
|
metavar.set_value("mycustom", mycustom);
|
|
|
|
std::string mystring = "hello";
|
|
tinyusdz::MetaVariable metavar2("mystring", mystring);
|
|
|
|
customData.emplace("mycustom", metavar);
|
|
customData.emplace("mystring", metavar2);
|
|
customData.emplace("myvalue", 2.45); // Construct MetaVariables implicitly
|
|
|
|
// You can also use SetCustomDataByKey to set custom value with key having
|
|
// namespaces(':')
|
|
|
|
tinyusdz::MetaVariable intval = int(5);
|
|
tinyusdz::SetCustomDataByKey("mydict:myval", intval,
|
|
/* inout */ customData);
|
|
|
|
stage->metas().customLayerData = customData;
|
|
}
|
|
|
|
// Commit Stage.
|
|
// Internally, it calls Stage::compute_absolute_prim_path_and_assign_prim_id()
|
|
// to compute absolute Prim path and assign unique Prim id to each Prims in
|
|
// the Stage. NOTE: Stage::metas() is not affected by `commit` API, so you can
|
|
// call `commit` before manipulating StageMetas through `Stage::metas()`
|
|
if (!stage->commit()) {
|
|
std::cerr << "Failed to commit Stage. ERR: " << stage->get_error() << "\n";
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
tinyusdz::Stage stage; // empty scene
|
|
|
|
CreateScene(&stage);
|
|
|
|
if (stage.get_warning().size()) {
|
|
std::cout << "WARN in Stage: " << stage.get_warning() << "\n";
|
|
}
|
|
|
|
// Print USD scene as Ascii.
|
|
std::cout << to_string(stage) << "\n";
|
|
// std::cout << stage.ExportToString() << "\n"; // you can also use pxrUSD
|
|
// compatible ExportToString().
|
|
|
|
// Dump Prim tree info.
|
|
std::cout << stage.dump_prim_tree() << "\n";
|
|
|
|
{
|
|
tinyusdz::Path path(/* absolute prim path */ "/root",
|
|
/* property path */ "");
|
|
|
|
const tinyusdz::Prim *prim{nullptr};
|
|
std::string err;
|
|
bool ret = stage.find_prim_at_path(path, prim, &err);
|
|
if (ret) {
|
|
std::cout << "Found Prim at path: " << tinyusdz::to_string(path) << "\n";
|
|
std::cout << "Prim ID: " << prim->prim_id() << "\n";
|
|
std::cout << "Prim's absolute_path: "
|
|
<< tinyusdz::to_string(prim->absolute_path()) << "\n";
|
|
} else {
|
|
std::cerr << err << "\n";
|
|
}
|
|
|
|
if (!prim) {
|
|
// This should not be happen though.
|
|
std::cerr << "Prim is null\n";
|
|
return -1;
|
|
}
|
|
|
|
if (!prim->is<tinyusdz::Xform>()) {
|
|
std::cerr << "Expected Xform prim."
|
|
<< "\n";
|
|
return -1;
|
|
}
|
|
|
|
// Cast to Xform
|
|
const tinyusdz::Xform *xform = prim->as<tinyusdz::Xform>();
|
|
if (!xform) {
|
|
std::cerr << "Expected Xform prim."
|
|
<< "\n";
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// find Prim by prim_id
|
|
{
|
|
uint64_t prim_id = 2;
|
|
|
|
const tinyusdz::Prim *prim{nullptr};
|
|
std::string err;
|
|
bool ret = stage.find_prim_by_prim_id(prim_id, prim, &err);
|
|
if (ret && prim) {
|
|
std::cout << "Found Prim by ID: " << prim_id << "\n";
|
|
std::cout << "Prim's absolute_path: "
|
|
<< tinyusdz::to_string(prim->absolute_path()) << "\n";
|
|
} else {
|
|
std::cerr << err << "\n";
|
|
}
|
|
}
|
|
|
|
// GetAttribute and GeomPrimvar
|
|
{
|
|
tinyusdz::Path path(/* absolute prim path */ "/root/quad",
|
|
/* property path */ "");
|
|
|
|
const tinyusdz::Prim *prim{nullptr};
|
|
std::string err;
|
|
bool ret = stage.find_prim_at_path(path, prim, &err);
|
|
if (ret && prim) {
|
|
std::cout << "Found Prim at path: " << tinyusdz::to_string(path) << "\n";
|
|
std::cout << "Prim ID: " << prim->prim_id() << "\n";
|
|
std::cout << "Prim's absolute_path: "
|
|
<< tinyusdz::to_string(prim->absolute_path()) << "\n";
|
|
} else {
|
|
std::cerr << err << "\n";
|
|
}
|
|
|
|
if (!prim) {
|
|
// This should not be happen though.
|
|
std::cerr << "Prim is null\n";
|
|
return -1;
|
|
}
|
|
|
|
tinyusdz::Attribute attr;
|
|
if (tinyusdz::tydra::GetAttribute(*prim, "points", &attr, &err)) {
|
|
std::cout << "point attribute type = " << attr.type_name() << "\n";
|
|
|
|
// Ensure Attribute has a value(not Attribute connection)
|
|
if (attr.is_value()) {
|
|
std::vector<tinyusdz::value::point3f> pts;
|
|
if (attr.is_timesamples()) {
|
|
// TODO: timesamples
|
|
} else {
|
|
if (attr.get_value(&pts)) {
|
|
std::cout << "point attribute value = " << pts << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
std::cerr << err << "\n";
|
|
}
|
|
|
|
const tinyusdz::GeomMesh *mesh = prim->as<tinyusdz::GeomMesh>();
|
|
if (!mesh) {
|
|
std::cerr << "Expected GeomMesh.\n";
|
|
return -1;
|
|
}
|
|
|
|
// GeomPrimvar
|
|
// Access GeomPrimvar
|
|
{
|
|
std::cout << "uv is primvar? " << mesh->has_primvar("uv") << "\n";
|
|
tinyusdz::GeomPrimvar primvar;
|
|
std::string err;
|
|
if (mesh->get_primvar("uv", &primvar, &err)) {
|
|
std::cout << "uv primvar is Indexed Primvar? " << primvar.has_indices()
|
|
<< "\n";
|
|
} else {
|
|
std::cerr << "get_primvar(\"uv\") failed. err = " << err << "\n";
|
|
}
|
|
|
|
// Equivalent to pxr::UsdGeomPrimvar::ComputeFlattened().
|
|
// elems[i] = values[indices[i]]
|
|
tinyusdz::value::Value value;
|
|
if (primvar.flatten_with_indices(&value, &err)) {
|
|
// value;:Value can contain any types, but value.array_size() should
|
|
// work well only for primvar types(e.g. `float[]`, `color3f[]`) It
|
|
// would report 0 for non-primvar types(e.g.`std::vector<Xform>`)
|
|
std::cout << "uv primvars. array size = " << value.array_size() << "\n";
|
|
std::cout << "uv primvars. expand_by_indices result = "
|
|
<< tinyusdz::value::pprint_value(value) << "\n";
|
|
} else {
|
|
std::cerr << "expand_by_indices failed. err = " << err << "\n";
|
|
}
|
|
|
|
// Typed version
|
|
std::vector<tinyusdz::value::texcoord2f> uvs;
|
|
if (primvar.flatten_with_indices(&uvs, &err)) {
|
|
// value;:Value can contain any types, but value.array_size() should
|
|
// work well only for primvar types(e.g. `float[]`, `color3f[]`) It
|
|
// would report 0 for non-primvar types(e.g.`std::vector<Xform>`)
|
|
std::cout << "uv primvars. array size = " << uvs.size() << "\n";
|
|
std::cout << "uv primvars. expand_by_indices result = "
|
|
<< tinyusdz::value::pprint_value(uvs) << "\n";
|
|
} else {
|
|
std::cerr << "expand_by_indices failed. err = " << err << "\n";
|
|
}
|
|
|
|
std::vector<tinyusdz::GeomPrimvar> gpvars = mesh->get_primvars();
|
|
std::cout << "# of primvars = " << gpvars.size();
|
|
for (const auto &item : gpvars) {
|
|
std::cout << " primvar = " << item.name() << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|