void My_TestGLDrawing::OffscreenTest() { DrawScene(); WriteToFile("color", "color1_unselected.png"); // select cube0 _picker.Pick(GfVec2i(319,221), GfVec2i(320,222)); DrawScene(); WriteToFile("color", "color2_cube0_pickable.png"); HdSelectionSharedPtr selection = _picker.GetSelection(); HdSelection::HighlightMode mode = HdSelection::HighlightModeSelect; TF_VERIFY(selection->GetSelectedPrimPaths(mode).size() == 1); TF_VERIFY(selection->GetSelectedPrimPaths(mode)[0] == SdfPath("/cube0")); // make cube0 unpickable; it should not let us pick cube1 since it occludes SdfPathVector excludePaths = {SdfPath("/cube0")}; _pickablesCol.SetExcludePaths(excludePaths); _picker.SetDoUnpickablesOcclude(true); _picker.Pick(GfVec2i(319,221), GfVec2i(320,222)); DrawScene(); WriteToFile("color", "color3_cube0_unpickable.png"); selection = _picker.GetSelection(); //TF_VERIFY(selection->GetSelectedPrimPaths(mode).size() == 0); }
void My_TestGLDrawing::OffscreenTest() { SdfPath primId; int instanceIndex = -1; int elementIndex = -1; bool refined = (_reprName == HdTokens->refined); primId = PickScene(180, 100, &instanceIndex, &elementIndex); TF_VERIFY(primId == SdfPath("/cube1") && instanceIndex == 0 && elementIndex == 3); primId = PickScene(250, 190, &instanceIndex, &elementIndex); if (refined) { TF_VERIFY(primId == SdfPath("/protoTop") && instanceIndex == 2 && elementIndex == 4); } else { TF_VERIFY(primId == SdfPath("/protoTop") && instanceIndex == 2 && elementIndex == 3); } primId = PickScene(320, 290, &instanceIndex, &elementIndex); TF_VERIFY(primId == SdfPath("/protoBottom") && instanceIndex == 1 && elementIndex == 3); }
/*virtual*/ SdfPath HdSceneDelegate::GetPathForInstanceIndex(const SdfPath &protoPrimPath, int instanceIndex, int *absoluteInstanceIndex) { return SdfPath(); }
UsdPrim UsdPrim::GetMaster() const { Usd_PrimDataConstPtr masterPrimData = _GetStage()->_GetMasterForInstance(get_pointer(_Prim())); return UsdPrim(masterPrimData, SdfPath()); }
SdfPath UsdRelationship::_GetTargetForAuthoring(const SdfPath &target, std::string* whyNot) const { if (!target.IsEmpty()) { SdfPath absTarget = target.MakeAbsolutePath(GetPath().GetAbsoluteRootOrPrimPath()); if (Usd_InstanceCache::IsPathMasterOrInMaster(absTarget)) { if (whyNot) { *whyNot = "Cannot target a master or an object within a " "master."; } return SdfPath(); } } UsdStage *stage = _GetStage(); SdfPath mappedPath = _MapTargetPath(stage, GetPath(), target); if (mappedPath.IsEmpty()) { if (whyNot) { *whyNot = TfStringPrintf("Cannot map <%s> to layer @%s@ via stage's " "EditTarget", target.GetText(), stage->GetEditTarget(). GetLayer()->GetIdentifier().c_str()); } } return mappedPath; }
UsdMayaGLBatchRenderer::ShapeRenderer * UsdMayaGLBatchRenderer::GetShapeRenderer( const UsdPrim& usdPrim, const SdfPathVector& excludePrimPaths, const MDagPath& objPath ) { const size_t hash = _ShapeHash( usdPrim, excludePrimPaths, objPath ); // We can get away with this because the spec for std::unordered_map // guarantees that data pairs remain valid even if other objects are inserted. // ShapeRenderer *toReturn = &_shapeRendererMap[ hash ]; if( !toReturn->_batchRenderer ) { // Create a simple hash string to put into a flat SdfPath "hierarchy". // This is much faster than more complicated pathing schemes. // std::string idString = TfStringPrintf("/x%zx", hash); toReturn->Init(_renderIndex, SdfPath(idString), usdPrim, excludePrimPaths); toReturn->_batchRenderer = this; } return toReturn; }
void HdRprim::_Sync(HdSceneDelegate* delegate, TfToken const &defaultReprName, bool forced, HdDirtyBits *dirtyBits) { HdRenderIndex &renderIndex = delegate->GetRenderIndex(); HdChangeTracker &changeTracker = renderIndex.GetChangeTracker(); // Check if the rprim has a new surface shader associated to it, // if so, we will request the binding from the delegate and set it up in // this rprim. if(*dirtyBits & HdChangeTracker::DirtySurfaceShader) { VtValue shaderBinding = delegate->Get(GetId(), HdShaderTokens->surfaceShader); if(shaderBinding.IsHolding<SdfPath>()){ _SetSurfaceShaderId(changeTracker, shaderBinding.Get<SdfPath>()); } else { _SetSurfaceShaderId(changeTracker, SdfPath()); } *dirtyBits &= ~HdChangeTracker::DirtySurfaceShader; } }
static void _ProcessChildren( const TfToken& childrenField, const VtValue& srcChildrenValue, const VtValue& dstChildrenValue, const SdfLayerHandle& srcLayer, const SdfPath& srcPath, bool childrenInSrc, const SdfLayerHandle& dstLayer, const SdfPath& dstPath, bool childrenInDst, _CopyStack* copyStack) { typedef typename ChildPolicy::FieldType FieldType; typedef std::vector<FieldType> ChildrenVector; if (!TF_VERIFY(srcChildrenValue.IsHolding<ChildrenVector>() || srcChildrenValue.IsEmpty()) || !TF_VERIFY(dstChildrenValue.IsHolding<ChildrenVector>() || dstChildrenValue.IsEmpty())) { return; } const ChildrenVector emptyChildren; const ChildrenVector& srcChildren = srcChildrenValue.IsEmpty() ? emptyChildren : srcChildrenValue.UncheckedGet<ChildrenVector>(); const ChildrenVector& dstChildren = dstChildrenValue.IsEmpty() ? emptyChildren : dstChildrenValue.UncheckedGet<ChildrenVector>(); for (size_t i = 0; i < srcChildren.size(); ++i) { if (srcChildren[i].IsEmpty() || dstChildren[i].IsEmpty()) { continue; } const SdfPath srcChildPath = ChildPolicy::GetChildPath(srcPath, srcChildren[i]); const SdfPath dstChildPath = ChildPolicy::GetChildPath(dstPath, dstChildren[i]); copyStack->emplace_back(srcChildPath, dstChildPath); } // Add entries to the copy stack to mark the removal of child specs // in the destination layer that aren't included in the list of children // to copy. if (childrenInDst) { const VtValue oldDstChildrenValue = dstLayer->GetField(dstPath, childrenField); if (!TF_VERIFY(oldDstChildrenValue.IsHolding<ChildrenVector>())) { return; } for (const auto& oldDstChild : oldDstChildrenValue.UncheckedGet<ChildrenVector>()) { if (std::find(dstChildren.begin(), dstChildren.end(), oldDstChild) == dstChildren.end()) { const SdfPath oldDstChildPath = ChildPolicy::GetChildPath(dstPath, oldDstChild); copyStack->emplace_back(SdfPath(), oldDstChildPath); } } } }
SdfPath SdfAttributeSpec::GetConnectionPathForMapper( const SdfMapperSpecHandle& mapper) { if (mapper->GetAttribute() == SdfCreateHandle(this)) { return mapper->GetConnectionTargetPath(); } return SdfPath(); }
UsdPrim PxrUsdKatanaUsdInArgs::GetRootPrim() const { if (_isolatePath.empty()) { return _stage->GetPseudoRoot(); } else { return _stage->GetPrimAtPath(SdfPath(_isolatePath)); } }
/// Extracts an absolute path at \p key from \p userArgs, or the empty path if /// it can't extract. static SdfPath _AbsolutePath(const VtDictionary& userArgs, const TfToken& key) { const std::string s = _String(userArgs, key); // Assume that empty strings are empty paths. (This might be an error case.) if (s.empty()) { return SdfPath(); } // Make all relative paths into absolute paths. SdfPath path(s); if (path.IsAbsolutePath()) { return path; } else { return SdfPath::AbsoluteRootPath().AppendPath(path); } }
UsdMayaGLBatchRenderer::UsdMayaGLBatchRenderer() : _renderIndex(nullptr) , _renderDelegate() , _taskDelegate() , _intersector() { _renderIndex = HdRenderIndex::New(&_renderDelegate); if (!TF_VERIFY(_renderIndex != nullptr)) { return; } _taskDelegate = TaskDelegateSharedPtr( new TaskDelegate(_renderIndex, SdfPath("/mayaTask"))); _intersector = HdxIntersectorSharedPtr(new HdxIntersector(_renderIndex)); static MCallbackId sceneUpdateCallbackId = 0; if (sceneUpdateCallbackId == 0) { sceneUpdateCallbackId = MSceneMessage::addCallback(MSceneMessage::kSceneUpdate, _OnMayaSceneUpdateCallback); } }
static void TestPrimQueries() { printf("TestPrimQueries...\n"); auto stage = UsdStage::CreateInMemory("TestPrimQueries.usd"); auto path = SdfPath("/p"); auto prim = stage->DefinePrim(path); printf("--------Ensuring no schemas are applied -------\n"); assert(!prim.HasAPI<UsdClipsAPI>()); assert(!prim.HasAPI<UsdModelAPI>()); printf("--------Applying UsdModelAPI -------\n"); UsdModelAPI::Apply(stage, path); assert(!prim.HasAPI<UsdClipsAPI>()); assert(prim.HasAPI<UsdModelAPI>()); printf("--------Applying UsdClipsAPI -------\n"); UsdClipsAPI::Apply(stage, path); assert(prim.HasAPI<UsdClipsAPI>()); assert(prim.HasAPI<UsdModelAPI>()); }
static void TestPrimQueries() { printf("TestPrimQueries...\n"); auto stage = UsdStage::CreateInMemory("TestPrimQueries.usd"); auto path = SdfPath("/p"); auto prim = stage->DefinePrim(path); printf("--------Ensuring no schemas are applied -------\n"); assert(!prim.HasAPI<UsdCollectionAPI>()); printf("--------Applying UsdCollectionAPI -------\n"); UsdCollectionAPI coll = UsdCollectionAPI::ApplyCollection(prim, TfToken("testColl")); assert(prim.HasAPI<UsdCollectionAPI>()); assert(prim.HasAPI<UsdCollectionAPI>(/*instanceName*/ TfToken("testColl"))); assert(!prim.HasAPI<UsdCollectionAPI>( /*instanceName*/ TfToken("nonExistentColl"))); }
static void _AddClipsFromNode(const PcpPrimIndex& primIndex, Usd_ClipCache::Clips* clips) { Usd_ResolvedClipInfo clipInfo; auto node = Usd_ResolveClipInfo(primIndex, &clipInfo); // If we haven't found all of the required clip metadata we can just // bail out. Note that clipTimes and clipManifestAssetPath are *not* // required. if (!clipInfo.clipAssetPaths || !clipInfo.clipPrimPath || !clipInfo.clipActive) { return; } // The clip manifest is currently optional but can greatly improve // performance if specified. For debugging performance problems, // issue a message indicating if one hasn't been specified. if (!clipInfo.clipManifestAssetPath) { TF_DEBUG(USD_CLIPS).Msg( "No clip manifest specified for prim <%s>. " "Performance may be improved if a manifest is specified.", primIndex.GetPath().GetString().c_str()); } // XXX: Possibly want a better way to inform consumers of the error // message.. std::string error; if (!_ValidateClipFields( *clipInfo.clipAssetPaths, *clipInfo.clipPrimPath, *clipInfo.clipActive, &error)) { TF_WARN( "Invalid clips specified for prim <%s> in LayerStack %s: %s", node.GetPath().GetString().c_str(), TfStringify(node.GetLayerStack()).c_str(), error.c_str()); return; } // If a clip manifest has been specified, create a clip for it. if (clipInfo.clipManifestAssetPath) { const Usd_ClipRefPtr clip(new Usd_Clip( /* clipSourceNode = */ node, /* clipSourceLayerIndex = */ clipInfo.indexOfLayerWhereAssetPathsFound, /* clipAssetPath = */ *clipInfo.clipManifestAssetPath, /* clipPrimPath = */ SdfPath(*clipInfo.clipPrimPath), /* clipStartTime = */ Usd_ClipTimesEarliest, /* clipEndTime = */ Usd_ClipTimesLatest, /* clipTimes = */ Usd_Clip::TimeMappings())); clips->manifestClip = clip; } // Generate a mapping of startTime -> clip entry. This allows us to // quickly determine the (startTime, endTime) for a given clip. typedef std::map<double, Usd_ClipEntry> _TimeToClipMap; _TimeToClipMap startTimeToClip; for (const auto& startFrameAndClipIndex : *clipInfo.clipActive) { const double startFrame = startFrameAndClipIndex[0]; const int clipIndex = (int)(startFrameAndClipIndex[1]); const SdfAssetPath& assetPath = (*clipInfo.clipAssetPaths)[clipIndex]; Usd_ClipEntry entry; entry.startTime = startFrame; entry.clipAssetPath = assetPath; entry.clipPrimPath = SdfPath(*clipInfo.clipPrimPath); // Validation should have caused us to bail out if there were any // conflicting clip activations set. TF_VERIFY(startTimeToClip.insert( std::make_pair(entry.startTime, entry)).second); } // Build up the final vector of clips. const _TimeToClipMap::const_iterator itBegin = startTimeToClip.begin(); const _TimeToClipMap::const_iterator itEnd = startTimeToClip.end(); _TimeToClipMap::const_iterator it = startTimeToClip.begin(); while (it != itEnd) { const Usd_ClipEntry clipEntry = it->second; const Usd_Clip::ExternalTime clipStartTime = (it == itBegin ? Usd_ClipTimesEarliest : it->first); ++it; const Usd_Clip::ExternalTime clipEndTime = (it == itEnd ? Usd_ClipTimesLatest : it->first); // Generate the clip time mapping that applies to this clip. Usd_Clip::TimeMappings timeMapping; if (clipInfo.clipTimes) { for (const auto& clipTime : *clipInfo.clipTimes) { const Usd_Clip::ExternalTime extTime = clipTime[0]; const Usd_Clip::InternalTime intTime = clipTime[1]; if (clipStartTime <= extTime && extTime < clipEndTime) { timeMapping.push_back( Usd_Clip::TimeMapping(extTime, intTime)); } } } const Usd_ClipRefPtr clip(new Usd_Clip( /* clipSourceNode = */ node, /* clipSourceLayerIndex = */ clipInfo.indexOfLayerWhereAssetPathsFound, /* clipAssetPath = */ clipEntry.clipAssetPath, /* clipPrimPath = */ clipEntry.clipPrimPath, /* clipStartTime = */ clipStartTime, /* clipEndTime = */ clipEndTime, /* clipTimes = */ timeMapping)); clips->valueClips.push_back(clip); } clips->sourceNode = node; clips->sourceLayerIndex = clipInfo.indexOfLayerWhereAssetPathsFound; }
HdTextureResourceSharedPtr UsdImagingGL_GetTextureResource(UsdPrim const& usdPrim, SdfPath const& usdPath, UsdTimeCode time) { if (!TF_VERIFY(usdPrim)) return HdTextureResourceSharedPtr(); if (!TF_VERIFY(usdPath != SdfPath())) return HdTextureResourceSharedPtr(); UsdAttribute attr = _GetTextureResourceAttr(usdPrim, usdPath); SdfAssetPath asset; if (!TF_VERIFY(attr) || !TF_VERIFY(attr.Get(&asset, time))) { return HdTextureResourceSharedPtr(); } HdTextureType textureType = HdTextureType::Uv; TfToken filePath = TfToken(asset.GetResolvedPath()); // If the path can't be resolved, it's either an UDIM texture // or the texture doesn't exists and we can to exit early. if (filePath.IsEmpty()) { filePath = TfToken(asset.GetAssetPath()); if (GlfIsSupportedUdimTexture(filePath)) { textureType = HdTextureType::Udim; } else { TF_DEBUG(USDIMAGING_TEXTURES).Msg( "File does not exist, returning nullptr"); TF_WARN("Unable to find Texture '%s' with path '%s'.", filePath.GetText(), usdPath.GetText()); return {}; } } else { if (GlfIsSupportedPtexTexture(filePath)) { textureType = HdTextureType::Ptex; } } GlfImage::ImageOriginLocation origin = UsdImagingGL_ComputeTextureOrigin(usdPrim); HdWrap wrapS = _GetWrapS(usdPrim, textureType); HdWrap wrapT = _GetWrapT(usdPrim, textureType); HdMinFilter minFilter = _GetMinFilter(usdPrim); HdMagFilter magFilter = _GetMagFilter(usdPrim); float memoryLimit = _GetMemoryLimit(usdPrim); TF_DEBUG(USDIMAGING_TEXTURES).Msg( "Loading texture: id(%s), type(%s)\n", usdPath.GetText(), textureType == HdTextureType::Uv ? "Uv" : textureType == HdTextureType::Ptex ? "Ptex" : "Udim"); HdTextureResourceSharedPtr texResource; TfStopwatch timer; timer.Start(); // Udim's can't be loaded through like other textures, because // we can't select the right factory based on the file type. // We also need to pass the layer context to the factory, // so each file gets resolved properly. GlfTextureHandleRefPtr texture; if (textureType == HdTextureType::Udim) { UdimTextureFactory factory(_FindLayerHandle(attr, time)); texture = GlfTextureRegistry::GetInstance().GetTextureHandle( filePath, origin, &factory); } else { texture = GlfTextureRegistry::GetInstance().GetTextureHandle( filePath, origin); } texResource = HdTextureResourceSharedPtr( new HdStSimpleTextureResource(texture, textureType, wrapS, wrapT, minFilter, magFilter, memoryLimit)); timer.Stop(); TF_DEBUG(USDIMAGING_TEXTURES).Msg(" Load time: %.3f s\n", timer.GetSeconds()); return texResource; }
UsdImaging_DefaultTaskDelegate::UsdImaging_DefaultTaskDelegate( HdRenderIndexSharedPtr const& parentIndex, SdfPath const& delegateID) : UsdImagingTaskDelegate(parentIndex, delegateID) , _viewport(0,0,1,1) , _selectionColor(1,1,0,1) { // create an unique namespace _rootId = delegateID.AppendChild( TfToken(TfStringPrintf("_UsdImaging_%p", this))); _renderTaskId = _rootId.AppendChild(_tokens->renderTask); _idRenderTaskId = _rootId.AppendChild(_tokens->idRenderTask); _selectionTaskId = _rootId.AppendChild(_tokens->selectionTask); _simpleLightTaskId = _rootId.AppendChild(_tokens->simpleLightTask); _simpleLightBypassTaskId = _rootId.AppendChild(_tokens->simpleLightBypassTask); _cameraId = _rootId.AppendChild(_tokens->camera); _activeSimpleLightTaskId = SdfPath(); // TODO: tasks of shadow map generation, accumulation etc will be // prepared here. HdRenderIndex &renderIndex = GetRenderIndex(); // camera { renderIndex.InsertCamera<HdCamera>(this, _cameraId); _ValueCache &cache = _valueCacheMap[_cameraId]; cache[HdShaderTokens->worldToViewMatrix] = VtValue(GfMatrix4d(1)); cache[HdShaderTokens->projectionMatrix] = VtValue(GfMatrix4d(1)); cache[HdTokens->cameraFrustum] = VtValue(); // we don't use GfFrustum. cache[HdTokens->windowPolicy] = VtValue(); // we don't use window policy. } // selection task { renderIndex.InsertTask<HdxSelectionTask>(this, _selectionTaskId); _ValueCache &cache = _valueCacheMap[_selectionTaskId]; HdxSelectionTaskParams params; params.enableSelection = true; params.selectionColor = _selectionColor; params.locateColor = GfVec4f(0,0,1,1); cache[HdTokens->params] = VtValue(params); cache[HdTokens->children] = VtValue(SdfPathVector()); } // simple lighting task (for Hydra native) { renderIndex.InsertTask<HdxSimpleLightTask>(this, _simpleLightTaskId); _ValueCache &cache = _valueCacheMap[_simpleLightTaskId]; HdxSimpleLightTaskParams params; params.cameraPath = _cameraId; cache[HdTokens->params] = VtValue(params); cache[HdTokens->children] = VtValue(SdfPathVector()); } // simple lighting task (for Presto UsdBaseIc compatible) { renderIndex.InsertTask<HdxSimpleLightBypassTask>(this, _simpleLightBypassTaskId); _ValueCache &cache = _valueCacheMap[_simpleLightBypassTaskId]; HdxSimpleLightBypassTaskParams params; params.cameraPath = _cameraId; cache[HdTokens->params] = VtValue(params); cache[HdTokens->children] = VtValue(SdfPathVector()); } // render task _InsertRenderTask(_renderTaskId); _InsertRenderTask(_idRenderTaskId); // initialize HdxRenderTaskParams for render tasks _UpdateCollection(&_rprims, HdTokens->geometry, HdTokens->smoothHull, SdfPathVector(1, SdfPath::AbsoluteRootPath()), _renderTaskId, _idRenderTaskId); _UpdateRenderParams(_renderParams, _renderParams, _renderTaskId); _UpdateRenderParams(_idRenderParams, _idRenderParams, _idRenderTaskId); }
void USDVMP::setup(FnKat::ViewerModifierInput& input) { TF_DEBUG(KATANA_DEBUG_VMP_USD).Msg("%s @ %p : %s\n", TF_FUNC_NAME().c_str(), this, input.getFullName().c_str()); // The multi-threaded Usd Op may be loading or unloading models on the stage // we need, so we grab the global lock in reader mode. boost::shared_lock<boost::upgrade_mutex> readerLock(UsdKatanaGetStageLock()); // Open stage if necessary. if (not _stage) { // Get usd file, node path, and current time, // needed to call TidSceneRenderer FnKat::StringAttribute usdFileAttr = input.getAttribute("fileName"); FnKat::StringAttribute usdRootLocationAttr = input.getAttribute("rootLocation"); FnKat::StringAttribute usdReferencePathAttr = input.getAttribute("referencePath"); FnKat::StringAttribute variantStringAttr = input.getAttribute("variants"); FnKat::StringAttribute ignoreLayerAttr= input.getAttribute("ignoreLayerRegex"); FnKat::FloatAttribute forcePopulateAttr = input.getAttribute("forcePopulateUsdStage"); std::string usdFile = usdFileAttr.getValue("", false); std::string usdRootLocation = usdRootLocationAttr.getValue("", false); std::string usdReferencePath = usdReferencePathAttr.getValue("",false); std::string variantString = variantStringAttr.getValue("",false); std::string ignoreLayerRegex = ignoreLayerAttr.getValue("$^", false); bool forcePopulate = forcePopulateAttr.getValue((float)true,false); if (usdFile.empty()) return; _stage = UsdKatanaCache::GetInstance().GetStage(usdFile, variantString, ignoreLayerRegex, forcePopulate); if (not _stage) { TF_DEBUG(KATANA_DEBUG_VMP_USD).Msg( "Cannot resolve path %s", usdFile.c_str()); return; } if (usdReferencePath == "") _prim = _stage->GetPseudoRoot(); else _prim = _stage->GetPrimAtPath(SdfPath(usdReferencePath)); if (not _prim) FnLogWarn(std::string("Cannot compose ") + _prim.GetPath().GetString()); _params.cullStyle = UsdImagingEngine::CULL_STYLE_BACK_UNLESS_DOUBLE_SIDED; _renderer = UsdKatanaCache::GetInstance() .GetRenderer(_stage, _prim, variantString); } // always update frame time FnKat::DoubleAttribute currentTimeAttr = input.getAttribute("currentTime"); double currentTime = currentTimeAttr.getValue(0.0, false); _params.frame = currentTime; }
/// Finds the existing SkelRoot which is shared by all \p paths. /// If no SkelRoot is found, and \p config is "auto", then attempts to /// find a common ancestor of \p paths which can be converted to SkelRoot. /// \p outMadeSkelRoot must be non-null; it will be set to indicate whether /// any auto-typename change actually occurred (true) or whether there was /// already a SkelRoot, so no renaming was necessary (false). /// If an existing, common SkelRoot cannot be found for all paths, and if /// it's not possible to create one, returns an empty SdfPath. static SdfPath _VerifyOrMakeSkelRoot(const UsdStagePtr& stage, const SdfPath& path, const TfToken& config) { if (config != UsdMayaJobExportArgsTokens->auto_ && config != UsdMayaJobExportArgsTokens->explicit_) { return SdfPath(); } // Only try to auto-rename to SkelRoot if we're not already a // descendant of one. Otherwise, verify that the user tagged it in a sane // way. if (UsdSkelRoot root = UsdSkelRoot::Find(stage->GetPrimAtPath(path))) { // Verify that the SkelRoot isn't nested in another SkelRoot. // This is necessary because UsdSkel doesn't handle nested skel roots // very well currently; this restriction may be loosened in the future. if (UsdSkelRoot root2 = UsdSkelRoot::Find(root.GetPrim().GetParent())) { TF_RUNTIME_ERROR("The SkelRoot <%s> is nested inside another " "SkelRoot <%s>. This might cause unexpected behavior.", root.GetPath().GetText(), root2.GetPath().GetText()); return SdfPath(); } else { return root.GetPath(); } } else if(config == UsdMayaJobExportArgsTokens->auto_) { // If auto-generating the SkelRoot, find the rootmost // UsdGeomXform and turn it into a SkelRoot. // XXX: It might be good to also consider model hierarchy here, and not // go past our ancestor component when trying to generate the SkelRoot. // (Example: in a scene with /World, /World/Char_1, /World/Char_2, we // might want SkelRoots to stop at Char_1 and Char_2.) Unfortunately, // the current structure precludes us from accessing model hierarchy // here. if (UsdPrim root = _FindRootmostXformOrSkelRoot(stage, path)) { UsdSkelRoot::Define(stage, root.GetPath()); return root.GetPath(); } else { if (path.IsRootPrimPath()) { // This is the most common problem when we can't obtain a // SkelRoot. // Show a nice error with useful information about root prims. TF_RUNTIME_ERROR("The prim <%s> is a root prim, so it has no " "ancestors that can be converted to a SkelRoot. (USD " "requires that skinned meshes and skeletons be " "encapsulated under a SkelRoot.) Try grouping this " "prim under a parent group.", path.GetText()); } else { // Show generic error as a last resort if we don't know exactly // what went wrong. TF_RUNTIME_ERROR("Could not find an ancestor of the prim <%s> " "that can be converted to a SkelRoot. (USD requires " "that skinned meshes and skeletons be encapsulated " "under a SkelRoot.)", path.GetText()); } return SdfPath(); } } return SdfPath(); }
void My_TestGLDrawing::_InitScene() { _delegate->AddCube(SdfPath("/cube0"), _GetTranslate( 0, 0, 0)); _delegate->AddCube(SdfPath("/cube1"), _GetTranslate( 0, 5, 1)); }
HdTextureResource::ID UsdImagingGL_GetTextureResourceID(UsdPrim const& usdPrim, SdfPath const& usdPath, UsdTimeCode time, size_t salt) { if (!TF_VERIFY(usdPrim)) { return HdTextureResource::ID(-1); } if (!TF_VERIFY(usdPath != SdfPath())) { return HdTextureResource::ID(-1); } // If the texture name attribute doesn't exist, it might be badly specified // in scene data. UsdAttribute attr = _GetTextureResourceAttr(usdPrim, usdPath); SdfAssetPath asset; if (!attr || !attr.Get(&asset, time)) { TF_WARN("Unable to find texture attribute <%s> in scene data", usdPath.GetText()); return HdTextureResource::ID(-1); } HdTextureType textureType = HdTextureType::Uv; TfToken filePath = TfToken(asset.GetResolvedPath()); if (!filePath.IsEmpty()) { // If the resolved path contains a correct path, then we are // dealing with a ptex or uv textures. if (GlfIsSupportedPtexTexture(filePath)) { textureType = HdTextureType::Ptex; } else { textureType = HdTextureType::Uv; } } else { // If the path couldn't be resolved, then it might be a Udim as they // contain special characters in the path to identify them <Udim>. // Another option is that the path is just wrong and it can not be // resolved. filePath = TfToken(asset.GetAssetPath()); if (GlfIsSupportedUdimTexture(filePath)) { const GlfContextCaps& caps = GlfContextCaps::GetInstance(); if (!UsdImaging_UdimTilesExist(filePath, caps.maxArrayTextureLayers, _FindLayerHandle(attr, time))) { TF_WARN("Unable to find Texture '%s' with path '%s'. Fallback " "textures are not supported for udim", filePath.GetText(), usdPath.GetText()); return HdTextureResource::ID(-1); } if (!caps.arrayTexturesEnabled) { TF_WARN("OpenGL context does not support array textures, " "skipping UDIM Texture %s with path %s.", filePath.GetText(), usdPath.GetText()); return HdTextureResource::ID(-1); } textureType = HdTextureType::Udim; } else if (GlfIsSupportedPtexTexture(filePath)) { TF_WARN("Unable to find Texture '%s' with path '%s'. Fallback " "textures are not supported for ptex", filePath.GetText(), usdPath.GetText()); return HdTextureResource::ID(-1); } else { TF_WARN("Unable to find Texture '%s' with path '%s'. A black " "texture will be substituted in its place.", filePath.GetText(), usdPath.GetText()); return HdTextureResource::ID(-1); } } GlfImage::ImageOriginLocation origin = UsdImagingGL_ComputeTextureOrigin(usdPrim); // Hash on the texture filename. size_t hash = asset.GetHash(); // Hash in wrapping and filtering metadata. HdWrap wrapS = _GetWrapS(usdPrim, textureType); HdWrap wrapT = _GetWrapT(usdPrim, textureType); HdMinFilter minFilter = _GetMinFilter(usdPrim); HdMagFilter magFilter = _GetMagFilter(usdPrim); float memoryLimit = _GetMemoryLimit(usdPrim); boost::hash_combine(hash, origin); boost::hash_combine(hash, wrapS); boost::hash_combine(hash, wrapT); boost::hash_combine(hash, minFilter); boost::hash_combine(hash, magFilter); boost::hash_combine(hash, memoryLimit); // Salt the result to prevent collisions in non-shared imaging. // Note that the salt is ignored for fallback texture hashes above. boost::hash_combine(hash, salt); return HdTextureResource::ID(hash); }
void Usd_PrimData::_ComposeAndCacheFlags(Usd_PrimDataConstPtr parent, bool isMasterPrim) { // We do not have to clear _flags here since in the pseudo root or instance // master case the values never change, and in the ordinary prim case we set // every flag. // Special-case the root (the only prim which has no parent) and // instancing masters. if (ARCH_UNLIKELY(!parent || isMasterPrim)) { _flags[Usd_PrimActiveFlag] = true; _flags[Usd_PrimLoadedFlag] = true; _flags[Usd_PrimModelFlag] = true; _flags[Usd_PrimGroupFlag] = true; _flags[Usd_PrimDefinedFlag] = true; _flags[Usd_PrimMasterFlag] = isMasterPrim; } else { // Compose and cache 'active'. UsdPrim self(Usd_PrimDataIPtr(this), SdfPath()); bool active = true; self.GetMetadata(SdfFieldKeys->Active, &active); _flags[Usd_PrimActiveFlag] = active; // Cache whether or not this prim has a payload. bool hasPayload = _primIndex->HasPayload(); _flags[Usd_PrimHasPayloadFlag] = hasPayload; // An active prim is loaded if it's loadable and in the load set, or // it's not loadable and its parent is loaded. _flags[Usd_PrimLoadedFlag] = active && (hasPayload ? _stage->_GetPcpCache()->IsPayloadIncluded(_primIndex->GetPath()) : parent->IsLoaded()); // According to Model hierarchy rules, only Model Groups may have Model // children (groups or otherwise). So if our parent is not a Model // Group, then this prim cannot be a model (or a model group). // Otherwise we look up the kind metadata and consult the kind registry. bool isGroup = false, isModel = false; if (parent->IsGroup()) { static TfToken kindToken("kind"); TfToken kind; self.GetMetadata(kindToken, &kind); // Use the kind registry to determine model/groupness. if (!kind.IsEmpty()) { isGroup = KindRegistry::IsA(kind, KindTokens->group); isModel = isGroup || KindRegistry::IsA(kind, KindTokens->model); } } _flags[Usd_PrimGroupFlag] = isGroup; _flags[Usd_PrimModelFlag] = isModel; // Get specifier. SdfSpecifier specifier = GetSpecifier(); // This prim is abstract if its parent is or if it's a class. _flags[Usd_PrimAbstractFlag] = parent->IsAbstract() || specifier == SdfSpecifierClass; // Cache whether or not this prim has an authored defining specifier. const bool isDefiningSpec = SdfIsDefiningSpecifier(specifier); _flags[Usd_PrimHasDefiningSpecifierFlag] = isDefiningSpec; // This prim is defined if its parent is and its specifier is defining. _flags[Usd_PrimDefinedFlag] = isDefiningSpec && parent->IsDefined(); // The presence of clips that may affect attributes on this prim // is computed and set in UsdStage. Default to false. _flags[Usd_PrimClipsFlag] = false; // These flags indicate whether this prim is an instance or an // instance master. _flags[Usd_PrimInstanceFlag] = active && _primIndex->IsInstanceable(); _flags[Usd_PrimMasterFlag] = parent->IsInMaster(); } }
void My_TestGLDrawing::InitTest() { _renderIndex = HdRenderIndex::New(&_renderDelegate); TF_VERIFY(_renderIndex != nullptr); _delegate = new Hdx_UnitTestDelegate(_renderIndex); _delegate->SetRefineLevel(_refineLevel); // prepare render task SdfPath renderSetupTask("/renderSetupTask"); SdfPath renderTask("/renderTask"); _delegate->AddRenderSetupTask(renderSetupTask); _delegate->AddRenderTask(renderTask); // render task parameters. HdxRenderTaskParams param = _delegate->GetTaskParam( renderSetupTask, HdTokens->params).Get<HdxRenderTaskParams>(); param.enableLighting = true; // use default lighting _delegate->SetTaskParam(renderSetupTask, HdTokens->params, VtValue(param)); _delegate->SetTaskParam(renderTask, HdTokens->collection, VtValue(HdRprimCollection(HdTokens->geometry, _reprName))); // prepare scene // To ensure that the non-aggregated element index returned via picking, // we need to have at least two cubes with uniform colors. GfVec4f red(1,0,0,1), green(0,1,0,1), blue(0,0,1,1), yellow(1,1,0,1), magenta(1,0,1,1), cyan(0,1,1,1), white(1,1,1,1), black(0,0,0,1); GfVec4f faceColors[] = { red, green, blue, yellow, magenta, cyan}; VtValue faceColor = VtValue(_BuildArray(&faceColors[0], sizeof(faceColors)/sizeof(faceColors[0]))); GfVec4f vertColors[] = { white, blue, green, yellow, black, blue, magenta, red}; VtValue vertColor = VtValue(_BuildArray(&vertColors[0], sizeof(vertColors)/sizeof(vertColors[0]))); _delegate->AddCube(SdfPath("/cube0"), _GetTranslate( 5, 0, 5), /*guide=*/false, /*instancerId=*/SdfPath(), /*scheme=*/PxOsdOpenSubdivTokens->catmark, /*color=*/faceColor, /*colorInterpolation=*/Hdx_UnitTestDelegate::UNIFORM); _delegate->AddCube(SdfPath("/cube1"), _GetTranslate(-5, 0, 5), /*guide=*/false, /*instancerId=*/SdfPath(), /*scheme=*/PxOsdOpenSubdivTokens->catmark, /*color=*/faceColor, /*colorInterpolation=*/Hdx_UnitTestDelegate::UNIFORM); _delegate->AddCube(SdfPath("/cube2"), _GetTranslate(-5, 0,-5)); _delegate->AddCube(SdfPath("/cube3"), _GetTranslate( 5, 0,-5), /*guide=*/false, /*instancerId=*/SdfPath(), /*scheme=*/PxOsdOpenSubdivTokens->catmark, /*color=*/vertColor, /*colorInterpolation=*/Hdx_UnitTestDelegate::VERTEX); { _delegate->AddInstancer(SdfPath("/instancerTop")); _delegate->AddCube(SdfPath("/protoTop"), GfMatrix4d(1), false, SdfPath("/instancerTop")); std::vector<SdfPath> prototypes; prototypes.push_back(SdfPath("/protoTop")); VtVec3fArray scale(3); VtVec4fArray rotate(3); VtVec3fArray translate(3); VtIntArray prototypeIndex(3); scale[0] = GfVec3f(1); rotate[0] = GfVec4f(0); translate[0] = GfVec3f(3, 0, 2); prototypeIndex[0] = 0; scale[1] = GfVec3f(1); rotate[1] = GfVec4f(0); translate[1] = GfVec3f(0, 0, 2); prototypeIndex[1] = 0; scale[2] = GfVec3f(1); rotate[2] = GfVec4f(0); translate[2] = GfVec3f(-3, 0, 2); prototypeIndex[2] = 0; _delegate->SetInstancerProperties(SdfPath("/instancerTop"), prototypeIndex, scale, rotate, translate); } { _delegate->AddInstancer(SdfPath("/instancerBottom")); _delegate->AddCube(SdfPath("/protoBottom"), GfMatrix4d(1), false, SdfPath("/instancerBottom")); std::vector<SdfPath> prototypes; prototypes.push_back(SdfPath("/protoBottom")); VtVec3fArray scale(3); VtVec4fArray rotate(3); VtVec3fArray translate(3); VtIntArray prototypeIndex(3); scale[0] = GfVec3f(1); rotate[0] = GfVec4f(0); translate[0] = GfVec3f(3, 0, -2); prototypeIndex[0] = 0; scale[1] = GfVec3f(1); rotate[1] = GfVec4f(0); translate[1] = GfVec3f(0, 0, -2); prototypeIndex[1] = 0; scale[2] = GfVec3f(1); rotate[2] = GfVec4f(0); translate[2] = GfVec3f(-3, 0, -2); prototypeIndex[2] = 0; _delegate->SetInstancerProperties(SdfPath("/instancerBottom"), prototypeIndex, scale, rotate, translate); } SetCameraTranslate(GfVec3f(0, 0, -20)); // XXX: Setup a VAO, the current drawing engine will not yet do this. glGenVertexArrays(1, &vao); glBindVertexArray(vao); glBindVertexArray(0); }
bool usdWriteJob::beginJob(const std::string &iFileName, bool append, double startTime, double endTime) { // Check for DAG nodes that are a child of an already specified DAG node to export // if that's the case, report the issue and skip the export PxrUsdMayaUtil::ShapeSet::const_iterator m, n; PxrUsdMayaUtil::ShapeSet::const_iterator endPath = mArgs.dagPaths.end(); for (m = mArgs.dagPaths.begin(); m != endPath; ) { MDagPath path1 = *m; m++; for (n = m; n != endPath; n++) { MDagPath path2 = *n; if (PxrUsdMayaUtil::isAncestorDescendentRelationship(path1,path2)) { MString errorMsg = path1.fullPathName(); errorMsg += " and "; errorMsg += path2.fullPathName(); errorMsg += " have an ancestor relationship. Skipping USD Export."; MGlobal::displayError(errorMsg); return false; } } // for n } // for m // Make sure the file name is a valid one with a proper USD extension. const std::string iFileExtension = TfStringGetSuffix(iFileName, '.'); if (iFileExtension == PxrUsdMayaTranslatorTokens->UsdFileExtensionDefault || iFileExtension == PxrUsdMayaTranslatorTokens->UsdFileExtensionASCII || iFileExtension == PxrUsdMayaTranslatorTokens->UsdFileExtensionCrate) { mFileName = iFileName; } else { mFileName = TfStringPrintf("%s.%s", iFileName.c_str(), PxrUsdMayaTranslatorTokens->UsdFileExtensionDefault.GetText()); } MGlobal::displayInfo("usdWriteJob::beginJob: Create stage file "+MString(mFileName.c_str())); ArResolverContext resolverCtx = ArGetResolver().GetCurrentContext(); if (append) { mStage = UsdStage::Open(SdfLayer::FindOrOpen(mFileName), resolverCtx); if (!mStage) { MGlobal::displayError("Failed to open stage file "+MString(mFileName.c_str())); return false; } } else { mStage = UsdStage::CreateNew(mFileName, resolverCtx); if (!mStage) { MGlobal::displayError("Failed to create stage file "+MString(mFileName.c_str())); return false; } } // Set time range for the USD file mStage->SetStartTimeCode(startTime); mStage->SetEndTimeCode(endTime); mModelKindWriter.Reset(); // Setup the requested render layer mode: // defaultLayer - Switch to the default render layer before exporting, // then switch back afterwards (no layer switching if // the current layer IS the default layer). // currentLayer - No layer switching before or after exporting. Just // use whatever is the current render layer for export. // modelingVariant - Switch to the default render layer before exporting, // and export each render layer in the scene as a // modeling variant, then switch back afterwards (no // layer switching if the current layer IS the default // layer). The default layer will be made the default // modeling variant. MFnRenderLayer currentLayer(MFnRenderLayer::currentLayer()); mCurrentRenderLayerName = currentLayer.name(); if (mArgs.renderLayerMode == PxUsdExportJobArgsTokens->modelingVariant) { // Handle usdModelRootOverridePath for USD Variants MFnRenderLayer::listAllRenderLayers(mRenderLayerObjs); if (mRenderLayerObjs.length() > 1) { mArgs.usdModelRootOverridePath = SdfPath("/_BaseModel_"); } } // Switch to the default render layer unless the renderLayerMode is // 'currentLayer', or the default layer is already the current layer. if (mArgs.renderLayerMode != PxUsdExportJobArgsTokens->currentLayer && MFnRenderLayer::currentLayer() != MFnRenderLayer::defaultRenderLayer()) { // Set the RenderLayer to the default render layer MFnRenderLayer defaultLayer(MFnRenderLayer::defaultRenderLayer()); MGlobal::executeCommand(MString("editRenderLayerGlobals -currentRenderLayer ")+ defaultLayer.name(), false, false); } // Pre-process the argument dagPath path names into two sets. One set // contains just the arg dagPaths, and the other contains all parents of // arg dagPaths all the way up to the world root. Partial path names are // enough because Maya guarantees them to still be unique, and they require // less work to hash and compare than full path names. TfHashSet<std::string, TfHash> argDagPaths; TfHashSet<std::string, TfHash> argDagPathParents; PxrUsdMayaUtil::ShapeSet::const_iterator end = mArgs.dagPaths.end(); for (PxrUsdMayaUtil::ShapeSet::const_iterator it = mArgs.dagPaths.begin(); it != end; ++it) { MDagPath curDagPath = *it; std::string curDagPathStr(curDagPath.partialPathName().asChar()); argDagPaths.insert(curDagPathStr); while (curDagPath.pop() && curDagPath.length() >= 0) { curDagPathStr = curDagPath.partialPathName().asChar(); if (argDagPathParents.find(curDagPathStr) != argDagPathParents.end()) { // We've already traversed up from this path. break; } argDagPathParents.insert(curDagPathStr); } } // Now do a depth-first traversal of the Maya DAG from the world root. // We keep a reference to arg dagPaths as we encounter them. MDagPath curLeafDagPath; for (MItDag itDag(MItDag::kDepthFirst, MFn::kInvalid); !itDag.isDone(); itDag.next()) { MDagPath curDagPath; itDag.getPath(curDagPath); std::string curDagPathStr(curDagPath.partialPathName().asChar()); if (argDagPathParents.find(curDagPathStr) != argDagPathParents.end()) { // This dagPath is a parent of one of the arg dagPaths. It should // be included in the export, but not necessarily all of its // children should be, so we continue to traverse down. } else if (argDagPaths.find(curDagPathStr) != argDagPaths.end()) { // This dagPath IS one of the arg dagPaths. It AND all of its // children should be included in the export. curLeafDagPath = curDagPath; } else if (!MFnDagNode(curDagPath).hasParent(curLeafDagPath.node())) { // This dagPath is not a child of one of the arg dagPaths, so prune // it and everything below it from the traversal. itDag.prune(); continue; } MayaPrimWriterPtr primWriter = nullptr; if (!createPrimWriter(curDagPath, &primWriter) && curDagPath.length() > 0) { // This dagPath and all of its children should be pruned. itDag.prune(); continue; } if (primWriter) { mMayaPrimWriterList.push_back(primWriter); // Write out data (non-animated/default values). if (UsdPrim usdPrim = primWriter->write(UsdTimeCode::Default())) { MDagPath dag = primWriter->getDagPath(); mDagPathToUsdPathMap[dag] = usdPrim.GetPath(); // If we are merging transforms and the object derives from // MayaTransformWriter but isn't actually a transform node, we // need to add its parent. if (mArgs.mergeTransformAndShape) { MayaTransformWriterPtr xformWriter = boost::dynamic_pointer_cast<MayaTransformWriter>( primWriter); if (xformWriter) { MDagPath xformDag = xformWriter->getTransformDagPath(); mDagPathToUsdPathMap[xformDag] = usdPrim.GetPath(); } } mModelKindWriter.OnWritePrim(usdPrim, primWriter); if (primWriter->shouldPruneChildren()) { itDag.prune(); } } } } // Writing Materials/Shading PxrUsdMayaTranslatorMaterial::ExportShadingEngines( mStage, mArgs.dagPaths, mArgs.shadingMode, mArgs.mergeTransformAndShape, mArgs.usdModelRootOverridePath); if (!mModelKindWriter.MakeModelHierarchy(mStage)) { return false; } // now we populate the chasers and run export default mChasers.clear(); PxrUsdMayaChaserRegistry::FactoryContext ctx(mStage, mDagPathToUsdPathMap, mArgs); for (const std::string& chaserName : mArgs.chaserNames) { if (PxrUsdMayaChaserRefPtr fn = PxrUsdMayaChaserRegistry::GetInstance().Create(chaserName, ctx)) { mChasers.push_back(fn); } else { std::string error = TfStringPrintf("Failed to create chaser: %s", chaserName.c_str()); MGlobal::displayError(MString(error.c_str())); } } for (const PxrUsdMayaChaserRefPtr& chaser : mChasers) { if (!chaser->ExportDefault()) { return false; } } return true; }
void My_TestGLDrawing::InitTest() { _renderIndex = HdRenderIndex::New(&_renderDelegate); TF_VERIFY(_renderIndex != nullptr); _delegate = new Hdx_UnitTestDelegate(_renderIndex); _delegate->SetRefineLevel(_refineLevel); // prepare render task SdfPath renderSetupTask("/renderSetupTask"); SdfPath renderTask("/renderTask"); _delegate->AddRenderSetupTask(renderSetupTask); _delegate->AddRenderTask(renderTask); // render task parameters. HdxRenderTaskParams param = _delegate->GetTaskParam( renderSetupTask, HdTokens->params).Get<HdxRenderTaskParams>(); param.enableLighting = true; // use default lighting _delegate->SetTaskParam(renderSetupTask, HdTokens->params, VtValue(param)); _delegate->SetTaskParam(renderTask, HdTokens->collection, VtValue(HdRprimCollection(HdTokens->geometry, _reprName))); // prepare scene _delegate->AddCube(SdfPath("/cube0"), _GetTranslate( 5, 0, 5)); _delegate->AddCube(SdfPath("/cube1"), _GetTranslate(-5, 0, 5)); _delegate->AddCube(SdfPath("/cube2"), _GetTranslate(-5, 0,-5)); _delegate->AddCube(SdfPath("/cube3"), _GetTranslate( 5, 0,-5)); { _delegate->AddInstancer(SdfPath("/instancerTop")); _delegate->AddCube(SdfPath("/protoTop"), GfMatrix4d(1), false, SdfPath("/instancerTop")); std::vector<SdfPath> prototypes; prototypes.push_back(SdfPath("/protoTop")); VtVec3fArray scale(3); VtVec4fArray rotate(3); VtVec3fArray translate(3); VtIntArray prototypeIndex(3); scale[0] = GfVec3f(1); rotate[0] = GfVec4f(0); translate[0] = GfVec3f(3, 0, 2); prototypeIndex[0] = 0; scale[1] = GfVec3f(1); rotate[1] = GfVec4f(0); translate[1] = GfVec3f(0, 0, 2); prototypeIndex[1] = 0; scale[2] = GfVec3f(1); rotate[2] = GfVec4f(0); translate[2] = GfVec3f(-3, 0, 2); prototypeIndex[2] = 0; _delegate->SetInstancerProperties(SdfPath("/instancerTop"), prototypeIndex, scale, rotate, translate); } { _delegate->AddInstancer(SdfPath("/instancerBottom")); _delegate->AddCube(SdfPath("/protoBottom"), GfMatrix4d(1), false, SdfPath("/instancerBottom")); std::vector<SdfPath> prototypes; prototypes.push_back(SdfPath("/protoBottom")); VtVec3fArray scale(3); VtVec4fArray rotate(3); VtVec3fArray translate(3); VtIntArray prototypeIndex(3); scale[0] = GfVec3f(1); rotate[0] = GfVec4f(0); translate[0] = GfVec3f(3, 0, -2); prototypeIndex[0] = 0; scale[1] = GfVec3f(1); rotate[1] = GfVec4f(0); translate[1] = GfVec3f(0, 0, -2); prototypeIndex[1] = 0; scale[2] = GfVec3f(1); rotate[2] = GfVec4f(0); translate[2] = GfVec3f(-3, 0, -2); prototypeIndex[2] = 0; _delegate->SetInstancerProperties(SdfPath("/instancerBottom"), prototypeIndex, scale, rotate, translate); } SetCameraTranslate(GfVec3f(0, 0, -20)); // XXX: Setup a VAO, the current drawing engine will not yet do this. glGenVertexArrays(1, &vao); glBindVertexArray(vao); glBindVertexArray(0); }