bool MayaPrimWriter::writePrimAttrs(const MDagPath &dagT, const UsdTimeCode &usdTime, UsdGeomImageable &primSchema) { MStatus status; MFnDependencyNode depFn(getDagPath().node()); MFnDependencyNode depFn2(dagT.node()); // optionally also scan a shape's transform if merging transforms if (getArgs().exportVisibility) { bool isVisible = true; // if BOTH shape or xform is animated, then visible bool isAnimated = false; // if either shape or xform is animated, then animated PxrUsdMayaUtil::getPlugValue(depFn, "visibility", &isVisible, &isAnimated); if ( dagT.isValid() ) { bool isVis, isAnim; if (PxrUsdMayaUtil::getPlugValue(depFn2, "visibility", &isVis, &isAnim)){ isVisible = isVisible and isVis; isAnimated = isAnimated or isAnim; } } TfToken const &visibilityTok = (isVisible ? UsdGeomTokens->inherited : UsdGeomTokens->invisible); if (usdTime.IsDefault() != isAnimated ) { if (usdTime.IsDefault()) primSchema.CreateVisibilityAttr(VtValue(visibilityTok), true); else primSchema.CreateVisibilityAttr().Set(visibilityTok, usdTime); } } UsdPrim usdPrim = primSchema.GetPrim(); // There is no Gprim abstraction in this module, so process the few // gprim attrs here. UsdGeomGprim gprim = UsdGeomGprim(usdPrim); if (gprim and usdTime.IsDefault()){ PxrUsdMayaPrimWriterContext* unused = NULL; PxrUsdMayaTranslatorGprim::Write( getDagPath().node(), gprim, unused); } _writeUsdInfo(dagT, usdTime, usdPrim); // Write user-tagged export attributes. Write attributes on the transform // first, and then attributes on the shape node. This means that attribute // name collisions will always be handled by taking the shape node's value // if we're merging transforms and shapes. if (dagT.isValid() and !(dagT == getDagPath())) { PxrUsdMayaWriteUtil::WriteUserExportedAttributes(dagT, usdPrim, usdTime); } PxrUsdMayaWriteUtil::WriteUserExportedAttributes(getDagPath(), usdPrim, usdTime); return true; }
bool MayaMeshWriter::isMeshValid() { MStatus status = MS::kSuccess; // Sanity checks MFnMesh lMesh( getDagPath(), &status ); if ( !status ) { MGlobal::displayError( "MFnMesh() failed for MayaMeshWriter" ); return false; } unsigned int numVertices = lMesh.numVertices(); unsigned int numPolygons = lMesh.numPolygons(); if (numVertices < 3 && numVertices > 0) { MString err = lMesh.fullPathName() + " is not a valid mesh, because it only has "; err += numVertices; err += " points."; MGlobal::displayError(err); } if (numPolygons == 0) { MGlobal::displayWarning(lMesh.fullPathName() + " has no polygons."); } return true; }
MStatus Object::setShapesVisibility(bool visible, MTypeId & typeId) { MStatus status; MDagPath dagPath = getDagPath(status); if (!status) { status.perror("Object::getDagPath"); return status; } unsigned int numShapes; if (!(status = dagPath.numberOfShapesDirectlyBelow(numShapes))) { status.perror("MDagPath::numberOfShapesDirectlyBelow"); return status; } for(unsigned int i = 0; i < numShapes; ++i) { MDagPath shape = dagPath; if (!(status = shape.extendToShapeDirectlyBelow(i))) { status.perror("MDagPath::extendToShapeDirectlyBelow"); return status; } MFnDagNode shape_dagNode(shape); if (shape_dagNode.typeId(&status) == typeId) { MPlug visibilityPlug(shape.node(), shape_dagNode.findPlug("visibility", &status)); if (!status) { status.perror("MFnDagNode::findPlug"); return status; } if (!(status = visibilityPlug.setBool(visible))) { status.perror("MPlug::setBool"); return status; } } else if (!status) { status.perror("MFnDagNode::typeId"); return status; } } return MStatus::kSuccess; }
MStatus Object::getRotation(MEulerRotation & rotation) { MStatus status; MFnTransform transform(getDagPath(status)); if (!status) { status.perror("Base::getDagPath"); return status; } if (!(status = transform.getRotation(rotation))) { status.perror("MFnTransform::getRotation"); return status; } return MStatus::kSuccess; }
bool Object::isAnyShapeVisible(MTypeId & typeId, MStatus & status) { MDagPath dagPath = getDagPath(status); if (!status) { status.perror("Object::getDagPath"); return false; } unsigned int numShapes; if (!(status = dagPath.numberOfShapesDirectlyBelow(numShapes))) { status.perror("MDagPath::numberOfShapesDirectlyBelow"); return false; } for(unsigned int i = 0; i < numShapes; ++i) { MDagPath shape = dagPath; if (!(status = shape.extendToShapeDirectlyBelow(i))) { status.perror("MDagPath::extendToShapeDirectlyBelow"); return false; } MFnDagNode shape_dagNode(shape); if (shape_dagNode.typeId(&status) == typeId) { MPlug visibilityPlug(shape.node(), shape_dagNode.findPlug("visibility", &status)); if (!status) { status.perror("MFnDagNode::findPlug"); return false; } if (visibilityPlug.asBool()) { status = MStatus::kSuccess; return true; } } } status = MStatus::kSuccess; return false; }
MStatus Object::getTranslation(MVector & vector, MSpace::Space space) { MStatus status; MFnTransform transform(getDagPath(status)); if (!status) { status.perror("Base::getDagPath"); return status; } vector = transform.getTranslation(space, &status); if (!status) { status.perror("MFnTransform::getTranslation"); return status; } return MStatus::kSuccess; }
MStatus Object::getTransform(MTransformationMatrix & matrix) { MStatus status; MFnTransform transform(getDagPath(status)); if (!status) { status.perror("Base::getDagPath"); return status; } matrix = transform.transformation(&status); if (!status) { status.perror("MFnTransform::transformation"); return status; } return MStatus::kSuccess; }
// virtual bool MayaNurbsCurveWriter::writeNurbsCurveAttrs(const UsdTimeCode &usdTime, UsdGeomNurbsCurves &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; } MFnDependencyNode fnDepNode(getDagPath().node(), &status); MString name = fnDepNode.name(); MFnNurbsCurve curveFn( getDagPath(), &status ); if (!status) { MGlobal::displayError("MFnNurbsCurve() failed for MayaNurbsCurveWriter"); return false; } // Get curve attrs ====== unsigned int numCurves = 1; // Assuming only 1 curve for now VtArray<int> curveOrder(numCurves); VtArray<int> curveVertexCounts(numCurves); VtArray<float> curveWidths(numCurves); VtArray<GfVec2d> ranges(numCurves); curveOrder[0] = curveFn.degree()+1; curveVertexCounts[0] = curveFn.numCVs(); TF_AXIOM(curveOrder[0] <= curveVertexCounts[0] ); curveWidths[0] = 1.0; // TODO: Retrieve from custom attr double mayaKnotDomainMin; double mayaKnotDomainMax; status = curveFn.getKnotDomain(mayaKnotDomainMin, mayaKnotDomainMax); TF_AXIOM(status == MS::kSuccess); ranges[0][0] = mayaKnotDomainMin; ranges[0][1] = mayaKnotDomainMax; MPointArray mayaCurveCVs; status = curveFn.getCVs(mayaCurveCVs, MSpace::kObject); TF_AXIOM(status == MS::kSuccess); VtArray<GfVec3f> points(mayaCurveCVs.length()); // all CVs batched together for (unsigned int i=0; i < mayaCurveCVs.length(); i++) { points[i].Set(mayaCurveCVs[i].x, mayaCurveCVs[i].y, mayaCurveCVs[i].z); } MDoubleArray mayaCurveKnots; status = curveFn.getKnots(mayaCurveKnots); TF_AXIOM(status == MS::kSuccess); VtArray<double> curveKnots(mayaCurveKnots.length()); // all knots batched together for (unsigned int i=0; i < mayaCurveKnots.length(); i++) { curveKnots[i] = mayaCurveKnots[i]; } // Gprim VtArray<GfVec3f> extent(2); UsdGeomCurves::ComputeExtent(points, curveWidths, &extent); primSchema.CreateExtentAttr().Set(extent, usdTime); // Curve primSchema.GetOrderAttr().Set(curveOrder); // not animatable primSchema.GetCurveVertexCountsAttr().Set(curveVertexCounts); // not animatable primSchema.GetWidthsAttr().Set(curveWidths); // not animatable primSchema.GetKnotsAttr().Set(curveKnots); // not animatable primSchema.GetRangesAttr().Set(ranges); // not animatable primSchema.GetPointsAttr().Set(points, usdTime); // CVs // TODO: Handle periodic and non-periodic cases return true; }
// 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; }
/* virtual */ bool MayaCameraWriter::writeCameraAttrs(const UsdTimeCode &usdTime, UsdGeomCamera &primSchema) { // Since write() above will take care of any animation on the camera's // transform, we only want to proceed here if: // - We are at the default time and NO attributes on the shape are animated. // OR // - We are at a non-default time and some attribute on the shape IS animated. if (usdTime.IsDefault() == isShapeAnimated()) { return true; } MStatus status; MFnCamera camFn(getDagPath(), &status); CHECK_MSTATUS_AND_RETURN(status, false); // NOTE: We do not use a GfCamera and then call SetFromCamera() below // because we want the xformOps populated by the parent class to survive. // Using SetFromCamera() would stomp them with a single "transform" xformOp. // Set the type of projection. if (camFn.isOrtho()) { primSchema.GetProjectionAttr().Set(UsdGeomTokens->orthographic, usdTime); } else { primSchema.GetProjectionAttr().Set(UsdGeomTokens->perspective, usdTime); } // Setup the aperture. primSchema.GetHorizontalApertureAttr().Set( float(PxrUsdMayaUtil::ConvertInchesToMM( camFn.horizontalFilmAperture() * camFn.lensSqueezeRatio())), usdTime); primSchema.GetVerticalApertureAttr().Set( float(PxrUsdMayaUtil::ConvertInchesToMM( camFn.verticalFilmAperture() * camFn.lensSqueezeRatio())), usdTime); primSchema.GetHorizontalApertureOffsetAttr().Set( float(camFn.horizontalFilmOffset()), usdTime); primSchema.GetVerticalApertureOffsetAttr().Set( float(camFn.verticalFilmOffset()), usdTime); // Set the lens parameters. primSchema.GetFocalLengthAttr().Set( float(camFn.focalLength()), usdTime); // Always export focus distance and fStop regardless of what // camFn.isDepthOfField() says. Downstream tools can choose to ignore or // override them. primSchema.GetFocusDistanceAttr().Set( float(camFn.focusDistance()), usdTime); primSchema.GetFStopAttr().Set( float(camFn.fStop()), usdTime); // Set the clipping planes. GfVec2f clippingRange(camFn.nearClippingPlane(), camFn.farClippingPlane()); primSchema.GetClippingRangeAttr().Set(clippingRange, usdTime); return true; }