bool UsdGeomCollectionAPI::AppendTarget( const SdfPath &target, const VtIntArray &faceIndices /* =VtIntArray() */, const UsdTimeCode &time /* =UsdTimeCode::Default() */) const { if (target.IsEmpty()) { TF_CODING_ERROR("Cannot add empty target to collection '%s' on " "prim <%s>.", _name.GetText(), GetPath().GetText()); return false; } bool hasFaceCountsAtTime = true; if (time != UsdTimeCode::Default()) { UsdAttribute targetFaceCountsAttr = GetTargetFaceCountsAttr(); double lower=0., upper=0.; bool hasTimeSamples=false; if (targetFaceCountsAttr.GetBracketingTimeSamples(time.GetValue(), &lower, &upper, &hasTimeSamples)) { hasFaceCountsAtTime = (lower==upper && lower==time.GetValue()); } } VtIntArray targetFaceCounts, targetFaceIndices; if (hasFaceCountsAtTime) { GetTargetFaceCounts(&targetFaceCounts, time); GetTargetFaceIndices(&targetFaceIndices, time); } SdfPathVector targets; GetTargets(&targets); // If there are no existing face restrictions and no face-restriction is // specified on the current target, simly add the target and return. if (targetFaceCounts.empty() && targetFaceIndices.empty() && faceIndices.empty()) { // We can simply add the target here to the relationship here since // there are no companion non-list-edited integer arrays. return CreateTargetsRel().AppendTarget(target); } if (targetFaceCounts.empty() && !targetFaceIndices.empty()) { TF_CODING_ERROR("targetFaceCounts is empty, but targetFaceIndices " "is not, for the collection '%s' belonging to prim <%s>.", _name.GetText(), GetPath().GetText()); return false; } if (targetFaceCounts.empty() && !faceIndices.empty()) { for (size_t i = 0 ; i < targets.size(); i++) targetFaceCounts.push_back(0); } targetFaceCounts.push_back(faceIndices.size()); targetFaceIndices.reserve(targetFaceIndices.size() + faceIndices.size()); TF_FOR_ALL(it, faceIndices) { targetFaceIndices.push_back(*it); }
std::vector<bool> UsdGeomPointInstancer::ComputeMaskAtTime(UsdTimeCode time, VtInt64Array const *ids) const { VtInt64Array idVals, invisedIds; std::vector<bool> mask; SdfInt64ListOp inactiveIdsListOp; // XXX Note we could be doing all three fetches in parallel GetPrim().GetMetadata(UsdGeomTokens->inactiveIds, &inactiveIdsListOp); std::vector<int64_t> inactiveIds = inactiveIdsListOp.GetExplicitItems(); GetInvisibleIdsAttr().Get(&invisedIds, time); if (inactiveIds.size() > 0 || invisedIds.size() > 0){ bool anyPruned = false; std::set<int64_t> maskedIds(inactiveIds.begin(), inactiveIds.end()); maskedIds.insert(invisedIds.begin(), invisedIds.end()); if (!ids){ if (GetIdsAttr().Get(&idVals, time)){ ids = &idVals; } if (!ids){ VtIntArray protoIndices; if (!GetProtoIndicesAttr().Get(&protoIndices, time)){ // not a functional PointInstancer... just return // trivial pass return mask; } size_t numInstances = protoIndices.size(); idVals.reserve(numInstances); for (size_t i = 0; i < numInstances; ++i) { idVals.push_back(i); } ids = &idVals; } } mask.reserve(ids->size()); for (int64_t id : *ids){ bool pruned = (maskedIds.find(id) != maskedIds.end()); anyPruned = anyPruned || pruned; mask.push_back(!pruned); } if (!anyPruned){ mask.resize(0); } } return mask; }
/*static*/ int HdMeshTopology::ComputeNumPoints(VtIntArray const &verts) { HD_TRACE_FUNCTION(); // compute numPoints from topology indices int numIndices = verts.size(); int numPoints = -1; int const * vertsPtr = verts.cdata(); for (int i= 0;i <numIndices; ++i) { // find the max vertex index in face verts numPoints = std::max(numPoints, vertsPtr[i]); } // numPoints = max vertex index + 1 return numPoints + 1; }
void PxOsdMeshTopology::SetHoleIndices(VtIntArray const &holeIndices) { if (TfDebug::IsEnabled(0)) { // make sure faceIndices is given in ascending order. int nFaceIndices = holeIndices.size(); for (int i = 1; i < nFaceIndices; ++i) { if (holeIndices[i] <= holeIndices[i-1]) { // XXX: would be better to print the prim name. TF_WARN("hole face indices are not in ascending order."); return; } } } _holeIndices = holeIndices; }
PXR_NAMESPACE_OPEN_SCOPE /// "Flattens out" the given \p interpolation onto face-vertexes of the given /// \p meshFn, returning a mapping of the face-vertex indices to data indices. /// Takes into account data authored sparsely if \p assignmentIndices and /// \p unauthoredValuesIndex are specified. static MIntArray _GetMayaFaceVertexAssignmentIds( const MFnMesh& meshFn, const TfToken& interpolation, const VtIntArray& assignmentIndices, const int unauthoredValuesIndex) { MIntArray valueIds(meshFn.numFaceVertices(), -1); MItMeshFaceVertex itFV(meshFn.object()); unsigned int fvi = 0; for (itFV.reset(); !itFV.isDone(); itFV.next(), ++fvi) { int valueId = 0; if (interpolation == UsdGeomTokens->constant) { valueId = 0; } else if (interpolation == UsdGeomTokens->uniform) { valueId = itFV.faceId(); } else if (interpolation == UsdGeomTokens->vertex) { valueId = itFV.vertId(); } else if (interpolation == UsdGeomTokens->faceVarying) { valueId = fvi; } if (static_cast<size_t>(valueId) < assignmentIndices.size()) { // The data is indexed, so consult the indices array for the // correct index into the data. valueId = assignmentIndices[valueId]; if (valueId == unauthoredValuesIndex) { // This component had no authored value, so leave it unassigned. continue; } } valueIds[fvi] = valueId; } return valueIds; }
/* static */ bool UsdMayaTranslatorMesh::_AssignColorSetPrimvarToMesh( const UsdGeomMesh& primSchema, const UsdGeomPrimvar& primvar, MFnMesh& meshFn) { const TfToken& primvarName = primvar.GetPrimvarName(); const SdfValueTypeName& typeName = primvar.GetTypeName(); MString colorSetName(primvarName.GetText()); // If the primvar is displayOpacity and it is a FloatArray, check if // displayColor is authored. If not, we'll import this 'displayOpacity' // primvar as a 'displayColor' color set. This supports cases where the // user created a single channel value for displayColor. // Note that if BOTH displayColor and displayOpacity are authored, they will // be imported as separate color sets. We do not attempt to combine them // into a single color set. if (primvarName == UsdMayaMeshColorSetTokens->DisplayOpacityColorSetName && typeName == SdfValueTypeNames->FloatArray) { if (!UsdMayaRoundTripUtil::IsAttributeUserAuthored(primSchema.GetDisplayColorPrimvar())) { colorSetName = UsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetText(); } } // We'll need to convert colors from linear to display if this color set is // for display colors. const bool isDisplayColor = (colorSetName == UsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetText()); // Get the raw data before applying any indexing. We'll only populate one // of these arrays based on the primvar's typeName, and we'll also set the // color representation so we know which array to use later. VtFloatArray alphaArray; VtVec3fArray rgbArray; VtVec4fArray rgbaArray; MFnMesh::MColorRepresentation colorRep; size_t numValues = 0; MStatus status = MS::kSuccess; if (typeName == SdfValueTypeNames->FloatArray) { colorRep = MFnMesh::kAlpha; if (!primvar.Get(&alphaArray) || alphaArray.empty()) { status = MS::kFailure; } else { numValues = alphaArray.size(); } } else if (typeName == SdfValueTypeNames->Float3Array || typeName == SdfValueTypeNames->Color3fArray) { colorRep = MFnMesh::kRGB; if (!primvar.Get(&rgbArray) || rgbArray.empty()) { status = MS::kFailure; } else { numValues = rgbArray.size(); } } else if (typeName == SdfValueTypeNames->Float4Array || typeName == SdfValueTypeNames->Color4fArray) { colorRep = MFnMesh::kRGBA; if (!primvar.Get(&rgbaArray) || rgbaArray.empty()) { status = MS::kFailure; } else { numValues = rgbaArray.size(); } } else { TF_WARN("Unsupported color set primvar type '%s' for primvar '%s' on " "mesh: %s", typeName.GetAsToken().GetText(), primvarName.GetText(), primvar.GetAttr().GetPrimPath().GetText()); return false; } if (status != MS::kSuccess || numValues == 0) { TF_WARN("Could not read color set values from primvar '%s' on mesh: %s", primvarName.GetText(), primvar.GetAttr().GetPrimPath().GetText()); return false; } VtIntArray assignmentIndices; int unauthoredValuesIndex = -1; if (primvar.GetIndices(&assignmentIndices)) { // The primvar IS indexed, so the indices array is what determines the // number of color values. numValues = assignmentIndices.size(); unauthoredValuesIndex = primvar.GetUnauthoredValuesIndex(); } // Go through the color data and translate the values into MColors in the // colorArray, taking into consideration that indexed data may have been // authored sparsely. If the assignmentIndices array is empty then the data // is NOT indexed. // Note that with indexed data, the data is added to the arrays in ascending // component ID order according to the primvar's interpolation (ascending // face ID for uniform interpolation, ascending vertex ID for vertex // interpolation, etc.). This ordering may be different from the way the // values are ordered in the primvar. Because of this, we recycle the // assignmentIndices array as we go to store the new mapping from component // index to color index. MColorArray colorArray; for (size_t i = 0; i < numValues; ++i) { int valueIndex = i; if (i < assignmentIndices.size()) { // The data is indexed, so consult the indices array for the // correct index into the data. valueIndex = assignmentIndices[i]; if (valueIndex == unauthoredValuesIndex) { // This component is unauthored, so just update the // mapping in assignmentIndices and then skip the value. // We don't actually use the value at the unassigned index. assignmentIndices[i] = -1; continue; } // We'll be appending a new value, so the current length of the // array gives us the new value's index. assignmentIndices[i] = colorArray.length(); } GfVec4f colorValue(1.0); switch(colorRep) { case MFnMesh::kAlpha: colorValue[3] = alphaArray[valueIndex]; break; case MFnMesh::kRGB: colorValue[0] = rgbArray[valueIndex][0]; colorValue[1] = rgbArray[valueIndex][1]; colorValue[2] = rgbArray[valueIndex][2]; break; case MFnMesh::kRGBA: colorValue[0] = rgbaArray[valueIndex][0]; colorValue[1] = rgbaArray[valueIndex][1]; colorValue[2] = rgbaArray[valueIndex][2]; colorValue[3] = rgbaArray[valueIndex][3]; break; default: break; } if (isDisplayColor) { colorValue = UsdMayaColorSpace::ConvertLinearToMaya(colorValue); } MColor mColor(colorValue[0], colorValue[1], colorValue[2], colorValue[3]); colorArray.append(mColor); } // colorArray now stores all of the values and any unassigned components // have had their indices set to -1, so update the unauthored values index. unauthoredValuesIndex = -1; const bool clamped = UsdMayaRoundTripUtil::IsPrimvarClamped(primvar); status = meshFn.createColorSet(colorSetName, nullptr, clamped, colorRep); if (status != MS::kSuccess) { TF_WARN("Unable to create color set '%s' for mesh: %s", colorSetName.asChar(), meshFn.fullPathName().asChar()); return false; } // Create colors on the mesh from the values we collected out of the // primvar. We'll assign mesh components to these values below. status = meshFn.setColors(colorArray, &colorSetName, colorRep); if (status != MS::kSuccess) { TF_WARN("Unable to set color data on color set '%s' for mesh: %s", colorSetName.asChar(), meshFn.fullPathName().asChar()); return false; } const TfToken& interpolation = primvar.GetInterpolation(); // Build an array of value assignments for each face vertex in the mesh. // Any assignments left as -1 will not be assigned a value. MIntArray colorIds = _GetMayaFaceVertexAssignmentIds(meshFn, interpolation, assignmentIndices, unauthoredValuesIndex); status = meshFn.assignColors(colorIds, &colorSetName); if (status != MS::kSuccess) { TF_WARN("Could not assign color values to color set '%s' on mesh: %s", colorSetName.asChar(), meshFn.fullPathName().asChar()); return false; } return true; }
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)); } }
HdBufferSourceSharedPtr _TriangulateFaceVarying(HdBufferSourceSharedPtr const &source, VtIntArray const &faceVertexCounts, VtIntArray const &holeFaces, bool flip, SdfPath const &id) { T const *srcPtr = reinterpret_cast<T const *>(source->GetData()); int numElements = source->GetNumElements(); // CPU face-varying triangulation bool invalidTopology = false; int numFVarValues = 0; int holeIndex = 0; int numHoleFaces = holeFaces.size(); for (int i = 0; i < faceVertexCounts.size(); ++i) { int nv = faceVertexCounts[i] - 2; if (nv < 1) { // skip degenerated face invalidTopology = true; } else if (holeIndex < numHoleFaces and holeFaces[holeIndex] == i) { // skip hole face ++holeIndex; } else { numFVarValues += 3 * nv; } } if (invalidTopology) { TF_WARN("degenerated face found [%s]", id.GetText()); invalidTopology = false; } VtArray<T> results(numFVarValues); // reset holeIndex holeIndex = 0; int dstIndex = 0; for (int i = 0, v = 0; i < faceVertexCounts.size(); ++i) { int nVerts = faceVertexCounts[i]; if (nVerts < 3) { // Skip degenerate faces. } else if (holeIndex < numHoleFaces and holeFaces[holeIndex] == i) { // Skip hole faces. ++holeIndex; } else { // triangulate. // apply same triangulation as index does for (int j=0; j < nVerts-2; ++j) { if (not _FanTriangulate(&results[dstIndex], srcPtr, v, j, numElements, flip)) { invalidTopology = true; } dstIndex += 3; } } v += nVerts; } if (invalidTopology) { TF_WARN("numVerts and verts are incosistent [%s]", id.GetText()); } return HdBufferSourceSharedPtr(new HdVtBufferSource( source->GetName(), VtValue(results))); }
bool UsdGeomPointInstancer::ComputeExtentAtTime( VtVec3fArray* extent, const UsdTimeCode time, const UsdTimeCode baseTime) const { if (!extent) { TF_WARN("%s -- null container passed to ComputeExtentAtTime()", GetPrim().GetPath().GetText()); return false; } VtIntArray protoIndices; if (!GetProtoIndicesAttr().Get(&protoIndices, time)) { TF_WARN("%s -- no prototype indices", GetPrim().GetPath().GetText()); return false; } const std::vector<bool> mask = ComputeMaskAtTime(time); if (!mask.empty() && mask.size() != protoIndices.size()) { TF_WARN("%s -- mask.size() [%zu] != protoIndices.size() [%zu]", GetPrim().GetPath().GetText(), mask.size(), protoIndices.size()); return false; } const UsdRelationship prototypes = GetPrototypesRel(); SdfPathVector protoPaths; if (!prototypes.GetTargets(&protoPaths) || protoPaths.empty()) { TF_WARN("%s -- no prototypes", GetPrim().GetPath().GetText()); return false; } // verify that all the protoIndices are in bounds. TF_FOR_ALL(iter, protoIndices) { const int protoIndex = *iter; if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size()) { TF_WARN("%s -- invalid prototype index: %d. Should be in [0, %zu)", GetPrim().GetPath().GetText(), protoIndex, protoPaths.size()); return false; } } // Note that we do NOT apply any masking when computing the instance // transforms. This is so that for a particular instance we can determine // both its transform and its prototype. Otherwise, the instanceTransforms // array would have masked instances culled out and we would lose the // mapping to the prototypes. // Masked instances will be culled before being applied to the extent below. VtMatrix4dArray instanceTransforms; if (!ComputeInstanceTransformsAtTime(&instanceTransforms, time, baseTime, IncludeProtoXform, IgnoreMask)) { TF_WARN("%s -- could not compute instance transforms", GetPrim().GetPath().GetText()); return false; } UsdStageWeakPtr stage = GetPrim().GetStage(); const TfTokenVector purposes { UsdGeomTokens->default_, UsdGeomTokens->proxy, UsdGeomTokens->render }; UsdGeomBBoxCache bboxCache(time, purposes); bboxCache.SetTime(time); GfRange3d extentRange; for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) { if (!mask.empty() && !mask[instanceId]) { continue; } const int protoIndex = protoIndices[instanceId]; const SdfPath& protoPath = protoPaths[protoIndex]; const UsdPrim& protoPrim = stage->GetPrimAtPath(protoPath); // Get the prototype bounding box. GfBBox3d thisBounds = bboxCache.ComputeUntransformedBound(protoPrim); // Apply the instance transform. thisBounds.Transform(instanceTransforms[instanceId]); extentRange.UnionWith(thisBounds.ComputeAlignedRange()); } const GfVec3d extentMin = extentRange.GetMin(); const GfVec3d extentMax = extentRange.GetMax(); *extent = VtVec3fArray(2); (*extent)[0] = GfVec3f(extentMin[0], extentMin[1], extentMin[2]); (*extent)[1] = GfVec3f(extentMax[0], extentMax[1], extentMax[2]); return true; }
bool UsdGeomPointInstancer::ComputeInstanceTransformsAtTime( VtArray<GfMatrix4d>* xforms, const UsdTimeCode time, const UsdTimeCode baseTime, const ProtoXformInclusion doProtoXforms, const MaskApplication applyMask) const { // XXX: Need to add handling of velocities/angularVelocities and baseTime. (void)baseTime; if (!xforms) { TF_WARN("%s -- null container passed to ComputeInstanceTransformsAtTime()", GetPrim().GetPath().GetText()); return false; } VtIntArray protoIndices; if (!GetProtoIndicesAttr().Get(&protoIndices, time)) { TF_WARN("%s -- no prototype indices", GetPrim().GetPath().GetText()); return false; } if (protoIndices.empty()) { xforms->clear(); return true; } VtVec3fArray positions; if (!GetPositionsAttr().Get(&positions, time)) { TF_WARN("%s -- no positions", GetPrim().GetPath().GetText()); return false; } if (positions.size() != protoIndices.size()) { TF_WARN("%s -- positions.size() [%zu] != protoIndices.size() [%zu]", GetPrim().GetPath().GetText(), positions.size(), protoIndices.size()); return false; } VtVec3fArray scales; GetScalesAttr().Get(&scales, time); if (!scales.empty() && scales.size() != protoIndices.size()) { TF_WARN("%s -- scales.size() [%zu] != protoIndices.size() [%zu]", GetPrim().GetPath().GetText(), scales.size(), protoIndices.size()); return false; } VtQuathArray orientations; GetOrientationsAttr().Get(&orientations, time); if (!orientations.empty() && orientations.size() != protoIndices.size()) { TF_WARN("%s -- orientations.size() [%zu] != protoIndices.size() [%zu]", GetPrim().GetPath().GetText(), orientations.size(), protoIndices.size()); return false; } // If we're going to include the prototype transforms, verify that we have // prototypes and that all of the protoIndices are in bounds. SdfPathVector protoPaths; if (doProtoXforms == IncludeProtoXform) { const UsdRelationship prototypes = GetPrototypesRel(); if (!prototypes.GetTargets(&protoPaths) || protoPaths.empty()) { TF_WARN("%s -- no prototypes", GetPrim().GetPath().GetText()); return false; } TF_FOR_ALL(iter, protoIndices) { const int protoIndex = *iter; if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size()) { TF_WARN("%s -- invalid prototype index: %d. Should be in [0, %zu)", GetPrim().GetPath().GetText(), protoIndex, protoPaths.size()); return false; } } } // Compute the mask only if applyMask says we should, otherwise we leave // mask empty so that its application below is a no-op. std::vector<bool> mask; if (applyMask == ApplyMask) { mask = ComputeMaskAtTime(time); if (!mask.empty() && mask.size() != protoIndices.size()) { TF_WARN("%s -- mask.size() [%zu] != protoIndices.size() [%zu]", GetPrim().GetPath().GetText(), mask.size(), protoIndices.size()); return false; } } UsdStageWeakPtr stage = GetPrim().GetStage(); UsdGeomXformCache xformCache(time); xforms->assign(protoIndices.size(), GfMatrix4d(1.0)); for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) { if (!mask.empty() && !mask[instanceId]) { continue; } GfTransform instanceTransform; if (!scales.empty()) { instanceTransform.SetScale(scales[instanceId]); } if (!orientations.empty()) { instanceTransform.SetRotation(GfRotation(orientations[instanceId])); } instanceTransform.SetTranslation(positions[instanceId]); GfMatrix4d protoXform(1.0); if (doProtoXforms == IncludeProtoXform) { const int protoIndex = protoIndices[instanceId]; const SdfPath& protoPath = protoPaths[protoIndex]; const UsdPrim& protoPrim = stage->GetPrimAtPath(protoPath); if (protoPrim) { // Get the prototype's local transformation. bool resetsXformStack; protoXform = xformCache.GetLocalTransformation(protoPrim, &resetsXformStack); } } (*xforms)[instanceId] = protoXform * instanceTransform.GetMatrix(); } return ApplyMaskToArray(mask, xforms); }
inline bool TopologyRefinerFactory<PXR_NS::Converter>::assignComponentTags( Far::TopologyRefiner & refiner, PXR_NS::Converter const & converter) { PXR_NAMESPACE_USING_DIRECTIVE PxOsdMeshTopology const & topology = converter.topology; PxOsdSubdivTags const & tags = topology.GetSubdivTags(); // // creases // // The sharpnesses can be defined either per-crease or per-edge. VtIntArray const creaseIndices = tags.GetCreaseIndices(), creaseLengths = tags.GetCreaseLengths(); VtFloatArray const creaseWeights = tags.GetCreaseWeights(); size_t numCreaseSets = creaseLengths.size(); bool perEdgeCrease = creaseWeights.size() != numCreaseSets; if (perEdgeCrease) { // validate per-edge crease. int numEdges = 0; for (size_t i = 0; i < numCreaseSets; ++i) { numEdges += creaseLengths[i] - 1; } if (creaseWeights.size() != static_cast<size_t>(numEdges)) { TF_WARN("Invalid length of crease sharpnesses (%s)\n", converter.name.GetText()); numCreaseSets = 0; } } for (size_t i=0, cindex=0, sindex=0; i < numCreaseSets; ++i) { int numSegments = creaseLengths[i] - 1; for (int j = 0; j < numSegments; ++j) { int v0 = creaseIndices[cindex+j], v1 = creaseIndices[cindex+j+1]; OpenSubdiv::Vtr::Index edge = refiner.GetLevel(0).FindEdge(v0, v1); if (edge==OpenSubdiv::Vtr::INDEX_INVALID) { TF_WARN("Set edge sharpness cannot find edge (%d-%d) (%s)", v0, v1, converter.name.GetText()); } else { setBaseEdgeSharpness(refiner, edge, std::max(0.0f, creaseWeights[sindex])); } if (perEdgeCrease) ++sindex; } if (!perEdgeCrease) ++sindex; cindex += creaseLengths[i]; } // // corners // VtIntArray const cornerIndices = tags.GetCornerIndices(); VtFloatArray const cornerWeights = tags.GetCornerWeights(); size_t numCorners = cornerIndices.size(); if (cornerWeights.size() != numCorners) { TF_WARN("Invalid length of corner sharpnesses at prim %s\n", converter.name.GetText()); numCorners = 0; } for (size_t i=0; i < numCorners; ++i) { int vert = cornerIndices[i]; if (vert >= 0 && vert < refiner.GetLevel(0).GetNumVertices()) { setBaseVertexSharpness(refiner, vert, std::max(0.0f, cornerWeights[i])); } else { TF_WARN("Set vertex sharpness cannot find vertex (%d) (%s)", vert, converter.name.GetText()); } } // // holes // VtIntArray const holeIndices = tags.GetHoleIndices(); int numHoles = holeIndices.size(); for (int i=0; i < numHoles; ++i) { int face = holeIndices[i]; if (face >= 0 && face < refiner.GetLevel(0).GetNumFaces()) { setBaseFaceHole(refiner, face, true); } else { TF_WARN("Set hole cannot find face (%d) (%s)", face, converter.name.GetText()); } } return true; }
void UsdMayaPrimReaderSkelRoot::PostReadSubtree( UsdMayaPrimReaderContext* context) { UsdSkelRoot skelRoot(_GetArgs().GetUsdPrim()); if (!TF_VERIFY(skelRoot)) return; // Compute skel bindings and create skin clusters for bound skels // We do this in a post-subtree stage to ensure that any skinnable // prims we produce skin clusters for have been processed first. _cache.Populate(skelRoot); std::vector<UsdSkelBinding> bindings; if (!_cache.ComputeSkelBindings(skelRoot, &bindings)) { return; } for (const UsdSkelBinding& binding : bindings) { if (binding.GetSkinningTargets().empty()) continue; if (const UsdSkelSkeletonQuery& skelQuery = _cache.GetSkelQuery(binding.GetSkeleton())) { VtArray<MObject> joints; if (!UsdMayaTranslatorSkel::GetJoints( skelQuery, context, &joints)) { continue; } for (const auto& skinningQuery : binding.GetSkinningTargets()) { const UsdPrim& skinnedPrim = skinningQuery.GetPrim(); // Get an ordering of the joints that matches the ordering of // the binding. VtArray<MObject> skinningJoints; if (!skinningQuery.GetMapper()) { skinningJoints = joints; } else { // TODO: // UsdSkelAnimMapper currently only supports remapping // of Sdf value types, so we can't easily use it here. // For now, we can delegate remapping behavior by // remapping ordered joint indices. VtIntArray indices(joints.size()); for (size_t i = 0; i < joints.size(); ++i) indices[i] = i; VtIntArray remappedIndices; if (!skinningQuery.GetMapper()->Remap( indices, &remappedIndices)) { continue; } skinningJoints.resize(remappedIndices.size()); for (size_t i = 0; i < remappedIndices.size(); ++i) { int index = remappedIndices[i]; if (index >= 0 && static_cast<size_t>(index) < joints.size()) { skinningJoints[i] = joints[index]; } } } MObject bindPose = UsdMayaTranslatorSkel::GetBindPose(skelQuery, context); // Add a skin cluster to skin this prim. UsdMayaTranslatorSkel::CreateSkinCluster( skelQuery, skinningQuery, skinningJoints, skinnedPrim, _GetArgs(), context, bindPose); } } } }