bool UsdGeomCurves::ComputeExtent(const VtVec3fArray& points, const VtFloatArray& widths, VtVec3fArray* extent) { // We know nothing about the curve basis. Compute the extent as if it were // a point cloud with some max width (convex hull). float maxWidth = (widths.size() > 0 ? *(std::max_element(widths.begin(), widths.end())) : 0); if (not UsdGeomPointBased::ComputeExtent(points, extent)) { return false; } GfVec3f widthVec = GfVec3f(maxWidth/2.); (*extent)[0] -= widthVec; (*extent)[1] += widthVec; return true; }
_UsdBuilder& SetSpline(std::string kat_prefix, std::string valueSuffix, UsdRiSplineAPI spline) { // Knot count { UsdAttribute posAttr = spline.GetPositionsAttr(); VtFloatArray posVec; posAttr.Get(&posVec); _builder.set(kat_prefix, FnKat::IntAttribute(posVec.size())); } // Knot positions Set( kat_prefix + "_Knots", spline.GetPositionsAttr() ); // Knot values Set( kat_prefix + valueSuffix, spline.GetValuesAttr() ); // Interpolation { VtValue val; UsdAttribute attr = spline.GetInterpolationAttr(); if (attr.IsValid() && attr.HasAuthoredValueOpinion() && attr.Get(&val, _time) && val.IsHolding<TfToken>()) { TfToken t = val.Get<TfToken>(); std::string interp = "unknown"; if (t == UsdRiTokens->linear) { interp = "linear"; } else if (t == UsdRiTokens->catmullRom) { interp = "catmull-rom"; } else if (t == UsdRiTokens->bspline) { interp = "bspline"; } else if (t == UsdRiTokens->constant) { interp = "constant"; } _builder.set(kat_prefix + "_Interpolation", FnKat::StringAttribute(interp)); } } return *this; }
/* 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; }
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; }