USD Tutorials を C++ でやってみた。
だいたい Python だったから C++ でやってみた。
いろいろ調べながら頑張ってお勉強しようとするよりも、まずは何も考えず公式チュートリアルを読みながら写経するのがよさげ。あと C++ だと namespace とか型定義が Python と微妙に違うのと、include でファイルパス指定しなきゃいけないから、ソースコードは手許に用意して、VS Code でいいからインテリセンスと grep は必須。
- ビルド環境
- 参考資料
- プリコンパイル済みヘッダー(stdafx.h)
- Hello World - Creating Your First USD Stage
- Inspecting and Authoring Properties
- Referencing Layers
- Traversing a Stage
- Authoring Variants
- Transformations, Time-sampled Animation, and Layer Offsets
- Simple Shading in USD
ビルド環境
- Microsoft Visual Studio Community 2019, Version 16.5.4
- USD 20.05
- USD-20.05 の Windows ビルドメモ。 - graphics.hatenablog.com
参考資料
プリコンパイル済みヘッダー(stdafx.h)
#pragma once #define NOMINMAX #pragma warning(push) #pragma warning(disable: 4244 4267 4305 6011 6319 26439 26451 26495 26812) #include <pxr/usd/usd/stage.h> #include <pxr/usd/usd/primRange.h> #include <pxr/usd/usd/variantSets.h> #include <pxr/usd/usd/editContext.h> #include <pxr/usd/usd/modelApi.h> #include <pxr/usd/sdf/types.h> #include <pxr/usd/usdGeom/xform.h> #include <pxr/usd/usdGeom/mesh.h> #include <pxr/usd/usdGeom/sphere.h> #include <pxr/usd/usdGeom/xformCommonAPI.h> #include <pxr/usd/usdGeom/metrics.h> #include <pxr/usd/usdGeom/tokens.h> #include <pxr/usd/usdShade/material.h> #include <pxr/usd/usdShade/materialBindingAPI.h> #pragma warning(pop) #undef NOMINMAX #include <iostream> #include <string> #include <conio.h>
Hello World - Creating Your First USD Stage
#include "stdafx.h" using namespace PXR_INTERNAL_NS; int main(int args, char* argv[]) { auto pStage = UsdStage::CreateNew("HelloWorld.usda"); UsdGeomXform::Define(pStage, SdfPath("/hello")); UsdGeomSphere::Define(pStage, SdfPath("/hello/world")); pStage->GetRootLayer()->Save(); return 0; }
Inspecting and Authoring Properties
#include "stdafx.h" using namespace PXR_INTERNAL_NS; int main(int args, char* argv[]) { auto pStage = UsdStage::CreateNew("HelloWorld.usda"); UsdGeomXform::Define(pStage, SdfPath("/hello")); auto sphere = UsdGeomSphere::Define(pStage, SdfPath("/hello/world")); auto radius = sphere.GetRadiusAttr(); radius.Set(2.0); auto extent = sphere.GetExtentAttr(); extent.Set(VtArray<GfVec3f> { GfVec3f(-2.f, -2.f, -2.f), GfVec3f(2.f, 2.f, 2.f) }); auto color = sphere.GetDisplayColorAttr(); color.Set(VtArray<GfVec3f> { GfVec3f(0.f, 0.f, 1.f) }); pStage->GetRootLayer()->Save(); return 0; }
Referencing Layers
#include "stdafx.h" using namespace PXR_INTERNAL_NS; void PrintStage(const UsdStagePtr& pStage) { std::string str; pStage->ExportToString(&str); std::cout << str << std::endl; } int main(int args, char* argv[]) { auto pStage = UsdStage::Open("HelloWorld.usda"); auto hello = pStage->GetPrimAtPath(SdfPath("/hello")); pStage->SetDefaultPrim(hello); UsdGeomXformCommonAPI(hello).SetTranslate(GfVec3f(4.f, 5.f, 6.f)); pStage->GetRootLayer()->Save(); auto pRefStage = UsdStage::CreateNew("RefExample.usda"); auto refSphere = pRefStage->OverridePrim(SdfPath("/refSphere")); refSphere.GetReferences().AddReference("./HelloWorld.usda"); auto refXform = UsdGeomXformable(refSphere); refXform.SetXformOpOrder({}); auto refSphere2 = pRefStage->OverridePrim(SdfPath("/refSphere2")); refSphere2.GetReferences().AddReference("./HelloWorld.usda"); auto overSphere = UsdGeomSphere::Get(pRefStage, SdfPath("/refSphere2/world")); overSphere.GetDisplayColorAttr().Set(VtArray<GfVec3f> { GfVec3f(1.f, 0.f, 0.f) }); pRefStage->GetRootLayer()->Save(); PrintStage(pRefStage); return 0; }
Traversing a Stage
#include "stdafx.h" using namespace PXR_INTERNAL_NS; int main(int args, char* argv[]) { auto pStage = UsdStage::Open("RefExample.usda"); for (auto prim : pStage->Traverse()) { std::cout << prim.GetName() << ": " << prim.GetTypeName() << std::endl; } auto iter = UsdPrimRange::PreAndPostVisit(pStage->GetPseudoRoot()); for (auto i = iter.begin(); i != iter.end(); ++i) { std::cout << i->GetName() << " " << i.IsPostVisit() << std::endl; } return 0; }
Authoring Variants
#include "stdafx.h" using namespace PXR_INTERNAL_NS; int main(int args, char* argv[]) { auto pStage = UsdStage::Open("HelloWorld.usda"); auto color = UsdGeomGprim::Get(pStage, SdfPath("/hello/world")).GetDisplayColorAttr(); color.Clear(); auto rootPrim = pStage->GetPrimAtPath(SdfPath("/hello")); auto vset = rootPrim.GetVariantSets().AddVariantSet("shadingVariant"); vset.AddVariant("red"); vset.AddVariant("blue"); vset.AddVariant("green"); vset.SetVariantSelection("red"); { UsdEditContext ctxt(vset.GetVariantEditContext()); color.Set(VtArray<GfVec3f> { GfVec3f(1.f, 0.f, 0.f) }); } vset.SetVariantSelection("blue"); { UsdEditContext ctxt(vset.GetVariantEditContext()); color.Set(VtArray<GfVec3f> { GfVec3f(0.f, 0.f, 1.f) }); } vset.SetVariantSelection("green"); { UsdEditContext ctxt(vset.GetVariantEditContext()); color.Set(VtArray<GfVec3f> { GfVec3f(0.f, 1.f, 0.f) }); } pStage->GetRootLayer()->Export("HelloWorldWithVariants.usda"); return 0; }
Transformations, Time-sampled Animation, and Layer Offsets
#include "stdafx.h" using namespace PXR_INTERNAL_NS; UsdStageRefPtr MakeInitialStage(const std::string& path) { auto pStage = UsdStage::CreateNew(path); UsdGeomSetStageUpAxis(pStage, UsdGeomTokens->z); pStage->SetStartTimeCode(0.0); pStage->SetEndTimeCode(192.0); return pStage; } UsdGeomXform AddReferenceToGeometry(UsdStageRefPtr pStage, const std::string& path) { auto geom = UsdGeomXform::Define(pStage, SdfPath(path)); geom.GetPrim().GetReferences().AddReference("./top.geom.usd"); return geom; } void AddSpin(UsdGeomXform top) { auto spin = top.AddRotateZOp(UsdGeomXformOp::PrecisionFloat, TfToken("spin")); spin.Set(0.f, UsdTimeCode(0.0)); spin.Set(1440.f, UsdTimeCode(192.0)); } void AddTilt(UsdGeomXform top) { auto tilt = top.AddRotateXOp(UsdGeomXformOp::PrecisionFloat, TfToken("tilt")); tilt.Set(12.f); } void AddOffset(UsdGeomXform top) { top.AddTranslateOp(UsdGeomXformOp::PrecisionFloat, TfToken("offset")).Set(GfVec3f(0.f, 0.1f, 0.f)); } void AddPrecession(UsdGeomXform top) { auto precess = top.AddRotateZOp(UsdGeomXformOp::PrecisionFloat, TfToken("precess")); precess.Set(0.f, UsdTimeCode(0.0)); precess.Set(360.f, UsdTimeCode(192.0)); } void Step1() { auto pStage = MakeInitialStage("Step1.usda"); pStage->SetMetadata(TfToken("comment"), "Step 1: Start and end time codes"); pStage->Save(); } void Step2() { auto pStage = MakeInitialStage("Step2.usda"); pStage->SetMetadata(TfToken("comment"), "Step 2: Geometry reference"); auto top = AddReferenceToGeometry(pStage, "/Top"); pStage->Save(); } void Step3() { auto pStage = MakeInitialStage("Step3.usda"); pStage->SetMetadata(TfToken("comment"), "Step 3: Adding spin animation"); auto top = AddReferenceToGeometry(pStage, "/Top"); AddSpin(top); pStage->Save(); } void Step4() { auto pStage = MakeInitialStage("Step4.usda"); pStage->SetMetadata(TfToken("comment"), "Step 4: Adding tilt"); auto top = AddReferenceToGeometry(pStage, "/Top"); AddSpin(top); AddTilt(top); pStage->Save(); } void Step5() { auto pStage = MakeInitialStage("Step5.usda"); pStage->SetMetadata(TfToken("comment"), "Step 5: Adding precession and offset"); auto top = AddReferenceToGeometry(pStage, "/Top"); AddPrecession(top); AddOffset(top); AddTilt(top); AddSpin(top); pStage->Save(); } void Step6() { const auto animLayerPath = "./Step5.usda"; auto pStage = MakeInitialStage("Step6.usda"); pStage->SetMetadata(TfToken("comment"), "Step 6: Layer offsets and animation"); auto left = UsdGeomXform::Define(pStage, SdfPath("/Left")); auto leftTop = UsdGeomXform::Define(pStage, SdfPath("/Left/Top")); leftTop.GetPrim().GetReferences().AddReference(animLayerPath, SdfPath("/Top")); auto middle = UsdGeomXform::Define(pStage, SdfPath("/Middle")); middle.AddTranslateOp().Set(GfVec3d(2.0, 0.0, 0.0)); auto middleTop = UsdGeomXform::Define(pStage, SdfPath("/Middle/Top")); middleTop.GetPrim().GetReferences().AddReference(animLayerPath, SdfPath("/Top"), SdfLayerOffset(96.0, 1.0)); auto right = UsdGeomXform::Define(pStage, SdfPath("/Right")); right.AddTranslateOp().Set(GfVec3d(4.0, 0.0, 0.0)); auto rightTop = UsdGeomXform::Define(pStage, SdfPath("/Right/Top")); rightTop.GetPrim().GetReferences().AddReference(animLayerPath, SdfPath("/Top"), SdfLayerOffset(0.0, 0.25)); pStage->Save(); } int main(int args, char* argv[]) { Step1(); Step2(); Step3(); Step4(); Step5(); Step6(); return 0; }
Simple Shading in USD
#include "stdafx.h" using namespace PXR_INTERNAL_NS; int main(int args, char* argv[]) { // Making a Model auto pStage = UsdStage::CreateNew("simpleShading.usda"); UsdGeomSetStageUpAxis(pStage, UsdGeomTokens->y); auto modelRoot = UsdGeomXform::Define(pStage, SdfPath("/TexModel")); UsdModelAPI(modelRoot).SetKind(TfToken("component")); // Adding a Mesh "Billboard" auto billboard = UsdGeomMesh::Define(pStage, SdfPath("/TexModel/card")); billboard.CreatePointsAttr().Set(VtArray<GfVec3f> { GfVec3f(-430.f, -145.f, 0.f), GfVec3f(430.f, -145.f, 0.f), GfVec3f(430.f, 145.f, 0.f), GfVec3f(-430.f, 145.f, 0.f), }); billboard.CreateFaceVertexCountsAttr().Set(VtArray<int> { 4 }); billboard.CreateFaceVertexIndicesAttr().Set(VtArray<int> { 0, 1, 2, 3 }); billboard.CreateExtentAttr().Set(VtArray<GfVec3f> { GfVec3f(-430.f, -145.f, 0.f), GfVec3f(430.f, 145.f, 0.f) }); auto texCoords = billboard.CreatePrimvar(TfToken("st"), SdfValueTypeNames->TexCoord2fArray, UsdGeomTokens->varying); texCoords.Set(VtArray<GfVec2f> { GfVec2f(0.f, 0.f), GfVec2f(1.f, 0.f), GfVec2f(1.f, 1.f), GfVec2f(0.f, 1.f) }); // Make a Material auto material = UsdShadeMaterial::Define(pStage, SdfPath("/TexModel/boardMat")); // Add a UsdPreviewSurface auto pbrShader = UsdShadeShader::Define(pStage, SdfPath("/TexModel/boardMat/PBRShader")); pbrShader.CreateIdAttr(VtValue(TfToken("UsdPreviewSurface"))); pbrShader.CreateInput(TfToken("roughness"), SdfValueTypeNames->Float).Set(0.4f); pbrShader.CreateInput(TfToken("metallic"), SdfValueTypeNames->Float).Set(0.f); material.CreateSurfaceOutput().ConnectToSource(pbrShader, TfToken("surface")); // Add Texturing auto stReader = UsdShadeShader::Define(pStage, SdfPath("/TexModel/boardMat/stReader")); stReader.CreateIdAttr(VtValue(TfToken("UsdPrimvarReader_float2"))); auto diffuseTextureSampler = UsdShadeShader::Define(pStage, SdfPath("/TexModel/boardMat/diffuseTexture")); diffuseTextureSampler.CreateIdAttr(VtValue(TfToken("UsdUVTexture"))); diffuseTextureSampler.CreateInput(TfToken("file"), SdfValueTypeNames->Asset).Set(SdfAssetPath("USDLogoLrg.png")); diffuseTextureSampler.CreateInput(TfToken("st"), SdfValueTypeNames->Float2).ConnectToSource(stReader, TfToken("result")); diffuseTextureSampler.CreateOutput(TfToken("rgb"), SdfValueTypeNames->Float3); pbrShader.CreateInput(TfToken("diffuseColor"), SdfValueTypeNames->Color3f).ConnectToSource(diffuseTextureSampler, TfToken("rgb")); auto stInput = material.CreateInput(TfToken("frame:stPrimvarName"), SdfValueTypeNames->Token); stInput.Set(TfToken("st")); stReader.CreateInput(TfToken("varname"), SdfValueTypeNames->Token).ConnectToSource(stInput); UsdShadeMaterialBindingAPI(billboard).Bind(material); pStage->Save(); return 0; }