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] ); size_t pointCount = geoIt.exactCount(); if( pointCount != pointIndexOffsets.size() ) { throw IECore::Exception( ( boost::format( "ToMayaSkinClusterConverter: topology of skinCluster \"%s\"'s output geometry has changed!" ) % fnSkinCluster.name() ).str() ); } 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; }
void CoronaRenderer::defineMaterial(Corona::IInstance* instance, std::shared_ptr<MayaObject> mobj) { std::shared_ptr<mtco_MayaObject> obj = std::static_pointer_cast<mtco_MayaObject>(mobj); MFnDependencyNode globalsNode(objectFromName("coronaGlobals")); if (getBoolAttr("useGlobalMaterialOverride", globalsNode, false)) { MObject surfaceShader = getOtherSideNode(MString("globalMaterialOverride"), globalsNode.object()); // get shading group for reuse MFnDependencyNode surfaceShaderNode(surfaceShader); MPlug outColorPlug = surfaceShaderNode.findPlug("outColor"); MObject shadingGroupObject; if (outColorPlug.isConnected()) { MPlugArray outArray; outColorPlug.connectedTo(outArray, false, true); if (outArray.length() > 0) { shadingGroupObject = outArray[0].node(); } } if (shadingGroupObject != MObject::kNullObj) if (assingExistingMat(shadingGroupObject, obj)) return; Corona::SharedPtr<Corona::IMaterial> base = defineCoronaMaterial(surfaceShader, obj); Corona::IMaterialSet ms = Corona::IMaterialSet(base); setRenderStats(ms, obj); obj->instance->addMaterial(ms); return; } getObjectShadingGroups(obj->dagPath, obj->perFaceAssignments, obj->shadingGroups, false); if( obj->shadingGroups.length() > 0) { for (uint sgId = 0; sgId < obj->shadingGroups.length(); sgId++) { MObject shadingGroup = obj->shadingGroups[sgId]; Logging::debug(MString("---------- Check shading group: ") + getObjectName(shadingGroup) + " for existence on object named " + obj->fullName); if (assingExistingMat(shadingGroup, obj)) return; MObject surfaceShader = getConnectedInNode(shadingGroup, "surfaceShader"); // check obj set overrides MObject connectedSet = getConnectedObjSet(obj->dagPath); if (connectedSet != MObject::kNullObj) { MFnDependencyNode setFn(connectedSet); Logging::debug(MString("Found connected object set:") + setFn.name()); MPlug shaderOverride = setFn.findPlug("mtco_mtlOverride"); if (!shaderOverride.isNull()) { MObject connectedObject = getConnectedInNode(shaderOverride); if (connectedObject != MObject::kNullObj) surfaceShader = connectedObject; } } // raytype shader is a special case. Here a material set gets different materials, so I have to call defineCoronaMaterial several times MFnDependencyNode shaderMat(surfaceShader); Corona::SharedPtr<Corona::IMaterial> base = nullptr; Corona::SharedPtr<Corona::IMaterial> reflect = nullptr; Corona::SharedPtr<Corona::IMaterial> refract = nullptr; Corona::SharedPtr<Corona::IMaterial> direct = nullptr; if (shaderMat.typeName() == "CoronaRaytype") { MPlug basePlug = shaderMat.findPlug("base"); MPlug reflectPlug = shaderMat.findPlug("reflect"); MPlug refractPlug = shaderMat.findPlug("refract"); MPlug directPlug = shaderMat.findPlug("direct"); if (basePlug.isConnected()) { MObject inNode = getConnectedInNode(basePlug); base = defineCoronaMaterial(inNode, nullptr); } if (reflectPlug.isConnected()) { MObject inNode = getConnectedInNode(reflectPlug); reflect = defineCoronaMaterial(inNode, nullptr); } if (refractPlug.isConnected()) { MObject inNode = getConnectedInNode(refractPlug); refract = defineCoronaMaterial(inNode, nullptr); } if (directPlug.isConnected()) { MObject inNode = getConnectedInNode(directPlug); direct = defineCoronaMaterial(inNode, nullptr); } } else{ base = defineCoronaMaterial(surfaceShader, obj); } Corona::IMaterialSet ms = Corona::IMaterialSet(base); ms.overrides.direct = direct; ms.overrides.reflect = reflect; ms.overrides.refract = refract; setRenderStats(ms, obj); obj->instance->addMaterial(ms); } } else{ Corona::SharedPtr<Corona::IMaterial> mat = defineCoronaMaterial(MObject::kNullObj, nullptr); Corona::IMaterialSet ms = Corona::IMaterialSet(mat); setRenderStats(ms, obj); obj->instance->addMaterial(ms); } }
/** * Build the animation from Maya MotionPath */ osg::ref_ptr<osg::AnimationPath> Transform::motionPath2AnimationPath(MObject &obj) { osg::ref_ptr<osg::AnimationPath> anim = new osg::AnimationPath(); // STEP 1. Get the animation curve from this MotionPath MFnMotionPath motion; MFnDependencyNode dn(obj); MPlugArray conns; dn.getConnections(conns); for(int i=0; i<conns.length(); i++){ MPlug conn = conns[i]; MPlugArray connectedTo; // Get the connections having this node as destination conn.connectedTo(connectedTo, true, false); for(int j=0; j<connectedTo.length(); j++){ MPlug origin = connectedTo[j]; MObject origin_node = origin.node(); if(origin_node.hasFn(MFn::kMotionPath)){ motion.setObject(origin_node); break; } } } MFnAnimCurve anim_curve; dn.setObject(motion.object()); dn.getConnections(conns); for(int i=0; i<conns.length(); i++){ MPlug conn = conns[i]; MPlugArray connectedTo; // Get the connections having this node as destination conn.connectedTo(connectedTo, true, false); for(int j=0; j<connectedTo.length(); j++){ MPlug origin = connectedTo[j]; MObject origin_node = origin.node(); if(origin_node.hasFn(MFn::kAnimCurve)){ anim_curve.setObject(origin_node); break; } } } // STEP 2 ... // STEP 3. Benefits! for(int i=0; i<anim_curve.numKeys(); i++){ MTime t = anim_curve.time(i); double time = t.as(MTime::kSeconds); MAnimControl::setCurrentTime(MTime(time,MTime::kSeconds)); anim->insert(time, osg::AnimationPath::ControlPoint( getCPPosition(obj), getCPRotation(obj), getCPScale(obj) )); } return anim; }
void ParameterisedHolder<B>::nonNetworkedConnections( const MPlug &plug, MPlugArray &connectionsFromPlug, MPlugArray &connectionsToPlug ) const { MPlugArray from; MPlugArray to; // the MPlug.connectedTo() method is documented as always returning networked plugs. plug.connectedTo( from, false, true ); plug.connectedTo( to, true, false ); connectionsFromPlug.clear(); connectionsFromPlug.setLength( from.length() ); connectionsToPlug.clear(); connectionsToPlug.setLength( to.length() ); for( unsigned i=0; i<from.length(); i++ ) { // the MPlug( node, attribute ) constructor is documented as always returning non-networked plugs. connectionsFromPlug.set( MPlug( from[i].node(), from[i].attribute() ), i ); } for( unsigned i=0; i<to.length(); i++ ) { connectionsToPlug.set( MPlug( to[i].node(), to[i].attribute() ), i ); } }
/** * Build the animation from Maya AnimCurves */ osg::ref_ptr<osg::AnimationPath> Transform::animCurve2AnimationPath(MObject &obj) { osg::ref_ptr<osg::AnimationPath> anim = new osg::AnimationPath(); // STEP 1. Get the animation curves MFnAnimCurve tx, ty, tz, rx, ry, rz, sx, sy, sz; MFnDependencyNode dn(obj); MPlugArray conns; dn.getConnections(conns); for(int i=0; i<conns.length(); i++){ MPlug conn = conns[i]; MPlugArray connectedTo; // Get the connections having this node as destination conn.connectedTo(connectedTo, true, false); for(int j=0; j<connectedTo.length(); j++){ MPlug origin = connectedTo[j]; MObject origin_node = origin.node(); if(origin_node.hasFn(MFn::kAnimCurve)){ if(conn.name() == dn.name() + ".translateX" ){ tx.setObject(origin_node); } else if(conn.name() == dn.name() + ".translateY" ){ ty.setObject(origin_node); } else if(conn.name() == dn.name() + ".translateZ" ){ tz.setObject(origin_node); } else if(conn.name() == dn.name() + ".rotateX" ){ rx.setObject(origin_node); } else if(conn.name() == dn.name() + ".rotateY" ){ ry.setObject(origin_node); } else if(conn.name() == dn.name() + ".rotateZ" ){ rz.setObject(origin_node); } else if(conn.name() == dn.name() + ".scaleX" ){ sx.setObject(origin_node); } else if(conn.name() == dn.name() + ".scaleY" ){ sy.setObject(origin_node); } else if(conn.name() == dn.name() + ".scaleZ" ){ sz.setObject(origin_node); } else { std::cout << "Animation curve connected to parameter " << conn.name().asChar() << " (not supported)" << std::endl; } } } } // STEP 2. Build the AnimationPath from animation curves // Search the first key in time from all the AnimCurves bool t_present=false; double mint=0; #define VALID_CURVE(f) ( f.object() != MObject::kNullObj ) #define GETMIN(f) if(VALID_CURVE(f)) { \ double t = f.time(0).as(MTime::kSeconds); \ if( !t_present || t < mint ) \ mint = t; \ t_present = true; \ } GETMIN(tx); GETMIN(ty); GETMIN(tz); GETMIN(rx); GETMIN(ry); GETMIN(rz); GETMIN(sx); GETMIN(sy); GETMIN(sz); // Set the right time in Maya timeline so all properties are updated MAnimControl::setCurrentTime(MTime(mint,MTime::kSeconds)); // Create ControlPoint for initial time anim->insert(mint, osg::AnimationPath::ControlPoint( getCPPosition(obj), getCPRotation(obj), getCPScale(obj) )); double t_prev = mint; // Locate the time of the next key (in any curve) #define GET_NEXT(f) if(VALID_CURVE(f)) { \ for(int c=0; c<f.numKeys(); c++){ \ double t = f.time(c).as(MTime::kSeconds); \ if(t > t_prev && !t_present){ \ t_now = t; \ t_present = true; \ break; \ } \ else if(t > t_prev && t < t_now) { \ t_now = t; \ break; \ } \ } \ } // Get next keys cronologically double t_now = t_prev; t_present=false; GET_NEXT(tx); GET_NEXT(ty); GET_NEXT(tz); GET_NEXT(rx); GET_NEXT(ry); GET_NEXT(rz); GET_NEXT(sx); GET_NEXT(sy); GET_NEXT(sz); while(t_now != t_prev){ // Set the right time in Maya timeline so all properties are updated MAnimControl::setCurrentTime(MTime(t_now,MTime::kSeconds)); anim->insert(t_now, osg::AnimationPath::ControlPoint( getCPPosition(obj), getCPRotation(obj), getCPScale(obj) )); t_prev = t_now; t_present=false; GET_NEXT(tx); GET_NEXT(ty); GET_NEXT(tz); GET_NEXT(rx); GET_NEXT(ry); GET_NEXT(rz); GET_NEXT(sx); GET_NEXT(sy); GET_NEXT(sz); } return anim; }