void SequenceContextInfoSupport::OnPrimaryClipRenamed( const ASL::String& inMediaPath, const ASL::String& inNewName, const ASL::String& inOldName) { ISRPrimaryClipRef primaryClip = PL::SRProject::GetInstance()->GetPrimaryClip(inMediaPath); if (primaryClip) { UIF::MultiContextHandler::ContextID contextID = kSequenceContextID_NULL; ISRLoggingClipRef loggingClip(primaryClip); ISRRoughCutRef roughCut(primaryClip); if (loggingClip) { contextID = kSequenceContextID_Clip; } else if (roughCut) { contextID = kSequenceContextID_RoughCut; } if (contextID != kSequenceContextID_NULL) { SequenceContextInfoPtr sequenceContextInfo = mSequenceContextInfoMap[contextID]; DVA_ASSERT(sequenceContextInfo); ASL::String itemName = GetAssetName(primaryClip); sequenceContextInfo->mName = itemName; ASL::StationUtils::BroadcastMessage( MZ::kStation_PreludeProject, SequenceContextInfoChanged(contextID)); } } }
/* **Set dirty flag for LoggingClip */ void SequenceContextInfoSupport::OnSilkRoadMediaDirtyChanged() { ISRPrimaryClipPlaybackRef loggingPlayback = ModulePicker::GetInstance()->GetLoggingClip(); if (loggingPlayback == NULL) return; SequenceContextInfoPtr sequenceContextInfo = mSequenceContextInfoMap[kSequenceContextID_Clip]; DVA_ASSERT(sequenceContextInfo); ASL::String itemName = GetAssetName(ISRPrimaryClipRef(loggingPlayback)); sequenceContextInfo->mName = itemName; ASL::StationUtils::BroadcastMessage( MZ::kStation_PreludeProject, SequenceContextInfoChanged(kSequenceContextID_Clip)); }
/* **Set dirty flag for RoughCut */ void SequenceContextInfoSupport::OnSilkRoadRoughCutDirtyChanged() { ISRPrimaryClipPlaybackRef rcPlayback = ModulePicker::GetInstance()->GetRoughCutClip(); if (rcPlayback == NULL) return; // in some case, the Roughcut's sequence point will change when it change to dirty. SequenceContextInfoPtr sequenceContextInfo = mSequenceContextInfoMap[kSequenceContextID_RoughCut]; DVA_ASSERT(sequenceContextInfo); ASL::String itemName = GetAssetName(ISRPrimaryClipRef(rcPlayback)); sequenceContextInfo->mName = itemName; sequenceContextInfo->mPrimaryClip = PL::ISRPrimaryClipRef(rcPlayback); ASL::StationUtils::BroadcastMessage( MZ::kStation_PreludeProject, SequenceContextInfoChanged(kSequenceContextID_RoughCut)); }
void CMasternodeSync::SwitchToNextAsset(CConnman& connman) { switch(nRequestedMasternodeAssets) { case(MASTERNODE_SYNC_FAILED): throw std::runtime_error("Can't switch to next asset from failed, should use Reset() first!"); break; case(MASTERNODE_SYNC_INITIAL): nRequestedMasternodeAssets = MASTERNODE_SYNC_WAITING; LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); break; case(MASTERNODE_SYNC_WAITING): LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nRequestedMasternodeAssets = MASTERNODE_SYNC_LIST; LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); break; case(MASTERNODE_SYNC_LIST): LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nRequestedMasternodeAssets = MASTERNODE_SYNC_MNW; LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); break; case(MASTERNODE_SYNC_MNW): LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nRequestedMasternodeAssets = MASTERNODE_SYNC_GOVERNANCE; LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName()); break; case(MASTERNODE_SYNC_GOVERNANCE): LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted); nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED; uiInterface.NotifyAdditionalDataSyncProgressChanged(1); //try to activate our masternode if possible activeMasternode.ManageState(connman); connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) { netfulfilledman.AddFulfilledRequest(pnode->addr, "full-sync"); }); LogPrint(MCLog::MN, "CMasternodeSync::SwitchToNextAsset -- Sync has finished\n"); break; } nRequestedMasternodeAttempt = 0; nTimeAssetSyncStarted = GetTime(); BumpAssetLastTime("CMasternodeSync::SwitchToNextAsset"); }
void CMasternodeSync::ProcessTick(CConnman& connman) { static int nTick = 0; if(nTick++ % MASTERNODE_SYNC_TICK_SECONDS != 0) return; // reset the sync process if the last call to this function was more than 60 minutes ago (client was in sleep mode) static int64_t nTimeLastProcess = GetTime(); if(GetTime() - nTimeLastProcess > 60*60) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- WARNING: no actions for too long, restarting sync...\n"); Reset(); SwitchToNextAsset(connman); nTimeLastProcess = GetTime(); return; } nTimeLastProcess = GetTime(); // reset sync status in case of any other sync failure if(IsFailed()) { if(nTimeLastFailure + (1*60) < GetTime()) { // 1 minute cooldown after failed sync LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- WARNING: failed to sync, trying again...\n"); Reset(); SwitchToNextAsset(connman); } return; } // gradually request the rest of the votes after sync finished if(IsSynced()) { std::vector<CNode*> vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly); governance.RequestGovernanceObjectVotes(vNodesCopy, connman); connman.ReleaseNodeVector(vNodesCopy); return; } // Calculate "progress" for LOG reporting / GUI notification double nSyncProgress = double(nRequestedMasternodeAttempt + (nRequestedMasternodeAssets - 1) * 8) / (8*4); LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nRequestedMasternodeAttempt %d nSyncProgress %f\n", nTick, nRequestedMasternodeAssets, nRequestedMasternodeAttempt, nSyncProgress); uiInterface.NotifyAdditionalDataSyncProgressChanged(nSyncProgress); std::vector<CNode*> vNodesCopy = connman.CopyNodeVector(CConnman::FullyConnectedOnly); for (auto& pnode : vNodesCopy) { // Don't try to sync any data from outbound "masternode" connections - // they are temporary and should be considered unreliable for a sync process. // Inbound connection this early is most likely a "masternode" connection // initiated from another node, so skip it too. if(pnode->fMasternode || (fMasternodeMode && pnode->fInbound)) continue; const CNetMsgMaker msgMaker(pnode->GetSendVersion()); // QUICK MODE (REGTEST ONLY!) if(Params().NetworkIDString() == CBaseChainParams::REGTEST) { if(nRequestedMasternodeAttempt <= 2) { mnodeman.DsegUpdate(pnode, connman); } else if(nRequestedMasternodeAttempt < 4) { //sync payment votes if(pnode->nVersion == 70018) { connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit())); //sync payment votes } else { connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC)); //sync payment votes } // connman.PushMessage(pnode, NetMsgType::MASTERNODEPAYMENTSYNC, nMnCount); //sync payment votes SendGovernanceSyncRequest(pnode, connman); } else { nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED; } nRequestedMasternodeAttempt++; connman.ReleaseNodeVector(vNodesCopy); return; } // NORMAL NETWORK MODE - TESTNET/MAINNET { if(netfulfilledman.HasFulfilledRequest(pnode->addr, "full-sync")) { // We already fully synced from this node recently, // disconnect to free this connection slot for another peer. pnode->fDisconnect = true; LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- disconnecting from recently synced peer=%d\n", pnode->GetId()); continue; } // INITIAL TIMEOUT if(nRequestedMasternodeAssets == MASTERNODE_SYNC_WAITING) { if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) { // At this point we know that: // a) there are peers (because we are looping on at least one of them); // b) we waited for at least MASTERNODE_SYNC_TIMEOUT_SECONDS since we reached // the headers tip the last time (i.e. since we switched from // MASTERNODE_SYNC_INITIAL to MASTERNODE_SYNC_WAITING and bumped time); // c) there were no blocks (UpdatedBlockTip, NotifyHeaderTip) or headers (AcceptedBlockHeader) // for at least MASTERNODE_SYNC_TIMEOUT_SECONDS. // We must be at the tip already, let's move to the next asset. SwitchToNextAsset(connman); } } // MNLIST : SYNC MASTERNODE LIST FROM OTHER CONNECTED CLIENTS if(nRequestedMasternodeAssets == MASTERNODE_SYNC_LIST) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped); // check for timeout first if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets); if (nRequestedMasternodeAttempt == 0) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName()); // there is no way we can continue without masternode list, fail here and try later Fail(); connman.ReleaseNodeVector(vNodesCopy); return; } SwitchToNextAsset(connman); connman.ReleaseNodeVector(vNodesCopy); return; } // request from three peers max if (nRequestedMasternodeAttempt > 2) { connman.ReleaseNodeVector(vNodesCopy); return; } // only request once from each peer if(netfulfilledman.HasFulfilledRequest(pnode->addr, "masternode-list-sync")) continue; netfulfilledman.AddFulfilledRequest(pnode->addr, "masternode-list-sync"); if (pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; nRequestedMasternodeAttempt++; mnodeman.DsegUpdate(pnode, connman); connman.ReleaseNodeVector(vNodesCopy); return; //this will cause each peer to get one request each six seconds for the various assets we need } // MNW : SYNC MASTERNODE PAYMENT VOTES FROM OTHER CONNECTED CLIENTS if(nRequestedMasternodeAssets == MASTERNODE_SYNC_MNW) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped); // check for timeout first // This might take a lot longer than MASTERNODE_SYNC_TIMEOUT_SECONDS due to new blocks, // but that should be OK and it should timeout eventually. if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets); if (nRequestedMasternodeAttempt == 0) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName()); // probably not a good idea to proceed without winner list Fail(); connman.ReleaseNodeVector(vNodesCopy); return; } SwitchToNextAsset(connman); connman.ReleaseNodeVector(vNodesCopy); return; } // check for data // if mnpayments already has enough blocks and votes, switch to the next asset // try to fetch data from at least two peers though if(nRequestedMasternodeAttempt > 1 && mnpayments.IsEnoughData()) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- found enough data\n", nTick, nRequestedMasternodeAssets); SwitchToNextAsset(connman); connman.ReleaseNodeVector(vNodesCopy); return; } // request from three peers max if (nRequestedMasternodeAttempt > 2) { connman.ReleaseNodeVector(vNodesCopy); return; } // only request once from each peer if(netfulfilledman.HasFulfilledRequest(pnode->addr, "masternode-payment-sync")) continue; netfulfilledman.AddFulfilledRequest(pnode->addr, "masternode-payment-sync"); if(pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; nRequestedMasternodeAttempt++; // ask node for all payment votes it has (new nodes will only return votes for future payments) //sync payment votes if(pnode->nVersion == 70018) { connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit())); } else { connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC)); } // connman.PushMessage(pnode, NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit()); // ask node for missing pieces only (old nodes will not be asked) mnpayments.RequestLowDataPaymentBlocks(pnode, connman); connman.ReleaseNodeVector(vNodesCopy); return; //this will cause each peer to get one request each six seconds for the various assets we need } // GOVOBJ : SYNC GOVERNANCE ITEMS FROM OUR PEERS if(nRequestedMasternodeAssets == MASTERNODE_SYNC_GOVERNANCE) { LogPrint(MCLog::GOV, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped); // check for timeout first if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets); if(nRequestedMasternodeAttempt == 0) { LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- WARNING: failed to sync %s\n", GetAssetName()); // it's kind of ok to skip this for now, hopefully we'll catch up later? } SwitchToNextAsset(connman); connman.ReleaseNodeVector(vNodesCopy); return; } // only request obj sync once from each peer, then request votes on per-obj basis if(netfulfilledman.HasFulfilledRequest(pnode->addr, "governance-sync")) { int nObjsLeftToAsk = governance.RequestGovernanceObjectVotes(pnode, connman); static int64_t nTimeNoObjectsLeft = 0; // check for data if(nObjsLeftToAsk == 0) { static int nLastTick = 0; static int nLastVotes = 0; if(nTimeNoObjectsLeft == 0) { // asked all objects for votes for the first time nTimeNoObjectsLeft = GetTime(); } // make sure the condition below is checked only once per tick if(nLastTick == nTick) continue; if(GetTime() - nTimeNoObjectsLeft > MASTERNODE_SYNC_TIMEOUT_SECONDS && governance.GetVoteCount() - nLastVotes < std::max(int(0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS) ) { // We already asked for all objects, waited for MASTERNODE_SYNC_TIMEOUT_SECONDS // after that and less then 0.01% or MASTERNODE_SYNC_TICK_SECONDS // (i.e. 1 per second) votes were recieved during the last tick. // We can be pretty sure that we are done syncing. LogPrint(MCLog::MN, "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- asked for all objects, nothing to do\n", nTick, nRequestedMasternodeAssets); // reset nTimeNoObjectsLeft to be able to use the same condition on resync nTimeNoObjectsLeft = 0; SwitchToNextAsset(connman); connman.ReleaseNodeVector(vNodesCopy); return; } nLastTick = nTick; nLastVotes = governance.GetVoteCount(); } continue; } netfulfilledman.AddFulfilledRequest(pnode->addr, "governance-sync"); if (pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) continue; nRequestedMasternodeAttempt++; SendGovernanceSyncRequest(pnode, connman); connman.ReleaseNodeVector(vNodesCopy); return; //this will cause each peer to get one request each six seconds for the various assets we need } } } // looped through all nodes, release them connman.ReleaseNodeVector(vNodesCopy); }
void PxrUsdKatanaReadPointInstancer( const UsdGeomPointInstancer& instancer, const PxrUsdKatanaUsdInPrivateData& data, PxrUsdKatanaAttrMap& instancerAttrMap, PxrUsdKatanaAttrMap& sourcesAttrMap, PxrUsdKatanaAttrMap& instancesAttrMap, PxrUsdKatanaAttrMap& inputAttrMap) { const double currentTime = data.GetCurrentTime(); PxrUsdKatanaReadXformable(instancer, data, instancerAttrMap); // Get primvars for setting later. Unfortunatley, the only way to get them // out of the attr map is to build it, which will cause its contents to be // cleared. We'll need to restore its contents before continuing. // FnKat::GroupAttribute instancerAttrs = instancerAttrMap.build(); FnKat::GroupAttribute primvarAttrs = instancerAttrs.getChildByName("geometry.arbitrary"); for (int64_t i = 0; i < instancerAttrs.getNumberOfChildren(); ++i) { instancerAttrMap.set(instancerAttrs.getChildName(i), instancerAttrs.getChildByIndex(i)); } instancerAttrMap.set("type", FnKat::StringAttribute("usd point instancer")); const std::string fileName = data.GetUsdInArgs()->GetFileName(); instancerAttrMap.set("info.usd.fileName", FnKat::StringAttribute(fileName)); FnKat::GroupAttribute inputAttrs = inputAttrMap.build(); const std::string katOutputPath = FnKat::StringAttribute( inputAttrs.getChildByName("outputLocationPath")).getValue("", false); if (katOutputPath.empty()) { _LogAndSetError(instancerAttrMap, "No output location path specified"); return; } // // Validate instancer data. // const std::string instancerPath = instancer.GetPath().GetString(); UsdStageWeakPtr stage = instancer.GetPrim().GetStage(); // Prototypes (required) // SdfPathVector protoPaths; instancer.GetPrototypesRel().GetTargets(&protoPaths); if (protoPaths.empty()) { _LogAndSetError(instancerAttrMap, "Instancer has no prototypes"); return; } _PathToPrimMap primCache; for (auto protoPath : protoPaths) { const UsdPrim &protoPrim = stage->GetPrimAtPath(protoPath); primCache[protoPath] = protoPrim; } // Indices (required) // VtIntArray protoIndices; if (!instancer.GetProtoIndicesAttr().Get(&protoIndices, currentTime)) { _LogAndSetError(instancerAttrMap, "Instancer has no prototype indices"); return; } const size_t numInstances = protoIndices.size(); if (numInstances == 0) { _LogAndSetError(instancerAttrMap, "Instancer has no prototype indices"); return; } for (auto protoIndex : protoIndices) { if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size()) { _LogAndSetError(instancerAttrMap, TfStringPrintf( "Out of range prototype index %d", protoIndex)); return; } } // Mask (optional) // std::vector<bool> pruneMaskValues = instancer.ComputeMaskAtTime(currentTime); if (!pruneMaskValues.empty() and pruneMaskValues.size() != numInstances) { _LogAndSetError(instancerAttrMap, "Mismatch in length of indices and mask"); return; } // Positions (required) // UsdAttribute positionsAttr = instancer.GetPositionsAttr(); if (!positionsAttr.HasValue()) { _LogAndSetError(instancerAttrMap, "Instancer has no positions"); return; } // // Compute instance transform matrices. // const double timeCodesPerSecond = stage->GetTimeCodesPerSecond(); // Gather frame-relative sample times and add them to the current time to // generate absolute sample times. // const std::vector<double> &motionSampleTimes = data.GetMotionSampleTimes(positionsAttr); const size_t sampleCount = motionSampleTimes.size(); std::vector<UsdTimeCode> sampleTimes(sampleCount); for (size_t a = 0; a < sampleCount; ++a) { sampleTimes[a] = UsdTimeCode(currentTime + motionSampleTimes[a]); } // Get velocityScale from the opArgs. // float velocityScale = FnKat::FloatAttribute( inputAttrs.getChildByName("opArgs.velocityScale")).getValue(1.0f, false); // XXX Replace with UsdGeomPointInstancer::ComputeInstanceTransformsAtTime. // std::vector<std::vector<GfMatrix4d>> xformSamples(sampleCount); const size_t numXformSamples = _ComputeInstanceTransformsAtTime(xformSamples, instancer, sampleTimes, UsdTimeCode(currentTime), timeCodesPerSecond, numInstances, positionsAttr, velocityScale); if (numXformSamples == 0) { _LogAndSetError(instancerAttrMap, "Could not compute " "sample/topology-invarying instance " "transform matrix"); return; } // // Compute prototype bounds. // bool aggregateBoundsValid = false; std::vector<double> aggregateBounds; // XXX Replace with UsdGeomPointInstancer::ComputeExtentAtTime. // VtVec3fArray aggregateExtent; if (_ComputeExtentAtTime( aggregateExtent, data.GetUsdInArgs(), xformSamples, motionSampleTimes, protoIndices, protoPaths, primCache, pruneMaskValues)) { aggregateBoundsValid = true; aggregateBounds.resize(6); aggregateBounds[0] = aggregateExtent[0][0]; // min x aggregateBounds[1] = aggregateExtent[1][0]; // max x aggregateBounds[2] = aggregateExtent[0][1]; // min y aggregateBounds[3] = aggregateExtent[1][1]; // max y aggregateBounds[4] = aggregateExtent[0][2]; // min z aggregateBounds[5] = aggregateExtent[1][2]; // max z } // // Build sources. Keep track of which instances use them. // FnGeolibServices::StaticSceneCreateOpArgsBuilder sourcesBldr(false); std::vector<int> instanceIndices; instanceIndices.reserve(numInstances); std::vector<std::string> instanceSources; instanceSources.reserve(protoPaths.size()); std::map<std::string, int> instanceSourceIndexMap; std::vector<int> omitList; omitList.reserve(numInstances); std::map<SdfPath, std::string> protoPathsToKatPaths; for (size_t i = 0; i < numInstances; ++i) { int index = protoIndices[i]; // Check to see if we are pruned. // bool isPruned = (!pruneMaskValues.empty() and pruneMaskValues[i] == false); if (isPruned) { omitList.push_back(i); } const SdfPath &protoPath = protoPaths[index]; // Compute the full (Katana) path to this prototype. // std::string fullProtoPath; std::map<SdfPath, std::string>::const_iterator pptkpIt = protoPathsToKatPaths.find(protoPath); if (pptkpIt != protoPathsToKatPaths.end()) { fullProtoPath = pptkpIt->second; } else { _PathToPrimMap::const_iterator pcIt = primCache.find(protoPath); const UsdPrim &protoPrim = pcIt->second; if (!protoPrim) { continue; } // Determine where (what path) to start building the prototype prim // such that its material bindings will be preserved. This could be // the prototype path itself or an ancestor path. // SdfPathVector commonPrefixes; UsdRelationship materialBindingsRel = UsdShadeMaterial::GetBindingRel(protoPrim); auto assetAPI = UsdModelAPI(protoPrim); std::string assetName; bool isReferencedModelPrim = assetAPI.IsModel() and assetAPI.GetAssetName(&assetName); if (!materialBindingsRel or isReferencedModelPrim) { // The prim has no material bindings or is a referenced model // prim (meaning that materials are defined below it); start // building at the prototype path. // commonPrefixes.push_back(protoPath); } else { SdfPathVector materialPaths; materialBindingsRel.GetForwardedTargets(&materialPaths); for (auto materialPath : materialPaths) { const SdfPath &commonPrefix = protoPath.GetCommonPrefix(materialPath); if (commonPrefix.GetString() == "/") { // XXX Unhandled case. // The prototype prim and its material are not under the // same parent; start building at the prototype path // (although it is likely that bindings will be broken). // commonPrefixes.push_back(protoPath); } else { // Start building at the common ancestor between the // prototype prim and its material. // commonPrefixes.push_back(commonPrefix); } } } // XXX Unhandled case. // We'll use the first common ancestor even if there is more than // one (which shouldn't appen if the prototype prim and its bindings // are under the same parent). // SdfPath::RemoveDescendentPaths(&commonPrefixes); const std::string buildPath = commonPrefixes[0].GetString(); // See if the path is a child of the point instancer. If so, we'll // match its hierarchy. If not, we'll put it under a 'prototypes' // group. // std::string relBuildPath; if (pystring::startswith(buildPath, instancerPath + "/")) { relBuildPath = pystring::replace( buildPath, instancerPath + "/", ""); } else { relBuildPath = "prototypes/" + FnGeolibUtil::Path::GetLeafName(buildPath); } // Start generating the full path to the prototype. // fullProtoPath = katOutputPath + "/" + relBuildPath; // Make the common ancestor our instance source. // sourcesBldr.setAttrAtLocation(relBuildPath, "type", FnKat::StringAttribute("instance source")); // Author a tracking attr. // sourcesBldr.setAttrAtLocation(relBuildPath, "info.usd.sourceUsdPath", FnKat::StringAttribute(buildPath)); // Tell the BuildIntermediate op to start building at the common // ancestor. // sourcesBldr.setAttrAtLocation(relBuildPath, "usdPrimPath", FnKat::StringAttribute(buildPath)); sourcesBldr.setAttrAtLocation(relBuildPath, "usdPrimName", FnKat::StringAttribute("geo")); if (protoPath.GetString() != buildPath) { // Finish generating the full path to the prototype. // fullProtoPath = fullProtoPath + "/geo" + pystring::replace( protoPath.GetString(), buildPath, ""); } // Create a mapping that will link the instance's index to its // prototype's full path. // instanceSourceIndexMap[fullProtoPath] = instanceSources.size(); instanceSources.push_back(fullProtoPath); // Finally, store the full path in the map so we won't have to do // this work again. // protoPathsToKatPaths[protoPath] = fullProtoPath; } instanceIndices.push_back(instanceSourceIndexMap[fullProtoPath]); } // // Build instances. // FnGeolibServices::StaticSceneCreateOpArgsBuilder instancesBldr(false); instancesBldr.createEmptyLocation("instances", "instance array"); instancesBldr.setAttrAtLocation("instances", "geometry.instanceSource", FnKat::StringAttribute(instanceSources, 1)); instancesBldr.setAttrAtLocation("instances", "geometry.instanceIndex", FnKat::IntAttribute(&instanceIndices[0], instanceIndices.size(), 1)); FnKat::DoubleBuilder instanceMatrixBldr(16); for (size_t a = 0; a < numXformSamples; ++a) { double relSampleTime = motionSampleTimes[a]; // Shove samples into the builder at the frame-relative sample time. If // motion is backwards, make sure to reverse time samples. std::vector<double> &matVec = instanceMatrixBldr.get( data.IsMotionBackward() ? PxrUsdKatanaUtils::ReverseTimeSample(relSampleTime) : relSampleTime); matVec.reserve(16 * numInstances); for (size_t i = 0; i < numInstances; ++i) { GfMatrix4d instanceXform = xformSamples[a][i]; const double *matArray = instanceXform.GetArray(); for (int j = 0; j < 16; ++j) { matVec.push_back(matArray[j]); } } } instancesBldr.setAttrAtLocation("instances", "geometry.instanceMatrix", instanceMatrixBldr.build()); if (!omitList.empty()) { instancesBldr.setAttrAtLocation("instances", "geometry.omitList", FnKat::IntAttribute(&omitList[0], omitList.size(), 1)); } instancesBldr.setAttrAtLocation("instances", "geometry.pointInstancerId", FnKat::StringAttribute(katOutputPath)); // // Transfer primvars. // FnKat::GroupBuilder instancerPrimvarsBldr; FnKat::GroupBuilder instancesPrimvarsBldr; for (int64_t i = 0; i < primvarAttrs.getNumberOfChildren(); ++i) { const std::string primvarName = primvarAttrs.getChildName(i); // Use "point" scope for the instancer. instancerPrimvarsBldr.set(primvarName, primvarAttrs.getChildByIndex(i)); instancerPrimvarsBldr.set(primvarName + ".scope", FnKat::StringAttribute("point")); // User "primitive" scope for the instances. instancesPrimvarsBldr.set(primvarName, primvarAttrs.getChildByIndex(i)); instancesPrimvarsBldr.set(primvarName + ".scope", FnKat::StringAttribute("primitive")); } instancerAttrMap.set("geometry.arbitrary", instancerPrimvarsBldr.build()); instancesBldr.setAttrAtLocation("instances", "geometry.arbitrary", instancesPrimvarsBldr.build()); // // Set the final aggregate bounds. // if (aggregateBoundsValid) { instancerAttrMap.set("bound", FnKat::DoubleAttribute(&aggregateBounds[0], 6, 2)); } // // Set proxy attrs. // instancerAttrMap.set("proxies", PxrUsdKatanaUtils::GetViewerProxyAttr(data)); // // Transfer builder results to our attr maps. // FnKat::GroupAttribute sourcesAttrs = sourcesBldr.build(); for (int64_t i = 0; i < sourcesAttrs.getNumberOfChildren(); ++i) { sourcesAttrMap.set( sourcesAttrs.getChildName(i), sourcesAttrs.getChildByIndex(i)); } FnKat::GroupAttribute instancesAttrs = instancesBldr.build(); for (int64_t i = 0; i < instancesAttrs.getNumberOfChildren(); ++i) { instancesAttrMap.set( instancesAttrs.getChildName(i), instancesAttrs.getChildByIndex(i)); } }