UsdGeomPrimvar UsdGeomPrimvarsAPI::FindPrimvarWithInheritance(const TfToken &name, const std::vector<UsdGeomPrimvar> &inheritedFromAncestors) const { TRACE_FUNCTION(); const UsdPrim &prim = GetPrim(); if (!prim) { TF_CODING_ERROR("FindPrimvarWithInheritance called on invalid prim: %s", UsdDescribe(prim).c_str()); return UsdGeomPrimvar(); } const TfToken attrName = UsdGeomPrimvar::_MakeNamespaced(name); UsdGeomPrimvar pv = GetPrimvar(attrName); if (pv.HasAuthoredValue()){ return pv; } for (UsdGeomPrimvar const &inherited : inheritedFromAncestors) { if (inherited.GetName() == attrName){ return inherited; } } return pv; }
bool MayaMeshWriter::_createUVPrimVar( UsdGeomGprim &primSchema, const TfToken& name, const VtArray<GfVec2f>& data, const TfToken& interpolation, const VtArray<int>& assignmentIndices, const int unassignedValueIndex) { unsigned int numValues = data.size(); if (numValues == 0) { return false; } TfToken interp = interpolation; if (numValues == 1 && interp == UsdGeomTokens->constant) { interp = TfToken(); } UsdGeomPrimvar primVar = primSchema.CreatePrimvar(name, SdfValueTypeNames->Float2Array, interp); primVar.Set(data); if (!assignmentIndices.empty()) { primVar.SetIndices(assignmentIndices); if (unassignedValueIndex != primVar.GetUnauthoredValuesIndex()) { primVar.SetUnauthoredValuesIndex(unassignedValueIndex); } } return true; }
UsdGeomPrimvar UsdGeomPrimvarsAPI::FindPrimvarWithInheritance(const TfToken &name) const { TRACE_FUNCTION(); const TfToken attrName = UsdGeomPrimvar::_MakeNamespaced(name); UsdPrim prim = GetPrim(); if (!prim) { TF_CODING_ERROR("FindPrimvarWithInheritance called on invalid prim: %s", UsdDescribe(prim).c_str()); return UsdGeomPrimvar(); } UsdGeomPrimvar localPv = GetPrimvar(name); if (localPv.HasAuthoredValue()){ return localPv; } for (prim = prim.GetParent(); prim && !prim.IsPseudoRoot(); prim = prim.GetParent()) { UsdAttribute attr = prim.GetAttribute(attrName); if (attr.HasAuthoredValue()) { if (UsdGeomPrimvar pv = UsdGeomPrimvar(attr)) { // Only constant primvars can be inherited. if (pv.GetInterpolation() == UsdGeomTokens->constant) { return pv; } else { // Non-constant interpolation blocks inheritance. return UsdGeomPrimvar(); } } } } return localPv; }
bool UsdGeomPrimvarsAPI::HasPossiblyInheritedPrimvar(const TfToken &name) const { TRACE_FUNCTION(); UsdPrim prim = GetPrim(); if (!prim) { TF_CODING_ERROR("HasPossiblyInheritedPrimvar called on invalid prim: %s", UsdDescribe(prim).c_str()); return false; } UsdGeomPrimvar pv = GetPrimvar(name); if (pv.HasAuthoredValue()){ return true; } const TfToken attrName = UsdGeomPrimvar::_MakeNamespaced(name); if (attrName.IsEmpty()) { return false; } for (prim = prim.GetParent(); prim && !prim.IsPseudoRoot(); prim = prim.GetParent()) { UsdAttribute attr = prim.GetAttribute(attrName); if (attr.HasAuthoredValue() && UsdGeomPrimvar::IsPrimvar(attr)) { // Only constant primvars can be inherited. // Non-constant interpolation blocks inheritance. return UsdGeomPrimvar(attr).GetInterpolation() == UsdGeomTokens->constant; } } return false; }
void UsdImagingGprimAdapter::_DiscoverPrimvars(UsdGeomGprim const& gprim, SdfPath const& cachePath, UsdShadeShader const& shader, UsdTimeCode time, UsdImagingValueCache* valueCache) { // TODO: It might be convenient to implicitly wire up PtexFaceOffset and // PtexFaceIndex primvars. TF_DEBUG(USDIMAGING_SHADERS).Msg("\t Looking for <%s> primvars at <%s>\n", gprim.GetPrim().GetPath().GetText(), shader.GetPrim().GetPath().GetText()); for (UsdShadeParameter const& param : shader.GetParameters()) { UsdShadeShader source; TfToken outputName; if (param.GetConnectedSource(&source, &outputName)) { UsdAttribute attr = source.GetIdAttr(); TfToken id; if (not attr or not attr.Get(&id)) { continue; } TF_DEBUG(USDIMAGING_SHADERS).Msg("\t\t Param <%s> connected <%s>(%s)\n", param.GetAttr().GetName().GetText(), source.GetPath().GetText(), id.GetText()); if (id == UsdHydraTokens->HwPrimvar_1) { TfToken t; VtValue v; UsdGeomPrimvar primvarAttr; if (UsdHydraPrimvar(source).GetVarnameAttr().Get(&t, UsdTimeCode::Default())) { primvarAttr = gprim.GetPrimvar(t); if (primvarAttr.ComputeFlattened(&v, time)) { TF_DEBUG(USDIMAGING_SHADERS).Msg("Found primvar %s\n", t.GetText()); UsdImagingValueCache::PrimvarInfo primvar; primvar.name = t; primvar.interpolation = primvarAttr.GetInterpolation(); valueCache->GetPrimvar(cachePath, t) = v; _MergePrimvar(primvar, &valueCache->GetPrimvars(cachePath)); } else { TF_DEBUG(USDIMAGING_SHADERS).Msg( "\t\t No primvar on <%s> named %s\n", gprim.GetPath().GetText(), t.GetText()); } } } else { // Recursively look for more primvars _DiscoverPrimvars(gprim, cachePath, source, time, valueCache); } } } }
void _WritePrefixedAttrs( const UsdTimeCode &usdTime, const _PrimEntry& entry) { MStatus status; MFnDependencyNode depFn(entry.mayaDagPath.node()); for (const auto& attrEntry : entry.attrs) { MPlug plg = depFn.findPlug(attrEntry.mayaAttributeName.c_str(), true); UsdAttribute usdAttr; if (attrEntry.isPrimvar) { // Treat as custom primvar. TfToken interpolation = _GetPrimvarInterpolation( depFn, attrEntry.mayaAttributeName); UsdGeomImageable imageable(entry.usdPrim); if (!imageable) { TF_RUNTIME_ERROR( "Cannot create primvar for non-UsdGeomImageable " "USD prim <%s>", entry.usdPrim.GetPath().GetText()); continue; } UsdGeomPrimvar primvar = UsdMayaWriteUtil::GetOrCreatePrimvar( plg, imageable, attrEntry.usdAttributeName, interpolation, -1, false); if (primvar) { usdAttr = primvar.GetAttr(); } } else { // Treat as custom attribute. usdAttr = UsdMayaWriteUtil::GetOrCreateUsdAttr( plg, entry.usdPrim, attrEntry.usdAttributeName, true); } if (usdAttr) { UsdMayaWriteUtil::SetUsdAttr(plg, usdAttr, usdTime); } else { TF_RUNTIME_ERROR( "Could not create attribute '%s' for " "USD prim <%s>", attrEntry.usdAttributeName.c_str(), entry.usdPrim.GetPath().GetText()); continue; } } }
bool MayaMeshWriter::_createRGBAPrimVar( UsdGeomGprim &primSchema, const TfToken& name, const VtArray<GfVec3f>& rgbData, const VtArray<float>& alphaData, const TfToken& interpolation, const VtArray<int>& assignmentIndices, const int unassignedValueIndex, bool clamped) { unsigned int numValues = rgbData.size(); if (numValues == 0 || numValues != alphaData.size()) { return false; } TfToken interp = interpolation; if (numValues == 1 && interp == UsdGeomTokens->constant) { interp = TfToken(); } UsdGeomPrimvar primVar = primSchema.CreatePrimvar(name, SdfValueTypeNames->Color4fArray, interp); VtArray<GfVec4f> rgbaData(numValues); for (size_t i = 0; i < rgbaData.size(); ++i) { rgbaData[i] = GfVec4f(rgbData[i][0], rgbData[i][1], rgbData[i][2], alphaData[i]); } primVar.Set(rgbaData); if (!assignmentIndices.empty()) { primVar.SetIndices(assignmentIndices); if (unassignedValueIndex != primVar.GetUnauthoredValuesIndex()) { primVar.SetUnauthoredValuesIndex(unassignedValueIndex); } } if (clamped) { PxrUsdMayaRoundTripUtil::MarkPrimvarAsClamped(primVar); } return true; }
bool MayaMeshWriter::_createRGBPrimVar( UsdGeomGprim &primSchema, const TfToken& name, const VtArray<GfVec3f>& data, const TfToken& interpolation, const VtArray<int>& assignmentIndices, const int unassignedValueIndex, bool clamped) { unsigned int numValues = data.size(); if (numValues == 0) { return false; } TfToken interp = interpolation; if (numValues == 1 && interp == UsdGeomTokens->constant) { interp = TfToken(); } UsdGeomPrimvar primVar = primSchema.CreatePrimvar(name, SdfValueTypeNames->Color3fArray, interp); primVar.Set(data); if (!assignmentIndices.empty()) { primVar.SetIndices(assignmentIndices); if (unassignedValueIndex != primVar.GetUnauthoredValuesIndex()) { primVar.SetUnauthoredValuesIndex(unassignedValueIndex); } } if (clamped) { PxrUsdMayaRoundTripUtil::MarkPrimvarAsClamped(primVar); } return true; }
/* static */ bool UsdMayaTranslatorMesh::_AssignConstantPrimvarToMesh( const UsdGeomPrimvar& primvar, MFnMesh& meshFn) { const TfToken& interpolation = primvar.GetInterpolation(); if (interpolation != UsdGeomTokens->constant) { return false; } const TfToken& name = primvar.GetBaseName(); const SdfValueTypeName& typeName = primvar.GetTypeName(); const SdfVariability& variability = SdfVariabilityUniform; MObject attrObj = UsdMayaReadUtil::FindOrCreateMayaAttr( typeName, variability, meshFn, name.GetText()); if (attrObj.isNull()) { return false; } VtValue primvarData; primvar.Get(&primvarData); MStatus status; MPlug plug = meshFn.findPlug( name.GetText(), /* wantNetworkedPlug = */ true, &status); if (status != MS::kSuccess || plug.isNull()) { return false; } return UsdMayaReadUtil::SetMayaAttr(plug, primvarData); }
/* 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; }
/* static */ GT_DataArrayHandle GusdPrimWrapper::convertPrimvarData( const UsdGeomPrimvar& primvar, UsdTimeCode time ) { VtValue val; if (!primvar.ComputeFlattened(&val, time)) { return nullptr; } #define _CONVERT_TUPLE(elemType, gtArray, tupleSize, gtType) \ if (val.IsHolding<elemType>()) { \ return Gusd_ConvertTupleToGt<elemType, gtArray, tupleSize>(val); \ } else if (val.IsHolding<VtArray<elemType> >()) { \ return Gusd_ConvertTupleArrayToGt<elemType, gtArray, tupleSize>( \ primvar, val); \ } // Check for most common value types first. _CONVERT_TUPLE(GfVec3f, GT_Real32Array, 3, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec2f, GT_Real32Array, 2, GT_TYPE_NONE); _CONVERT_TUPLE(float, GT_Real32Array, 1, GT_TYPE_NONE); _CONVERT_TUPLE(int, GT_Int32Array, 1, GT_TYPE_NONE); // Scalars _CONVERT_TUPLE(double, GT_Real64Array, 1, GT_TYPE_NONE); _CONVERT_TUPLE(GfHalf, GT_Real16Array, 1, GT_TYPE_NONE); _CONVERT_TUPLE(int64, GT_Int64Array, 1, GT_TYPE_NONE); _CONVERT_TUPLE(unsigned char, GT_UInt8Array, 1, GT_TYPE_NONE); // TODO: UInt, UInt64 (convert to int32/int64?) // Vec2 _CONVERT_TUPLE(GfVec2d, GT_Real64Array, 2, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec2h, GT_Real16Array, 2, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec2i, GT_Int32Array, 2, GT_TYPE_NONE); // Vec3 _CONVERT_TUPLE(GfVec3d, GT_Real64Array, 3, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec3h, GT_Real16Array, 3, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec3i, GT_Int32Array, 3, GT_TYPE_NONE); // Vec4 _CONVERT_TUPLE(GfVec4d, GT_Real64Array, 4, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec4f, GT_Real32Array, 4, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec4h, GT_Real16Array, 4, GT_TYPE_NONE); _CONVERT_TUPLE(GfVec4i, GT_Int32Array, 4, GT_TYPE_NONE); // Quat _CONVERT_TUPLE(GfQuatd, GT_Real64Array, 4, GT_TYPE_QUATERNION); _CONVERT_TUPLE(GfQuatf, GT_Real32Array, 4, GT_TYPE_QUATERNION); _CONVERT_TUPLE(GfQuath, GT_Real16Array, 4, GT_TYPE_QUATERNION); // Matrices _CONVERT_TUPLE(GfMatrix3d, GT_Real64Array, 9, GT_TYPE_MATRIX3); _CONVERT_TUPLE(GfMatrix4d, GT_Real64Array, 16, GT_TYPE_MATRIX); // TODO: Correct GT_Type for GfMatrix2d? _CONVERT_TUPLE(GfMatrix2d, GT_Real64Array, 4, GT_TYPE_NONE); #undef _CONVERT_TUPLE #define _CONVERT_STRING(elemType) \ if (val.IsHolding<elemType>()) { \ return Gusd_ConvertStringToGt<elemType>(val); \ } else if (val.IsHolding<VtArray<elemType> >()) { \ return Gusd_ConvertStringArrayToGt<elemType>(primvar, val); \ } _CONVERT_STRING(std::string); _CONVERT_STRING(TfToken); _CONVERT_STRING(SdfAssetPath); #undef _CONVERT_STRING return nullptr; }
void UsdImagingGprimAdapter::_DiscoverPrimvarsDeprecated(UsdGeomGprim const& gprim, SdfPath const& cachePath, UsdPrim const& shaderPrim, UsdTimeCode time, UsdImagingValueCache* valueCache) { UsdImagingValueCache::PrimvarInfo primvar; std::vector<UsdProperty> const& props = shaderPrim.GetProperties(); TF_FOR_ALL(propIt, props) { UsdAttribute attr = propIt->As<UsdAttribute>(); if (not attr) { continue; } if (attr.GetPath().IsNamespacedPropertyPath()) { continue; } // Ok this is a parameter, check source input. if (UsdAttribute texAttr = shaderPrim.GetAttribute( TfToken(attr.GetPath().GetName() + ":texture"))) { TfToken t; SdfAssetPath ap; VtValue v; UsdGeomPrimvar primvarAttr; texAttr.Get(&ap, UsdTimeCode::Default()); bool isPtex = GlfPtexTexture::IsPtexTexture(TfToken(ap.GetAssetPath())); if (isPtex) { t = UsdImagingTokens->ptexFaceIndex; // Allow the client to override this name texAttr.GetMetadata(UsdImagingTokens->faceIndexPrimvar, &t); primvarAttr = gprim.GetPrimvar(t); if (primvarAttr) { if (primvarAttr.ComputeFlattened(&v, time)) { primvar.name = t; primvar.interpolation = primvarAttr.GetInterpolation(); valueCache->GetPrimvar(cachePath, t) = v; _MergePrimvar(primvar, &valueCache->GetPrimvars(cachePath)); } } t = UsdImagingTokens->ptexFaceOffset; // Allow the client to override this name texAttr.GetMetadata(UsdImagingTokens->faceOffsetPrimvar, &t); primvarAttr = gprim.GetPrimvar(t); if (primvarAttr) { primvar.name = t; primvar.interpolation = primvarAttr.GetInterpolation(); if (primvarAttr.ComputeFlattened(&v, time)) { valueCache->GetPrimvar(cachePath, t) = v; _MergePrimvar(primvar, &valueCache->GetPrimvars(cachePath)); } } } else { texAttr.GetMetadata(UsdImagingTokens->uvPrimvar, &t); primvarAttr = gprim.GetPrimvar(t); if (TF_VERIFY(primvarAttr, "%s\n", t.GetText())) { if (TF_VERIFY(primvarAttr.ComputeFlattened(&v, time))) { primvar.name = t; // does not include primvars: primvar.interpolation = primvarAttr.GetInterpolation(); // Convert double to float, we don't need double precision. if (v.IsHolding<VtVec2dArray>()) { v = VtValue::Cast<VtVec2fArray>(v); } valueCache->GetPrimvar(cachePath, t) = v; _MergePrimvar(primvar, &valueCache->GetPrimvars(cachePath)); } } } } else if (UsdAttribute pvAttr = shaderPrim.GetAttribute( TfToken(attr.GetPath().GetName() + ":primvar"))) { TfToken t; VtValue v; UsdGeomPrimvar primvarAttr; if (TF_VERIFY(pvAttr.Get(&t, UsdTimeCode::Default()))) { primvarAttr = gprim.GetPrimvar(t); if (TF_VERIFY(primvarAttr.ComputeFlattened(&v, time))) { primvar.name = t; // does not include primvars: primvar.interpolation = primvarAttr.GetInterpolation(); valueCache->GetPrimvar(cachePath, t) = v; _MergePrimvar(primvar, &valueCache->GetPrimvars(cachePath)); } } } }
/* static */ bool UsdMayaTranslatorMesh::_AssignUVSetPrimvarToMesh( const UsdGeomPrimvar& primvar, MFnMesh& meshFn) { const TfToken& primvarName = primvar.GetPrimvarName(); // Get the raw data before applying any indexing. VtVec2fArray uvValues; if (!primvar.Get(&uvValues) || uvValues.empty()) { TF_WARN("Could not read UV values from primvar '%s' on mesh: %s", primvarName.GetText(), primvar.GetAttr().GetPrimPath().GetText()); return false; } // This is the number of UV values assuming the primvar is NOT indexed. VtIntArray assignmentIndices; if (primvar.GetIndices(&assignmentIndices)) { // The primvar IS indexed, so the indices array is what determines the // number of UV values. int unauthoredValuesIndex = primvar.GetUnauthoredValuesIndex(); // Replace any index equal to unauthoredValuesIndex with -1. if (unauthoredValuesIndex != -1) { for (int& index : assignmentIndices) { if (index == unauthoredValuesIndex) { index = -1; } } } // Furthermore, if unauthoredValuesIndex is valid for uvValues, then // remove it from uvValues and shift the indices (we don't want to // import the unauthored value into Maya, where it has no meaning). if (unauthoredValuesIndex >= 0 && static_cast<size_t>(unauthoredValuesIndex) < uvValues.size()) { // This moves [unauthoredValuesIndex + 1, end) to // [unauthoredValuesIndex, end - 1), erasing the // unauthoredValuesIndex. std::move( uvValues.begin() + unauthoredValuesIndex + 1, uvValues.end(), uvValues.begin() + unauthoredValuesIndex); uvValues.pop_back(); for (int& index : assignmentIndices) { if (index > unauthoredValuesIndex) { index = index - 1; } } } } // Go through the UV data and add the U and V values to separate // MFloatArrays. MFloatArray uCoords; MFloatArray vCoords; for (const GfVec2f& v : uvValues) { uCoords.append(v[0]); vCoords.append(v[1]); } MStatus status; MString uvSetName(primvarName.GetText()); if (primvarName == UsdUtilsGetPrimaryUVSetName()) { // We assume that the primary USD UV set maps to Maya's default 'map1' // set which always exists, so we shouldn't try to create it. uvSetName = "map1"; } else { status = meshFn.createUVSet(uvSetName); if (status != MS::kSuccess) { TF_WARN("Unable to create UV set '%s' for mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } } // The following two lines should have no effect on user-visible state but // prevent a Maya crash in MFnMesh.setUVs after creating a crease set. // XXX this workaround is needed pending a fix by Autodesk. MString currentSet = meshFn.currentUVSetName(); meshFn.setCurrentUVSetName(currentSet); // Create UVs on the mesh from the values we collected out of the primvar. // We'll assign mesh components to these values below. status = meshFn.setUVs(uCoords, vCoords, &uvSetName); if (status != MS::kSuccess) { TF_WARN("Unable to set UV data on UV set '%s' for mesh: %s", uvSetName.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 uvIds = _GetMayaFaceVertexAssignmentIds(meshFn, interpolation, assignmentIndices, -1); MIntArray vertexCounts; MIntArray vertexList; status = meshFn.getVertices(vertexCounts, vertexList); if (status != MS::kSuccess) { TF_WARN("Could not get vertex counts for UV set '%s' on mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } status = meshFn.assignUVs(vertexCounts, uvIds, &uvSetName); if (status != MS::kSuccess) { TF_WARN("Could not assign UV values to UV set '%s' on mesh: %s", uvSetName.asChar(), meshFn.fullPathName().asChar()); return false; } return true; }
void GusdPrimWrapper::loadPrimvars( UsdTimeCode time, const GT_RefineParms* rparms, int minUniform, int minPoint, int minVertex, const string& primPath, GT_AttributeListHandle* vertex, GT_AttributeListHandle* point, GT_AttributeListHandle* primitive, GT_AttributeListHandle* constant, const GT_DataArrayHandle& remapIndicies ) const { // Primvars will be loaded if they match a provided pattern. // By default, set the pattern to match only "Cd". Then write // over this pattern if there is one provided in rparms. const char* Cd = "Cd"; UT_String primvarPattern(Cd); if (rparms) { rparms->import("usd:primvarPattern", primvarPattern); } std::vector<UsdGeomPrimvar> authoredPrimvars; bool hasCdPrimvar = false; { UsdGeomImageable prim = getUsdPrimForRead(); UsdGeomPrimvar colorPrimvar = prim.GetPrimvar(GusdTokens->Cd); if (colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValueOpinion()) { hasCdPrimvar = true; } // It's common for "Cd" to be the only primvar to load. // In this case, avoid getting all other authored primvars. if (primvarPattern == Cd) { if (hasCdPrimvar) { authoredPrimvars.push_back(colorPrimvar); } else { // There is no authored "Cd" primvar. // Try to find "displayColor" instead. colorPrimvar = prim.GetPrimvar(UsdGeomTokens->primvarsDisplayColor); if (colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValueOpinion()) { authoredPrimvars.push_back(colorPrimvar); } } } else if (primvarPattern != "") { authoredPrimvars = prim.GetAuthoredPrimvars(); } } // Is it better to sort the attributes and build the attributes all at once. for( const UsdGeomPrimvar &primvar : authoredPrimvars ) { DBG(cerr << "loadPrimvar " << primvar.GetPrimvarName() << "\t" << primvar.GetTypeName() << "\t" << primvar.GetInterpolation() << endl); UT_String name(primvar.GetPrimvarName()); // One special case we always handle here is to change // the name of the USD "displayColor" primvar to "Cd", // as long as there is not already a "Cd" primvar. if (!hasCdPrimvar && primvar.GetName() == UsdGeomTokens->primvarsDisplayColor) { name = Cd; } // If the name of this primvar doesn't // match the primvarPattern, skip it. if (!name.multiMatch(primvarPattern, 1, " ")) { continue; } GT_DataArrayHandle gtData = convertPrimvarData( primvar, time ); if( !gtData ) { TF_WARN( "Failed to convert primvar %s:%s %s.", primPath.c_str(), primvar.GetPrimvarName().GetText(), primvar.GetTypeName().GetAsToken().GetText() ); continue; } // usd vertex primvars are assigned to points if( primvar.GetInterpolation() == UsdGeomTokens->vertex ) { if( gtData->entries() < minPoint ) { TF_WARN( "Not enough values found for primvar: %s:%s. " "%zd values given for %d points.", primPath.c_str(), primvar.GetPrimvarName().GetText(), gtData->entries(), minPoint ); } else { if (remapIndicies) { gtData = new GT_DAIndirect( remapIndicies, gtData ); } if( point ) { *point = (*point)->addAttribute( name.c_str(), gtData, true ); } } } else if( primvar.GetInterpolation() == UsdGeomTokens->faceVarying ) { if( gtData->entries() < minVertex ) { TF_WARN( "Not enough values found for primvar: %s:%s. " "%zd values given for %d verticies.", primPath.c_str(), primvar.GetPrimvarName().GetText(), gtData->entries(), minVertex ); } else if( vertex ) { *vertex = (*vertex)->addAttribute( name.c_str(), gtData, true ); } } else if( primvar.GetInterpolation() == UsdGeomTokens->uniform ) { if( gtData->entries() < minUniform ) { TF_WARN( "Not enough values found for primvar: %s:%s. " "%zd values given for %d faces.", primPath.c_str(), primvar.GetPrimvarName().GetText(), gtData->entries(), minUniform ); } else if( primitive ) { *primitive = (*primitive)->addAttribute( name.c_str(), gtData, true ); } } else if( primvar.GetInterpolation() == UsdGeomTokens->constant ) { if( constant ) { *constant = (*constant)->addAttribute( name.c_str(), gtData, true ); } } } }
void PxrUsdMayaRoundTripUtil::MarkPrimvarAsClamped(const UsdGeomPrimvar& primvar) { _SetMayaDictValue(primvar.GetAttr(), _tokens->clamped, true); }
/* static */ GT_DataArrayHandle GusdPrimWrapper::convertPrimvarData( const UsdGeomPrimvar& primvar, UsdTimeCode time ) { SdfValueTypeName typeName = primvar.GetTypeName(); if( typeName == SdfValueTypeNames->Int ) { int usdVal; primvar.Get( &usdVal, time ); return new GT_Int32Array( &usdVal, 1, 1 ); } else if( typeName == SdfValueTypeNames->Int64 ) { int64_t usdVal; primvar.Get( &usdVal, time ); return new GT_Int64Array( &usdVal, 1, 1 ); } else if( typeName == SdfValueTypeNames->Float ) { float usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( &usdVal, 1, 1 ); } else if( typeName == SdfValueTypeNames->Double ) { double usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( &usdVal, 1, 1 ); } else if( typeName == SdfValueTypeNames->Float3 ) { GfVec3f usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( usdVal.data(), 1, 3 ); } else if( typeName == SdfValueTypeNames->Double3 ) { GfVec3d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.data(), 1, 3 ); } else if( typeName == SdfValueTypeNames->Color3f ) { GfVec3f usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( usdVal.data(), 1, 3, GT_TYPE_COLOR ); } else if( typeName == SdfValueTypeNames->Color3d ) { GfVec3d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.data(), 1, 3, GT_TYPE_COLOR ); } else if( typeName == SdfValueTypeNames->Normal3f ) { GfVec3f usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( usdVal.data(), 1, 3, GT_TYPE_NORMAL ); } else if( typeName == SdfValueTypeNames->Normal3d ) { GfVec3d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.data(), 1, 3, GT_TYPE_NORMAL ); } else if( typeName == SdfValueTypeNames->Point3f ) { GfVec3f usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( usdVal.data(), 1, 3, GT_TYPE_POINT ); } else if( typeName == SdfValueTypeNames->Point3d ) { GfVec3d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.data(), 1, 3, GT_TYPE_POINT ); } else if( typeName == SdfValueTypeNames->Float4 ) { GfVec4f usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( usdVal.data(), 1, 4 ); } else if( typeName == SdfValueTypeNames->Double4 ) { GfVec4d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.data(), 1, 4 ); } else if( typeName == SdfValueTypeNames->Quatf ) { GfVec4f usdVal; primvar.Get( &usdVal, time ); return new GT_Real32Array( usdVal.data(), 1, 4, GT_TYPE_QUATERNION ); } else if( typeName == SdfValueTypeNames->Quatd ) { GfVec4d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.data(), 1, 4, GT_TYPE_QUATERNION ); } else if( typeName == SdfValueTypeNames->Matrix3d ) { GfMatrix3d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.GetArray(), 1, 9, GT_TYPE_MATRIX3 ); } else if( typeName == SdfValueTypeNames->Matrix4d || typeName == SdfValueTypeNames->Frame4d ) { GfMatrix4d usdVal; primvar.Get( &usdVal, time ); return new GT_Real64Array( usdVal.GetArray(), 1, 16, GT_TYPE_MATRIX ); } else if( typeName == SdfValueTypeNames->String ) { string usdVal; primvar.Get( &usdVal, time ); auto gtString = new GT_DAIndexedString( 1 ); gtString->setString( 0, 0, usdVal.c_str() ); return gtString; } else if( typeName == SdfValueTypeNames->StringArray ) { VtArray<string> usdVal; primvar.ComputeFlattened( &usdVal, time ); auto gtString = new GT_DAIndexedString( usdVal.size() ); for( size_t i = 0; i < usdVal.size(); ++i ) gtString->setString( i, 0, usdVal[i].c_str() ); return gtString; } else if( typeName == SdfValueTypeNames->IntArray ) { VtArray<int> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<int>(usdVal); } else if( typeName == SdfValueTypeNames->Int64Array ) { VtArray<int64_t> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<int64_t>(usdVal); } else if( typeName == SdfValueTypeNames->FloatArray ) { VtArray<float> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<float>(usdVal); } else if( typeName == SdfValueTypeNames->DoubleArray ) { VtArray<double> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<double>(usdVal); } else if( typeName == SdfValueTypeNames->Float2Array ) { VtArray<GfVec2f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec2f>(usdVal); } else if( typeName == SdfValueTypeNames->Double2Array ) { VtArray<GfVec2d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec2d>(usdVal); } else if( typeName == SdfValueTypeNames->Float3Array ) { VtArray<GfVec3f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3f>(usdVal); } else if( typeName == SdfValueTypeNames->Double3Array ) { VtArray<GfVec3d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3d>(usdVal); } else if( typeName == SdfValueTypeNames->Color3fArray ) { VtArray<GfVec3f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3f>(usdVal,GT_TYPE_COLOR); } else if( typeName == SdfValueTypeNames->Color3dArray ) { VtArray<GfVec3d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3d>(usdVal,GT_TYPE_COLOR); } else if( typeName == SdfValueTypeNames->Vector3fArray ) { VtArray<GfVec3f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3f>(usdVal, GT_TYPE_VECTOR); } else if( typeName == SdfValueTypeNames->Vector3dArray ) { VtArray<GfVec3d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3d>(usdVal, GT_TYPE_VECTOR); } else if( typeName == SdfValueTypeNames->Normal3fArray ) { VtArray<GfVec3f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3f>(usdVal, GT_TYPE_NORMAL); } else if( typeName == SdfValueTypeNames->Normal3dArray ) { VtArray<GfVec3d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3d>(usdVal, GT_TYPE_NORMAL); } else if( typeName == SdfValueTypeNames->Point3fArray ) { VtArray<GfVec3f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3f>(usdVal, GT_TYPE_POINT); } else if( typeName == SdfValueTypeNames->Point3dArray ) { VtArray<GfVec3d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec3d>(usdVal, GT_TYPE_POINT); } else if( typeName == SdfValueTypeNames->Float4Array ) { VtArray<GfVec4f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec4f>(usdVal); } else if( typeName == SdfValueTypeNames->Double4Array ) { VtArray<GfVec4d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec4d>(usdVal); } else if( typeName == SdfValueTypeNames->QuatfArray ) { VtArray<GfVec4f> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec4f>(usdVal, GT_TYPE_QUATERNION); } else if( typeName == SdfValueTypeNames->QuatdArray ) { VtArray<GfVec4d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfVec4d>(usdVal, GT_TYPE_QUATERNION); } else if( typeName == SdfValueTypeNames->Matrix3dArray ) { VtArray<GfMatrix3d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfMatrix3d>(usdVal, GT_TYPE_MATRIX3); } else if( typeName == SdfValueTypeNames->Matrix4dArray || typeName == SdfValueTypeNames->Frame4dArray ) { VtArray<GfMatrix4d> usdVal; primvar.ComputeFlattened( &usdVal, time ); return new GusdGT_VtArray<GfMatrix4d>(usdVal, GT_TYPE_MATRIX); } return NULL; }
bool MayaMeshWriter::_addDisplayPrimvars( UsdGeomGprim &primSchema, const MFnMesh::MColorRepresentation colorRep, const VtArray<GfVec3f>& RGBData, const VtArray<float>& AlphaData, const TfToken& interpolation, const VtArray<int>& assignmentIndices, const int unassignedValueIndex, const bool clamped, const bool authored) { // If we already have an authored value, don't try to write a new one. UsdAttribute colorAttr = primSchema.GetDisplayColorAttr(); if (!colorAttr.HasAuthoredValueOpinion() && !RGBData.empty()) { UsdGeomPrimvar displayColor = primSchema.CreateDisplayColorPrimvar(); if (interpolation != displayColor.GetInterpolation()) { displayColor.SetInterpolation(interpolation); } displayColor.Set(RGBData); if (!assignmentIndices.empty()) { displayColor.SetIndices(assignmentIndices); if (unassignedValueIndex != displayColor.GetUnauthoredValuesIndex()) { displayColor.SetUnauthoredValuesIndex(unassignedValueIndex); } } bool authRGB = authored; if (colorRep == MFnMesh::kAlpha) { authRGB = false; } if (authRGB) { if (clamped) { PxrUsdMayaRoundTripUtil::MarkPrimvarAsClamped(displayColor); } } else { PxrUsdMayaRoundTripUtil::MarkAttributeAsMayaGenerated(colorAttr); } } UsdAttribute alphaAttr = primSchema.GetDisplayOpacityAttr(); if (!alphaAttr.HasAuthoredValueOpinion() && !AlphaData.empty()) { // we consider a single alpha value that is 1.0 to be the "default" // value. We only want to write values that are not the "default". bool hasDefaultAlpha = AlphaData.size() == 1 && GfIsClose(AlphaData[0], 1.0, 1e-9); if (!hasDefaultAlpha) { UsdGeomPrimvar displayOpacity = primSchema.CreateDisplayOpacityPrimvar(); if (interpolation != displayOpacity.GetInterpolation()) { displayOpacity.SetInterpolation(interpolation); } displayOpacity.Set(AlphaData); if (!assignmentIndices.empty()) { displayOpacity.SetIndices(assignmentIndices); if (unassignedValueIndex != displayOpacity.GetUnauthoredValuesIndex()) { displayOpacity.SetUnauthoredValuesIndex(unassignedValueIndex); } } bool authAlpha = authored; if (colorRep == MFnMesh::kRGB) { authAlpha = false; } if (authAlpha) { if (clamped) { PxrUsdMayaRoundTripUtil::MarkPrimvarAsClamped(displayOpacity); } } else { PxrUsdMayaRoundTripUtil::MarkAttributeAsMayaGenerated(alphaAttr); } } } return true; }
// This method inspects the JSON blob stored in the 'USD_UserExportedAttributesJson' // attribute on the Maya node at dagPath and exports any attributes specified // there onto usdPrim at time usdTime. The JSON should contain an object that // maps Maya attribute names to other JSON objects that contain metadata about // how to export the attribute into USD. For example: // // { // "myMayaAttributeOne": { // }, // "myMayaAttributeTwo": { // "usdAttrName": "my:namespace:attributeTwo" // }, // "attributeAsPrimvar": { // "usdAttrType": "primvar" // }, // "attributeAsVertexInterpPrimvar": { // "usdAttrType": "primvar", // "interpolation": "vertex" // }, // "attributeAsRibAttribute": { // "usdAttrType": "usdRi" // }, // "doubleAttributeAsFloatAttribute": { // "translateMayaDoubleToUsdSinglePrecision": true // } // } // // If the attribute metadata contains a value for "usdAttrName", the attribute // will be given that name in USD. Otherwise, the Maya attribute name will be // used for primvars and UsdRi attributes, or the Maya attribute name prepended // with the "userProperties" namespace will be used for regular USD attributes. // Maya attributes in the JSON will be processed in sorted order, and any // USD attribute name collisions will be resolved by using the first attribute // visited and warning about subsequent attribute tags. // bool PxrUsdMayaWriteUtil::WriteUserExportedAttributes( const MDagPath& dagPath, const UsdPrim& usdPrim, const UsdTimeCode& usdTime) { std::vector<PxrUsdMayaUserTaggedAttribute> exportedAttributes = PxrUsdMayaUserTaggedAttribute::GetUserTaggedAttributesForNode(dagPath); for (const PxrUsdMayaUserTaggedAttribute& attr : exportedAttributes) { const std::string& usdAttrName = attr.GetUsdName(); const TfToken& usdAttrType = attr.GetUsdType(); const TfToken& interpolation = attr.GetUsdInterpolation(); const bool translateMayaDoubleToUsdSinglePrecision = attr.GetTranslateMayaDoubleToUsdSinglePrecision(); const MPlug& attrPlug = attr.GetMayaPlug(); UsdAttribute usdAttr; if (usdAttrType == PxrUsdMayaUserTaggedAttributeTokens->USDAttrTypePrimvar) { UsdGeomImageable imageable(usdPrim); if (!imageable) { MGlobal::displayError( TfStringPrintf( "Cannot create primvar for non-UsdGeomImageable USD prim: '%s'", usdPrim.GetPath().GetText()).c_str()); continue; } UsdGeomPrimvar primvar = PxrUsdMayaWriteUtil::GetOrCreatePrimvar(attrPlug, imageable, usdAttrName, interpolation, -1, true, translateMayaDoubleToUsdSinglePrecision); if (primvar) { usdAttr = primvar.GetAttr(); } } else if (usdAttrType == PxrUsdMayaUserTaggedAttributeTokens->USDAttrTypeUsdRi) { usdAttr = PxrUsdMayaWriteUtil::GetOrCreateUsdRiAttribute(attrPlug, usdPrim, usdAttrName, "user", translateMayaDoubleToUsdSinglePrecision); } else { usdAttr = PxrUsdMayaWriteUtil::GetOrCreateUsdAttr(attrPlug, usdPrim, usdAttrName, true, translateMayaDoubleToUsdSinglePrecision); } if (usdAttr) { if (!PxrUsdMayaWriteUtil::SetUsdAttr(attrPlug, usdAttr, usdTime, translateMayaDoubleToUsdSinglePrecision)) { MGlobal::displayError( TfStringPrintf("Could not set value for attribute: '%s'", usdAttr.GetPath().GetText()).c_str()); continue; } } else { MGlobal::displayError( TfStringPrintf("Could not create attribute '%s' for USD prim: '%s'", usdAttrName.c_str(), usdPrim.GetPath().GetText()).c_str()); continue; } } return true; }
bool PxrUsdMayaRoundTripUtil::IsPrimvarClamped(const UsdGeomPrimvar& primvar) { bool ret = false; return _GetMayaDictValue(primvar.GetAttr(), _tokens->clamped, &ret) && ret; }
// virtual bool MayaMeshWriter::writeMeshAttrs(const UsdTimeCode &usdTime, UsdGeomMesh &primSchema) { MStatus status = MS::kSuccess; // Write parent class attrs writeTransformAttrs(usdTime, primSchema); // Return if usdTime does not match if shape is animated if (usdTime.IsDefault() == isShapeAnimated() ) { // skip shape as the usdTime does not match if shape isAnimated value return true; } MFnMesh lMesh( getDagPath(), &status ); if ( !status ) { MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" ); return false; } unsigned int numVertices = lMesh.numVertices(); unsigned int numPolygons = lMesh.numPolygons(); // Set mesh attrs ========== // Get points // TODO: Use memcpy() const float* mayaRawPoints = lMesh.getRawPoints(&status); VtArray<GfVec3f> points(numVertices); for (unsigned int i = 0; i < numVertices; i++) { unsigned int floatIndex = i*3; points[i].Set(mayaRawPoints[floatIndex], mayaRawPoints[floatIndex+1], mayaRawPoints[floatIndex+2]); } primSchema.GetPointsAttr().Set(points, usdTime); // ANIMATED // Compute the extent using the raw points VtArray<GfVec3f> extent(2); UsdGeomPointBased::ComputeExtent(points, &extent); primSchema.CreateExtentAttr().Set(extent, usdTime); // Get faceVertexIndices unsigned int numFaceVertices = lMesh.numFaceVertices(&status); VtArray<int> faceVertexCounts(numPolygons); VtArray<int> faceVertexIndices(numFaceVertices); MIntArray mayaFaceVertexIndices; // used in loop below unsigned int curFaceVertexIndex = 0; for (unsigned int i = 0; i < numPolygons; i++) { lMesh.getPolygonVertices(i, mayaFaceVertexIndices); faceVertexCounts[i] = mayaFaceVertexIndices.length(); for (unsigned int j=0; j < mayaFaceVertexIndices.length(); j++) { faceVertexIndices[ curFaceVertexIndex ] = mayaFaceVertexIndices[j]; // push_back curFaceVertexIndex++; } } primSchema.GetFaceVertexCountsAttr().Set(faceVertexCounts); // not animatable primSchema.GetFaceVertexIndicesAttr().Set(faceVertexIndices); // not animatable // Read usdSdScheme attribute. If not set, we default to defaultMeshScheme // flag that can be user defined and initialized to catmullClark TfToken sdScheme = PxrUsdMayaMeshUtil::getSubdivScheme(lMesh, getArgs().defaultMeshScheme); primSchema.CreateSubdivisionSchemeAttr(VtValue(sdScheme), true); // Polygonal Mesh Case if (sdScheme==UsdGeomTokens->none) { // Support for standard USD bool and with Mojito bool tag TfToken normalInterp=PxrUsdMayaMeshUtil::getEmitNormals(lMesh, UsdGeomTokens->none); if (normalInterp==UsdGeomTokens->faceVarying) { // Get References to members of meshData object MFloatVectorArray normalArray; MFloatVectorArray vertexNormalArray; lMesh.getNormals(normalArray, MSpace::kObject); // Iterate through each face in the mesh. vertexNormalArray.setLength(lMesh.numFaceVertices()); VtArray<GfVec3f> meshNormals(lMesh.numFaceVertices()); size_t faceVertIdx = 0; for (MItMeshPolygon faceIter(getDagPath()); !faceIter.isDone(); faceIter.next()) { // Iterate through each face-vertex. for (size_t locVertIdx = 0; locVertIdx < faceIter.polygonVertexCount(); ++locVertIdx, ++faceVertIdx) { int index=faceIter.normalIndex(locVertIdx); for (int j=0;j<3;j++) { meshNormals[faceVertIdx][j]=normalArray[index][j]; } } } primSchema.GetNormalsAttr().Set(meshNormals, usdTime); primSchema.SetNormalsInterpolation(normalInterp); } } else { TfToken sdInterpBound = PxrUsdMayaMeshUtil::getSubdivInterpBoundary( lMesh, UsdGeomTokens->edgeAndCorner); primSchema.CreateInterpolateBoundaryAttr(VtValue(sdInterpBound), true); TfToken sdFVInterpBound = PxrUsdMayaMeshUtil::getSubdivFVInterpBoundary( lMesh); primSchema.CreateFaceVaryingLinearInterpolationAttr( VtValue(sdFVInterpBound), true); assignSubDivTagsToUSDPrim( lMesh, primSchema); } // Holes - we treat InvisibleFaces as holes MUintArray mayaHoles = lMesh.getInvisibleFaces(); if (mayaHoles.length() > 0) { VtArray<int> subdHoles(mayaHoles.length()); for (unsigned int i=0; i < mayaHoles.length(); i++) { subdHoles[i] = mayaHoles[i]; } // not animatable in Maya, so we'll set default only primSchema.GetHoleIndicesAttr().Set(subdHoles); } // == Write UVSets as Vec2f Primvars MStringArray uvSetNames; if (getArgs().exportMeshUVs) { status = lMesh.getUVSetNames(uvSetNames); } for (unsigned int i=0; i < uvSetNames.length(); i++) { // Initialize the VtArray to the max possible size (facevarying) VtArray<GfVec2f> uvValues(numFaceVertices); TfToken interpolation=TfToken(); // Gather UV data and interpolation into a Vec2f VtArray and try to compress if possible if (_GetMeshUVSetData(lMesh, uvSetNames[i], &uvValues, &interpolation) == MS::kSuccess) { // XXX:bug 118447 // We should be able to configure the UV map name that triggers this // behavior, and the name to which it exports. // The UV Set "map1" is renamed st. This is a Pixar/USD convention TfToken setName(uvSetNames[i].asChar()); if (setName == "map1") setName=UsdUtilsGetPrimaryUVSetName(); // Create the primvar and set the values UsdGeomPrimvar uvSet = primSchema.CreatePrimvar(setName, SdfValueTypeNames->Float2Array, interpolation); uvSet.Set( uvValues ); // not animatable } } // == Gather ColorSets MStringArray colorSetNames; if (getArgs().exportColorSets) { status = lMesh.getColorSetNames(colorSetNames); } // shaderColor is used in our pipeline as displayColor. // shaderColor is used to fill faces where the colorset is not assigned MColorArray shaderColors; MObjectArray shaderObjs; VtArray<GfVec3f> shadersRGBData; TfToken shadersRGBInterp; VtArray<float> shadersAlphaData; TfToken shadersAlphaInterp; // If exportDisplayColor is set to true or we have color sets, // gather color & opacity from the shader including per face // assignment. Color set require this to initialize unauthored/unpainted faces if (getArgs().exportDisplayColor or colorSetNames.length()>0) { PxrUsdMayaUtil::GetLinearShaderColor(lMesh, numPolygons, &shadersRGBData, &shadersRGBInterp, &shadersAlphaData, &shadersAlphaInterp); } for (unsigned int i=0; i < colorSetNames.length(); i++) { bool isDisplayColor=false; if (colorSetNames[i]=="displayColor") { if (not getArgs().exportDisplayColor) continue; isDisplayColor=true; } if (colorSetNames[i]=="displayOpacity") { MGlobal::displayWarning("displayOpacity on mesh:" + lMesh.fullPathName() + " is a reserved PrimVar name in USD. Skipping..."); continue; } VtArray<GfVec3f> RGBData; TfToken RGBInterp; VtArray<GfVec4f> RGBAData; TfToken RGBAInterp; VtArray<float> AlphaData; TfToken AlphaInterp; MFnMesh::MColorRepresentation colorSetRep; bool clamped=false; // If displayColor uses shaderValues for non authored areas // and allow RGB and Alpha to have different interpolation // For all other colorSets the non authored values are set // to (1,1,1,1) and RGB and Alpha will have the same interplation // since they will be emitted as a Vec4f if (not _GetMeshColorSetData( lMesh, colorSetNames[i], isDisplayColor, shadersRGBData, shadersAlphaData, &RGBData, &RGBInterp, &RGBAData, &RGBAInterp, &AlphaData, &AlphaInterp, &colorSetRep, &clamped)) { MGlobal::displayWarning("Unable to retrieve colorSet data: " + colorSetNames[i] + " on mesh: "+ lMesh.fullPathName() + ". Skipping..."); continue; } if (isDisplayColor) { // We tag the resulting displayColor/displayOpacity primvar as // authored to make sure we reconstruct the colorset on import // The RGB is also convererted From DisplayToLinear _setDisplayPrimVar( primSchema, colorSetRep, RGBData, RGBInterp, AlphaData, AlphaInterp, clamped, true); } else { TfToken colorSetNameToken = TfToken( PxrUsdMayaUtil::SanitizeColorSetName( std::string(colorSetNames[i].asChar()))); if (colorSetRep == MFnMesh::kAlpha) { _createAlphaPrimVar(primSchema, colorSetNameToken, AlphaData, AlphaInterp, clamped); } else if (colorSetRep == MFnMesh::kRGB) { _createRGBPrimVar(primSchema, colorSetNameToken, RGBData, RGBInterp, clamped); } else if (colorSetRep == MFnMesh::kRGBA) { _createRGBAPrimVar(primSchema, colorSetNameToken, RGBAData, RGBAInterp, clamped); } } } // Set displayColor and displayOpacity only if they are NOT authored already // Since this primvar will come from the shader and not a colorset, // we are not adding the clamp attribute as custom data // If a displayColor/displayOpacity is added, it's not considered authored // we don't need to reconstruct this as a colorset since it orgininated // from bound shader[s], so the authored flag is set to false // Given that this RGB is for display, we do DisplayToLinear conversion if (getArgs().exportDisplayColor) { _setDisplayPrimVar( primSchema, MFnMesh::kRGBA, shadersRGBData, shadersRGBInterp, shadersAlphaData, shadersAlphaInterp, false, false); } return true; }