bool ToMayaSkinClusterConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const { MStatus s; IECore::ConstSmoothSkinningDataPtr skinningData = IECore::runTimeCast<const IECore::SmoothSkinningData>( from ); assert( skinningData ); const std::vector<std::string> &influenceNames = skinningData->influenceNames()->readable(); const std::vector<Imath::M44f> &influencePoseData = skinningData->influencePose()->readable(); const std::vector<int> &pointIndexOffsets = skinningData->pointIndexOffsets()->readable(); const std::vector<int> &pointInfluenceCounts = skinningData->pointInfluenceCounts()->readable(); const std::vector<int> &pointInfluenceIndices = skinningData->pointInfluenceIndices()->readable(); const std::vector<float> &pointInfluenceWeights = skinningData->pointInfluenceWeights()->readable(); MFnDependencyNode fnSkinClusterNode( to, &s ); MFnSkinCluster fnSkinCluster( to, &s ); if ( s != MS::kSuccess ) { /// \todo: optional parameter to allow custom node types and checks for the necessary attributes /// \todo: create a new skinCluster if we want a kSkinClusterFilter and this isn't one throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid skinCluster" ) % fnSkinClusterNode.name() ).str() ); } const unsigned origNumInfluences = influenceNames.size(); unsigned numInfluences = origNumInfluences; std::vector<bool> ignoreInfluence( origNumInfluences, false ); std::vector<int> indexMap( origNumInfluences, -1 ); const bool ignoreMissingInfluences = m_ignoreMissingInfluencesParameter->getTypedValue(); const bool ignoreBindPose = m_ignoreBindPoseParameter->getTypedValue(); // gather the influence objects MObject mObj; MDagPath path; MSelectionList influenceList; MDagPathArray influencePaths; for ( unsigned i=0, index=0; i < origNumInfluences; i++ ) { MString influenceName( influenceNames[i].c_str() ); s = influenceList.add( influenceName ); if ( !s ) { if ( ignoreMissingInfluences ) { ignoreInfluence[i] = true; MGlobal::displayWarning( MString( "ToMayaSkinClusterConverter: \"" + influenceName + "\" is not a valid influence" ) ); continue; } throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid influence" ) % influenceName ).str() ); } influenceList.getDependNode( index, mObj ); MFnIkJoint fnInfluence( mObj, &s ); if ( !s ) { if ( ignoreMissingInfluences ) { ignoreInfluence[i] = true; influenceList.remove( index ); MGlobal::displayWarning( MString( "ToMayaSkinClusterConverter: \"" + influenceName + "\" is not a valid influence" ) ); continue; } throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid influence" ) % influenceName ).str() ); } fnInfluence.getPath( path ); influencePaths.append( path ); indexMap[i] = index; index++; } MPlugArray connectedPlugs; bool existingBindPose = true; MPlug bindPlug = fnSkinClusterNode.findPlug( "bindPose", true, &s ); if ( !bindPlug.connectedTo( connectedPlugs, true, false ) ) { existingBindPose = false; if ( !ignoreBindPose ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" does not have a valid bindPose" ) % fnSkinClusterNode.name() ).str() ); } } MPlug bindPoseMatrixArrayPlug; MPlug bindPoseMemberArrayPlug; if ( existingBindPose ) { MFnDependencyNode fnBindPose( connectedPlugs[0].node() ); if ( fnBindPose.typeName() != "dagPose" ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: \"%s\" is not a valid bindPose" ) % fnBindPose.name() ).str() ); } bindPoseMatrixArrayPlug = fnBindPose.findPlug( "worldMatrix", true, &s ); bindPoseMemberArrayPlug = fnBindPose.findPlug( "members", true, &s ); } /// \todo: optional parameter to reset the skinCluster's geomMatrix plug // break existing influence connections to the skinCluster MDGModifier dgModifier; MMatrixArray ignoredPreMatrices; MPlug matrixArrayPlug = fnSkinClusterNode.findPlug( "matrix", true, &s ); MPlug bindPreMatrixArrayPlug = fnSkinClusterNode.findPlug( "bindPreMatrix", true, &s ); for ( unsigned i=0; i < matrixArrayPlug.numConnectedElements(); i++ ) { MPlug matrixPlug = matrixArrayPlug.connectionByPhysicalIndex( i, &s ); matrixPlug.connectedTo( connectedPlugs, true, false ); if ( !connectedPlugs.length() ) { continue; } MFnIkJoint fnInfluence( connectedPlugs[0].node() ); fnInfluence.getPath( path ); if ( ignoreMissingInfluences && !influenceList.hasItem( path ) ) { MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( i ); preMatrixPlug.getValue( mObj ); MFnMatrixData matFn( mObj ); ignoredPreMatrices.append( matFn.matrix() ); ignoreInfluence.push_back( false ); indexMap.push_back( influenceList.length() ); influenceList.add( connectedPlugs[0].node() ); numInfluences++; } dgModifier.disconnect( connectedPlugs[0], matrixPlug ); } MPlug lockArrayPlug = fnSkinClusterNode.findPlug( "lockWeights", true, &s ); for ( unsigned i=0; i < lockArrayPlug.numConnectedElements(); i++ ) { MPlug lockPlug = lockArrayPlug.connectionByPhysicalIndex( i, &s ); lockPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], lockPlug ); } } MPlug paintPlug = fnSkinClusterNode.findPlug( "paintTrans", true, &s ); paintPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], paintPlug ); } // break existing influence connections to the bind pose if ( existingBindPose ) { for ( unsigned i=0; i < bindPoseMatrixArrayPlug.numConnectedElements(); i++ ) { MPlug matrixPlug = bindPoseMatrixArrayPlug.connectionByPhysicalIndex( i, &s ); matrixPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], matrixPlug ); } } for ( unsigned i=0; i < bindPoseMemberArrayPlug.numConnectedElements(); i++ ) { MPlug memberPlug = bindPoseMemberArrayPlug.connectionByPhysicalIndex( i, &s ); memberPlug.connectedTo( connectedPlugs, true, false ); if ( connectedPlugs.length() ) { dgModifier.disconnect( connectedPlugs[0], memberPlug ); } } } if ( !dgModifier.doIt() ) { dgModifier.undoIt(); throw IECore::Exception( "ToMayaSkinClusterConverter: Unable to break the influence connections" ); } // make connections from influences to skinCluster and bindPose for ( unsigned i=0; i < numInfluences; i++ ) { if ( ignoreInfluence[i] ) { continue; } int index = indexMap[i]; s = influenceList.getDependNode( index, mObj ); MFnIkJoint fnInfluence( mObj, &s ); MPlug influenceMatrixPlug = fnInfluence.findPlug( "worldMatrix", true, &s ).elementByLogicalIndex( 0, &s ); MPlug influenceMessagePlug = fnInfluence.findPlug( "message", true, &s ); MPlug influenceBindPosePlug = fnInfluence.findPlug( "bindPose", true, &s ); MPlug influenceLockPlug = fnInfluence.findPlug( "lockInfluenceWeights", true, &s ); if ( !s ) { // add the lockInfluenceWeights attribute if it doesn't exist MFnNumericAttribute nAttr; MObject attribute = nAttr.create( "lockInfluenceWeights", "liw", MFnNumericData::kBoolean, false ); fnInfluence.addAttribute( attribute ); influenceLockPlug = fnInfluence.findPlug( "lockInfluenceWeights", true, &s ); } // connect influence to the skinCluster MPlug matrixPlug = matrixArrayPlug.elementByLogicalIndex( index ); MPlug lockPlug = lockArrayPlug.elementByLogicalIndex( index ); dgModifier.connect( influenceMatrixPlug, matrixPlug ); dgModifier.connect( influenceLockPlug, lockPlug ); // connect influence to the bindPose if ( !ignoreBindPose ) { MPlug bindPoseMatrixPlug = bindPoseMatrixArrayPlug.elementByLogicalIndex( index ); MPlug memberPlug = bindPoseMemberArrayPlug.elementByLogicalIndex( index ); dgModifier.connect( influenceMessagePlug, bindPoseMatrixPlug ); dgModifier.connect( influenceBindPosePlug, memberPlug ); } } unsigned firstIndex = find( ignoreInfluence.begin(), ignoreInfluence.end(), false ) - ignoreInfluence.begin(); influenceList.getDependNode( firstIndex, mObj ); MFnDependencyNode fnInfluence( mObj ); MPlug influenceMessagePlug = fnInfluence.findPlug( "message", true, &s ); dgModifier.connect( influenceMessagePlug, paintPlug ); if ( !dgModifier.doIt() ) { dgModifier.undoIt(); throw IECore::Exception( "ToMayaSkinClusterConverter: Unable to create the influence connections" ); } // use influencePoseData as bindPreMatrix for ( unsigned i=0; i < numInfluences; i++ ) { if ( ignoreInfluence[i] ) { continue; } MMatrix preMatrix = ( i < origNumInfluences ) ? IECore::convert<MMatrix>( influencePoseData[i] ) : ignoredPreMatrices[i-origNumInfluences]; MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( indexMap[i], &s ); s = preMatrixPlug.getValue( mObj ); if ( s ) { MFnMatrixData matFn( mObj ); matFn.set( preMatrix ); mObj = matFn.object(); } else { MFnMatrixData matFn; mObj = matFn.create( preMatrix ); } preMatrixPlug.setValue( mObj ); } // remove unneeded bindPreMatrix children unsigned existingElements = bindPreMatrixArrayPlug.numElements(); for ( unsigned i=influenceList.length(); i < existingElements; i++ ) { MPlug preMatrixPlug = bindPreMatrixArrayPlug.elementByLogicalIndex( i, &s ); /// \todo: surely there is a way to accomplish this in c++... MGlobal::executeCommand( ( boost::format( "removeMultiInstance %s" ) % preMatrixPlug.name() ).str().c_str() ); } // get the geometry MObjectArray outputGeoObjs; if ( !fnSkinCluster.getOutputGeometry( outputGeoObjs ) ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: skinCluster \"%s\" does not have any output geometry!" ) % fnSkinCluster.name() ).str() ); } MFnDagNode dagFn( outputGeoObjs[0] ); MDagPath geoPath; dagFn.getPath( geoPath ); // loop through all the points of the geometry and set the weights MItGeometry geoIt( outputGeoObjs[0] ); MPlug weightListArrayPlug = fnSkinClusterNode.findPlug( "weightList", true, &s ); for ( unsigned pIndex=0; !geoIt.isDone(); geoIt.next(), pIndex++ ) { MPlug pointWeightsPlug = weightListArrayPlug.elementByLogicalIndex( pIndex, &s ).child( 0 ); // remove existing influence weight plugs MIntArray existingInfluenceIndices; pointWeightsPlug.getExistingArrayAttributeIndices( existingInfluenceIndices ); for( unsigned i=0; i < existingInfluenceIndices.length(); i++ ) { MPlug influenceWeightPlug = pointWeightsPlug.elementByLogicalIndex( existingInfluenceIndices[i], &s ); MGlobal::executeCommand( ( boost::format( "removeMultiInstance -break 1 %s" ) % influenceWeightPlug.name() ).str().c_str() ); } // add new influence weight plugs int firstIndex = pointIndexOffsets[pIndex]; for( int i=0; i < pointInfluenceCounts[pIndex]; i++ ) { int influenceIndex = pointInfluenceIndices[ firstIndex + i ]; if ( ignoreInfluence[ influenceIndex ] ) { continue; } int skinClusterInfluenceIndex = fnSkinCluster.indexForInfluenceObject( influencePaths[ indexMap[ influenceIndex ] ] ); MPlug influenceWeightPlug = pointWeightsPlug.elementByLogicalIndex( skinClusterInfluenceIndex, &s ); influenceWeightPlug.setValue( pointInfluenceWeights[ firstIndex + i ] ); } } return true; }
// returns 0 if static, 1 if sampled, and 2 if a curve int util::getSampledType(const MPlug& iPlug) { MPlugArray conns; iPlug.connectedTo(conns, true, false); // it's possible that only some element of an array plug or // some component of a compound plus is connected if (conns.length() == 0) { if (iPlug.isArray()) { unsigned int numConnectedElements = iPlug.numConnectedElements(); for (unsigned int e = 0; e < numConnectedElements; e++) { int retVal = getSampledType(iPlug.connectionByPhysicalIndex(e)); if (retVal > 0) return retVal; } } else if (iPlug.isCompound() && iPlug.numConnectedChildren() > 0) { unsigned int numChildren = iPlug.numChildren(); for (unsigned int c = 0; c < numChildren; c++) { int retVal = getSampledType(iPlug.child(c)); if (retVal > 0) return retVal; } } return 0; } MObject ob; MFnDependencyNode nodeFn; for (unsigned i = 0; i < conns.length(); i++) { ob = conns[i].node(); MFn::Type type = ob.apiType(); switch (type) { case MFn::kAnimCurveTimeToAngular: case MFn::kAnimCurveTimeToDistance: case MFn::kAnimCurveTimeToTime: case MFn::kAnimCurveTimeToUnitless: { nodeFn.setObject(ob); MPlug incoming = nodeFn.findPlug("i", true); // sampled if (incoming.isConnected()) return 1; // curve else return 2; } break; case MFn::kMute: { nodeFn.setObject(ob); MPlug mutePlug = nodeFn.findPlug("mute", true); // static if (mutePlug.asBool()) return 0; // curve else return 2; } break; default: break; } } return 1; }
void ShadingNetworkExporter::createShader(const MObject& node) { MStatus status; MFnDependencyNode depNodeFn(node); const OSLShaderInfo *shaderInfo = ShadingNodeRegistry::getShaderInfo(depNodeFn.typeName()); if(!shaderInfo) { std::cout << "Skipping unsupported shader: " << depNodeFn.typeName() << "\n"; return; } if(m_shadersExported.count(depNodeFn.name()) != 0) { std::cout << "Skipping already exported shader: " << depNodeFn.name() << "\n"; return; } m_shadersExported.insert(depNodeFn.name()); asr::ParamArray shaderParams; for(int i = 0, e = shaderInfo->paramInfo.size(); i < e; ++i) { const OSLParamInfo& paramInfo = shaderInfo->paramInfo[i]; // Skip output attributes. if(paramInfo.isOutput) { std::cout << "Skipping output attribute: " << "\n"; std::cout << paramInfo << std::endl; continue; } if(!paramInfo.validDefault) { std::cout << "Skipping attribute without valid default: " << "\n"; std::cout << paramInfo << std::endl; continue; } if(paramInfo.isArray) { std::cout << "Skipping array attribute: " << "\n"; std::cout << paramInfo << std::endl; continue; } MPlug plug = depNodeFn.findPlug(paramInfo.mayaAttributeName, &status); if(!status) { std::cout << "Skipping unknown attribute: " << paramInfo.mayaAttributeName << std::endl; continue; } if(plug.isConnected()) { MObject srcNode; if(AttributeUtils::get(plug, srcNode)) createShader(srcNode); continue; } if(plug.isCompound() && plug.numConnectedChildren() != 0) { std::cout << "Skipping connected compound attribute: " << plug.name() << "\n"; continue; } if(plug.isArray() && plug.numConnectedElements() != 0) { std::cout << "Skipping connected array attribute: " << plug.name() << "\n"; continue; } processAttribute(plug, paramInfo, shaderParams); } m_shaderGroup->add_shader( shaderInfo->shaderType.asChar(), shaderInfo->shaderName.asChar(), depNodeFn.name().asChar(), shaderParams); }
PxrUsdMayaShadingModeExportContext::AssignmentVector PxrUsdMayaShadingModeExportContext::GetAssignments() const { AssignmentVector ret; MStatus status; MFnDependencyNode seDepNode(_shadingEngine, &status); if (!status) { return ret; } MPlug dsmPlug = seDepNode.findPlug("dagSetMembers", true, &status); if (!status) { return ret; } SdfPathSet seenBoundPrimPaths; for (unsigned int i = 0; i < dsmPlug.numConnectedElements(); i++) { MPlug dsmElemPlug(dsmPlug.connectionByPhysicalIndex(i)); MStatus status = MS::kFailure; MFnDagNode dagNode(PxrUsdMayaUtil::GetConnected(dsmElemPlug).node(), &status); if (!status) { continue; } MDagPath dagPath; if (!dagNode.getPath(dagPath)) continue; SdfPath usdPath = PxrUsdMayaUtil::MDagPathToUsdPath(dagPath, _mergeTransformAndShape); // If _overrideRootPath is not empty, replace the root namespace with it if (!_overrideRootPath.IsEmpty() ) { usdPath = usdPath.ReplacePrefix(usdPath.GetPrefixes()[0], _overrideRootPath); } // If this path has already been processed, skip it. if (!seenBoundPrimPaths.insert(usdPath).second) continue; // If the bound prim's path is not below a bindable root, skip it. if (SdfPathFindLongestPrefix(_bindableRoots.begin(), _bindableRoots.end(), usdPath) == _bindableRoots.end()) { continue; } MObjectArray sgObjs, compObjs; // Assuming that instancing is not involved. status = dagNode.getConnectedSetsAndMembers(0, sgObjs, compObjs, true); if (!status) continue; for (size_t j = 0; j < sgObjs.length(); j++) { // If the shading group isn't the one we're interested in, skip it. if (sgObjs[j] != _shadingEngine) continue; VtIntArray faceIndices; if (!compObjs[j].isNull()) { MItMeshPolygon faceIt(dagPath, compObjs[j]); faceIndices.reserve(faceIt.count()); for ( faceIt.reset() ; !faceIt.isDone() ; faceIt.next() ) { faceIndices.push_back(faceIt.index()); } } ret.push_back(std::make_pair(usdPath, faceIndices)); } } return ret; }
void ShadingNetworkExporter::addConnections(const MObject& node) { MStatus status; MFnDependencyNode depNodeFn(node); const OSLShaderInfo *shaderInfo = ShadingNodeRegistry::getShaderInfo(depNodeFn.typeName()); if(!shaderInfo) { std::cout << "Skipping unsupported shader: " << depNodeFn.typeName() << "\n"; return; } if(m_shadersExported.count(depNodeFn.name()) != 0) { std::cout << "Skipping already exported shader: " << depNodeFn.name() << "\n"; return; } m_shadersExported.insert(depNodeFn.name()); for(int i = 0, e = shaderInfo->paramInfo.size(); i < e; ++i) { const OSLParamInfo& paramInfo = shaderInfo->paramInfo[i]; // Skip output attributes. if(paramInfo.isOutput) continue; MPlug plug = depNodeFn.findPlug(paramInfo.mayaAttributeName, &status); if(!status) { std::cout << "Skipping unknown attribute: " << paramInfo.mayaAttributeName << std::endl; continue; } if(plug.isConnected()) { MPlug srcPlug; if(AttributeUtils::getPlugConnectedTo(plug, srcPlug)) { MFnDependencyNode srcDepNodeFn(srcPlug.node()); const OSLShaderInfo *srcShaderInfo = ShadingNodeRegistry::getShaderInfo(srcDepNodeFn.typeName()); if(!srcShaderInfo) continue; if(const OSLParamInfo *srcParamInfo = srcShaderInfo->findParam(srcPlug.name())) { m_shaderGroup->add_connection( srcDepNodeFn.name().asChar(), srcParamInfo->paramName.asChar(), depNodeFn.name().asChar(), paramInfo.paramName.asChar()); } addConnections(srcPlug.node()); } } if(plug.isCompound() && plug.numConnectedChildren() != 0) { // ??? } if(plug.isArray() && plug.numConnectedElements() != 0) { // ??? } } }