//--------------------------------------------------- // get the first empty item in the named array plug unsigned DagHelper::getFirstEmptyElementId ( const MPlug& parent ) { unsigned num_element = 1; if ( parent.numElements() > num_element ) num_element = parent.numElements(); for ( unsigned i = 0; i< num_element; i++ ) { if ( !parent.elementByLogicalIndex ( i ).isConnected() ) return i; } return parent.numElements() +1; }
// -------------------------------------------------------------------------------------------- void polyModifierCmd::deleteTweaks() // -------------------------------------------------------------------------------------------- { // Now, set the tweak values on the meshNode(s) to zero (History dependent) // MStatus stat; MFnNumericData numDataFn; MObject nullVector; // Create a NULL vector (0,0,0) using MFnNumericData to pass into the plug // MFnDependencyNode depTmpFn(fDagPath.node(),&stat); //stat.perror(""); MPlug meshTweakPlug = depTmpFn.findPlug("pnts"); numDataFn.create( MFnNumericData::k3Float ); numDataFn.setData( 0, 0, 0 ); nullVector = numDataFn.object(); unsigned numTweaks = meshTweakPlug.numElements(); MPlug tweak; for(unsigned i = 0; i < numTweaks; i++ ) { // Access using logical indices since they are the only plugs guaranteed // to hold tweak data. // tweak = meshTweakPlug.elementByPhysicalIndex(i); tweak.setValue( nullVector ); } }
void getConnectedChildPlugs(const char *attrName, MFnDependencyNode& depFn, bool dest, MPlugArray& thisNodePlugs, MPlugArray& otherSidePlugs) { MPlug p = depFn.findPlug(attrName); if (p.isCompound() && !p.isArray()) { getConnectedChildPlugs(p, dest, thisNodePlugs, otherSidePlugs); return; } if (p.isArray()) { for (uint i = 0; i < p.numElements(); i++) { if (p[i].numConnectedChildren() == 0) continue; if (!p[i].isCompound()) getConnectedChildPlugs(p[i], dest, thisNodePlugs, otherSidePlugs); else { if (getAttributeNameFromPlug(p) == MString("colorEntryList")) { getConnectedChildPlugs(p[i].child(1), dest, thisNodePlugs, otherSidePlugs); } } } } }
// -------------------------------------------------------------------------------------------- void polyModifierCmd::collectNodeState() // -------------------------------------------------------------------------------------------- { MStatus status; // Collect node state information on the given polyMeshShape // // - HasHistory (Construction History exists) // - HasTweaks // - HasRecordHistory (Construction History is turned on) // fDagPath.extendToShape(); MObject meshNodeShape = fDagPath.node(); MFnDependencyNode depNodeFn; depNodeFn.setObject( meshNodeShape ); MPlug inMeshPlug = depNodeFn.findPlug( "inMesh" ); fHasHistory = inMeshPlug.isConnected(); // Tweaks exist only if the multi "pnts" attribute contains plugs // which contain non-zero tweak values. Use false, until proven true // search algorithm. // fHasTweaks = false; MPlug tweakPlug = depNodeFn.findPlug( "pnts" ); if( !tweakPlug.isNull() ) { // ASSERT: tweakPlug should be an array plug! // MAssert( (tweakPlug.isArray()), "tweakPlug.isArray() -- tweakPlug is not an array plug" ); MPlug tweak; MFloatVector tweakData; int i; int numElements = tweakPlug.numElements(); for( i = 0; i < numElements; i++ ) { tweak = tweakPlug.elementByPhysicalIndex( i, &status ); if( status == MS::kSuccess && !tweak.isNull() ) { getFloat3PlugValue( tweak, tweakData ); if( 0 != tweakData.x || 0 != tweakData.y || 0 != tweakData.z ) { fHasTweaks = true; break; } } } } int result; MGlobal::executeCommand( "constructionHistory -q -tgl", result ); fHasRecordHistory = (0 != result); }
void SurfaceAttach::inUVs(MFnDependencyNode &fn) { MPlug inUVPlug = fn.findPlug("inUV"); const std::uint32_t numElements = inUVPlug.numElements(); this->uInputs.resize((size_t)(numElements)); this->vInputs.resize((size_t)(numElements)); for (std::uint32_t i=0; i < numElements; i++){ MPlug uvPlug = inUVPlug.elementByLogicalIndex(i); this->uInputs[i] = uvPlug.child(0).asDouble(); this->vInputs[i] = uvPlug.child(1).asDouble(); } }
void getDirectConnectedPlugs(const char *attrName, MFnDependencyNode& depFn, bool dest, MPlugArray& thisNodePlugs, MPlugArray& otherSidePlugs) { MPlug thisPlug = depFn.findPlug(attrName); if (!thisPlug.isArray()) { if (thisPlug.isConnected()) { thisNodePlugs.append(thisPlug); otherSidePlugs.append(getDirectConnectedPlug(thisPlug, dest)); } return; } for (uint i = 0; i < thisPlug.numElements(); i++) { if (thisPlug.isCompound()) { // we only support simple compounds like colorListEntry if (MString(attrName) == MString("colorEntryList")) { MPlug element = thisPlug[i]; if (element.child(0).isConnected()) { MPlug connectedPlug = element.child(0); thisNodePlugs.append(connectedPlug); otherSidePlugs.append(getDirectConnectedPlug(connectedPlug, dest)); } if (element.child(1).isConnected()) { MPlug connectedPlug = element.child(1); thisNodePlugs.append(connectedPlug); otherSidePlugs.append(getDirectConnectedPlug(connectedPlug, dest)); } } } else{ if (!thisPlug[i].isConnected()) { continue; } MPlug connectedPlug = thisPlug[i]; thisNodePlugs.append(connectedPlug); otherSidePlugs.append(getDirectConnectedPlug(connectedPlug, dest)); } } }
int physicalIndex(MPlug& p) { MPlug parent = p; while (parent.isChild()) parent = parent.parent(); if (!parent.isElement()) return -1; if (!parent.array()) return - 1; MPlug arrayPlug = parent.array(); for (uint i = 0; i < arrayPlug.numElements(); i++) if (arrayPlug[i].logicalIndex() == parent.logicalIndex()) return i; return -1; }
// ------------------------------------------- bool AnimationHelper::isPhysicsAnimation ( const MObject& o ) { if ( o.hasFn ( MFn::kChoice ) ) { MFnDependencyNode n ( o ); MPlug p = n.findPlug ( "input" ); uint choiceCount = p.numElements(); for ( uint i = 0; i < choiceCount; ++i ) { MPlug child = p.elementByPhysicalIndex ( i ); MObject connection = DagHelper::getSourceNodeConnectedTo ( child ); if ( !connection.isNull() && connection != o ) if ( isPhysicsAnimation ( connection ) ) return true; } } else if ( o.hasFn ( MFn::kRigidSolver ) || o.hasFn ( MFn::kRigid ) ) return true; return false; }
//--------------------------------------------------- // // Find a node connected to a node's array attribute // bool DagHelper::getPlugArrayConnectedTo ( const MObject& node, const MString& attribute, MPlug& connectedPlug ) { MStatus status; MFnDependencyNode dgFn ( node ); MPlug plug = dgFn.findPlug ( attribute, &status ); if ( status != MS::kSuccess ) { MGlobal::displayWarning ( MString ( "couldn't find plug on attribute " ) + attribute + MString ( " on object " ) + dgFn.name() ); return false; } if ( plug.numElements() < 1 ) { MGlobal::displayWarning ( MString ( "plug array doesn't have any connection on attribute " ) + attribute + MString ( " on object " ) + dgFn.name() ); return false; } MPlug firstElementPlug = plug.connectionByPhysicalIndex ( 0 ); // Get the connection - there can be at most one input to a plug // MPlugArray connections; firstElementPlug.connectedTo ( connections, true, true ); if ( connections.length() == 0 ) { MGlobal::displayWarning ( MString ( "plug connected to an empty array on attribute " ) + attribute + MString ( " on object " ) + dgFn.name() ); return false; } connectedPlug = connections[0]; return true; }
int tm_polygon::removeTweaks_Func( MSelectionList &selectionList) { MStatus status; MObject object; status = selectionList.getDependNode( 0, object); if(!status) { MGlobal::displayError("***### tm_polygon: Can't find object."); return 0; } MFnMesh mesh( object, &status); if(!status) { MGlobal::displayError("***### tm_polygon: Can't find mesh."); return 0; } int pntsCount = 0; MPlug pntsPlug = mesh.findPlug( "pnts" ); if( !pntsPlug.isNull() ) { MPlug tweakPlug; MObject nullVector_object; MFnNumericData numDataFn( nullVector_object ); // numDataFn.setData3Double( 0.0, 0.0, 0.0 ); numDataFn.setData( 0.0, 0.0, 0.0 ); pntsCount = pntsPlug.numElements(); for( int i = 0; i < pntsCount; i++ ) { tweakPlug = pntsPlug.elementByPhysicalIndex( (unsigned int)i, &status ); if( status == MS::kSuccess && !tweakPlug.isNull() ) tweakPlug.setValue( nullVector_object ); } } return pntsCount; }
void MG_vectorGL::draw( M3dView & view, const MDagPath & path, M3dView::DisplayStyle dispStyle, M3dView::DisplayStatus status ) { MPlug drawItP (thisMObject(),drawIt); bool drawItV; drawItP.getValue(drawItV); MPlug arrowSizeP (thisMObject(),arrowSize); double arrowSizeV; arrowSizeP.getValue(arrowSizeV); MPlug upVecP (thisMObject(),upVec); MVector upVecV; upVecP.child(0).getValue(upVecV.x); upVecP.child(1).getValue(upVecV.y); upVecP.child(2).getValue(upVecV.z); MPlug vecsP (thisMObject(),vecs); MPlug startPointP (thisMObject(),startPoint); int elemVecs = vecsP.numElements(); int elemPoints = startPointP.numElements(); if ( drawItV == 0 ) { return ; } if (elemVecs != elemPoints ) { return; } // Draw it view.beginGL(); glPushAttrib( GL_ALL_ATTRIB_BITS ); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glLineWidth(2); if(status == M3dView::kLead) glColor4f(0.0,1.0,0.0,1.0f); else glColor4f(1.0,1.0,0.0,1.0f); for ( unsigned int i = 0 ; i < elemVecs ; i++ ) { vecsP.selectAncestorLogicalIndex( i , vecs); startPointP.selectAncestorLogicalIndex( i , startPoint); MVector currentVec ; MPoint currentPoint; vecsP.child(0).getValue(currentVec.x); vecsP.child(1).getValue(currentVec.y); vecsP.child(2).getValue(currentVec.z); startPointP.child(0).getValue(currentPoint.x); startPointP.child(1).getValue(currentPoint.y); startPointP.child(2).getValue(currentPoint.z); drawArrow(currentVec , upVecV , arrowSizeV , currentPoint); } glDisable(GL_BLEND); glPopAttrib(); }
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; }
MStatus CmpMeshModifierCmd::transferTweaks( const MDagPath &shapePath, MObject &tweakNode, MDagModifier &dagMod ) { // Get the tweaks from the mesh shape and apply them to the // to the tweak node MFnDagNode shapeNodeFn( shapePath ); MPlug srcTweaksPlug = shapeNodeFn.findPlug( "pnts" ); MFnDependencyNode tweakNodeFn( tweakNode ); MPlug dstTweaksPlug = tweakNodeFn.findPlug( "tweak" ); //MGlobal::displayInfo( MString( "storing tweaks from " ) + shapePath.fullPathName() + "\n" ); MPlugArray plugs; MPlug srcTweakPlug; MPlug dstTweakPlug; MObject dataObj; MFloatVector tweak; unsigned int nTweaks = srcTweaksPlug.numElements(); unsigned int i, j, ci, logicalIndex; for( i=0; i < nTweaks; i++ ) { srcTweakPlug = srcTweaksPlug.elementByPhysicalIndex( i ); if( !srcTweakPlug.isNull() ) { logicalIndex = srcTweakPlug.logicalIndex(); // Set tweak node tweak element srcTweakPlug.getValue( dataObj ); MFnNumericData numDataFn( dataObj ); numDataFn.getData( tweak[0], tweak[1], tweak[2] ); dagMod.commandToExecute( MString( "setAttr " ) + tweakNodeFn.name() + ".tweak[" + logicalIndex + "] " + tweak[0] + " " + tweak[1] + " " + tweak[2] ); // Handle transfer of incoming and outgoing connections to "pnts" elements dstTweakPlug = dstTweaksPlug.elementByLogicalIndex(logicalIndex); if( srcTweakPlug.isConnected() ) { // As source, transfer source to tweak node tweak srcTweakPlug.connectedTo( plugs, false, true ); for( j=0; j < plugs.length(); j++ ) { dagMod.disconnect( srcTweakPlug, plugs[j] ); dagMod.connect( dstTweakPlug, plugs[j] ); } // As destination, transfer destination to tweak node tweak srcTweakPlug.connectedTo( plugs, true, false ); if( plugs.length() == 1 ) // There can only be one input connection { dagMod.disconnect( plugs[0], srcTweakPlug ); dagMod.connect( plugs[0], dstTweakPlug ); } } else // Check children { MPlug srcTweakChildPlug; MPlug dstTweakChildPlug; for( ci=0; ci < srcTweakPlug.numChildren(); ci++ ) { srcTweakChildPlug = srcTweakPlug.child(ci); dstTweakChildPlug = dstTweakPlug.child(ci); if( srcTweakChildPlug.isConnected() ) { // As souce, transfer source to tweak node tweak srcTweakChildPlug.connectedTo( plugs, false, true ); for( j=0; j < plugs.length(); j++ ) { dagMod.disconnect( srcTweakChildPlug, plugs[j] ); dagMod.connect( dstTweakChildPlug, plugs[j] ); } // As destination, transfer destination to tweak node tweak srcTweakChildPlug.connectedTo( plugs, true, false ); if( plugs.length() == 1 ) // There can only be one input connection { dagMod.disconnect( plugs[0], srcTweakChildPlug ); dagMod.connect( plugs[0], dstTweakChildPlug ); } } } } // With the tweak values and any connections now transferred to // the tweak node's tweak element, this source element can be reset dagMod.commandToExecute( MString( "setAttr " ) + shapePath.fullPathName() + ".pnts[" + logicalIndex + "] 0 0 0" ); //MGlobal::displayInfo( MString(" tweak: ") + tweakIndices[i] + ": " + tweaks[i].x + ", " + tweaks[i].y + ", " + tweaks[i].z + "\n" ); } } return MS::kSuccess; }
MStatus CmpMeshModifierCmd::doIt( const MDagPath &dagPath, const MTypeId &meshModType ) { MStatus stat; meshShapePath = dagPath; if( !meshShapePath.isValid() ) { displayError( "Invalid mesh shape path: " + meshShapePath.fullPathName() ); return MS::kFailure; } meshModifierNodeType = meshModType; // // Get the current state of the history // MFnDagNode origShapeNodeFn( meshShapePath ); // Determine if the mesh has history MPlug inMeshOrigPlug = origShapeNodeFn.findPlug( "inMesh" ); hasHistory = inMeshOrigPlug.isConnected(); // Determine if the mesh has tweaks hasInternalTweaks = false; MPlug tweaksPlug = origShapeNodeFn.findPlug( "pnts" ); if( !tweaksPlug.isNull() ) { MObject obj; MPlug tweakPlug; MFloatVector tweak; unsigned int i; unsigned int nTweaks = tweaksPlug.numElements(); for( i=0; i < nTweaks; i++ ) { tweakPlug = tweaksPlug.elementByPhysicalIndex( i, &stat ); if( stat && !tweakPlug.isNull() ) { tweakPlug.getValue( obj ); MFnNumericData numDataFn( obj ); numDataFn.getData( tweak[0], tweak[1], tweak[2] ); if( tweak[0] != 0.0f || tweak[1] != 0.0f || tweak[2] != 0.0f ) { hasInternalTweaks = true; break; } } } } int res; MGlobal::executeCommand( "constructionHistory -query -toggle", res ); genHistory = res != 0; //MGlobal::displayInfo( MString("resulting: ") + hasHistory + " " + hasInternalTweaks + " " + genHistory + "\n" ); // When there is no existing history // cache the mesh data for later undoing // if( !hasHistory ) { MPlug meshPlug = origShapeNodeFn.findPlug( hasInternalTweaks ? "cachedInMesh" : "outMesh" ); meshPlug.getValue( origMeshData ); } // Create the modifier node MObject modNode = dagMods[0].MDGModifier::createNode( meshModifierNodeType, &stat ); // Create tweak node MObject tweakNode = dagMods[0].MDGModifier::createNode( "polyTweak", &stat ); // Execute DAG modifier to ensure that the nodes actually exist dagMods[0].doIt(); // Check that the inMesh and outMesh attributes exist in the modifier node MFnDependencyNode nodeFn( modNode ); if( nodeFn.attribute( "inMesh" ).isNull() || nodeFn.attribute( "outMesh" ).isNull() ) { displayError( "Invalid modifier node. It doesn't have inMesh and/or outMesh attributes" ); return MS::kFailure; } // Let the derived command class initialize the modifier node initModifierNode( modNode, dagMods[1] ); MFnDependencyNode modNodeFn( modNode ); // Get plug that is the start of the new stream MPlug newStreamInMeshPlug = modNodeFn.findPlug( "inMesh" ); // Get the plug connecting into original shape's inMesh MPlugArray inPlugs; inMeshOrigPlug.connectedTo( inPlugs, true, false ); MPlug oldStreamOutMeshPlug; // N.B. For meshes without construction history // there won't be incoming connection if( inPlugs.length() ) { oldStreamOutMeshPlug = inPlugs[0]; // Disconnect the connection into the mesh shape's inMesh attribute. // The outMesh of the modifier node will later connect into this. dagMods[1].disconnect( oldStreamOutMeshPlug, inMeshOrigPlug ); } if( hasInternalTweaks ) { // Transfer tweaks from the mesh shape to the tweak node transferTweaks( meshShapePath, tweakNode, dagMods[1] ); MFnDependencyNode tweakNodeFn( tweakNode ); newStreamInMeshPlug = tweakNodeFn.findPlug( "inputPolymesh" ); // Connect output of tweak node into modifier node MPlug inMeshModPlug = modNodeFn.findPlug( "inMesh" ); MPlug outMeshTweakPlug = tweakNodeFn.findPlug( "output" ); dagMods[1].connect( outMeshTweakPlug, inMeshModPlug ); } dagMods[1].doIt(); copyTransform = MObject::kNullObj; // Generate history for shape that doesn't have one if( !hasHistory ) //&& genHistory ) { // Duplicate the mesh shape node copyTransform = origShapeNodeFn.duplicate(); MFnDagNode copyTransformFn( copyTransform ); MObject copyShapeNode = copyTransformFn.child(0); MFnDagNode copyShapeNodeFn( copyShapeNode ); //MGlobal::displayInfo( MString("copy: transform: ") + copyTransformFn.fullPathName() + " shape name: " + copyShapeNodeFn.fullPathName() + "\n" ); // Set it to be an intermediate object dagMods[2].commandToExecute( "setAttr " + copyShapeNodeFn.fullPathName() + ".intermediateObject true" ); // Set output plug of old stream to be the outMesh of the duplicated shape oldStreamOutMeshPlug = copyShapeNodeFn.findPlug( "outMesh" ); // Rename the duplicate dagMods[2].renameNode( copyShapeNode, copyShapeNodeFn.name() + "Orig" ); // Reparent the shape MObject origTransform = meshShapePath.transform(); dagMods[2].reparentNode( copyShapeNode, origTransform ); // Remove the now orphaned transform // N.B. calling deleteNode( transformCopy ) causes the shape node to // also be deleted, even though it has been reparented to the original mesh. // As such, the MEL command "delete" was used instead. // // The deleteNode() method does some // preparation work before it enqueues itself in the MDagModifier list // of operations, namely, it looks at it's parents and children and // deletes them as well if they are the only parent/child of the node // scheduled to be deleted. dagMods[2].commandToExecute( "delete " + copyTransformFn.fullPathName() ); } if( !oldStreamOutMeshPlug.isNull() ) // Connect output mesh of the previous stream the input of the new stream dagMods[2].connect( oldStreamOutMeshPlug, newStreamInMeshPlug ); // Connect output of the mesh modifier node to the input of the original mesh shape MPlug outMeshModPlug = modNodeFn.findPlug( "outMesh" ); dagMods[2].connect( outMeshModPlug, inMeshOrigPlug ); if( !hasHistory && !genHistory ) // Collapse the history dagMods[2].commandToExecute( MString("delete -constructionHistory ") + meshShapePath.fullPathName() ); dagMods[2].doIt(); return MS::kSuccess; }
// Load material data MStatus Material::load(MFnDependencyNode* pShader,MStringArray& uvsets,ParamList& params) { MStatus stat; clear(); //read material name, adding the requested prefix MString tmpStr = params.matPrefix; if (tmpStr != "") tmpStr += "/"; tmpStr += pShader->name(); MStringArray tmpStrArray; tmpStr.split(':',tmpStrArray); m_name = ""; for (int i=0; i<tmpStrArray.length(); i++) { m_name += tmpStrArray[i]; if (i < tmpStrArray.length()-1) m_name += "_"; } //check if we want to export with lighting off option m_lightingOff = params.lightingOff; // GET MATERIAL DATA // Check material type if (pShader->object().hasFn(MFn::kPhong)) { stat = loadPhong(pShader); } else if (pShader->object().hasFn(MFn::kBlinn)) { stat = loadBlinn(pShader); } else if (pShader->object().hasFn(MFn::kLambert)) { stat = loadLambert(pShader); } else if (pShader->object().hasFn(MFn::kPluginHwShaderNode)) { stat = loadCgFxShader(pShader); } else { stat = loadSurfaceShader(pShader); } // Get textures data MPlugArray colorSrcPlugs; MPlugArray texSrcPlugs; MPlugArray placetexSrcPlugs; if (m_isTextured) { // Translate multiple textures if material is multitextured if (m_isMultiTextured) { // Get layered texture node MFnDependencyNode* pLayeredTexNode = NULL; if (m_type == MT_SURFACE_SHADER) pShader->findPlug("outColor").connectedTo(colorSrcPlugs,true,false); else pShader->findPlug("color").connectedTo(colorSrcPlugs,true,false); for (int i=0; i<colorSrcPlugs.length(); i++) { if (colorSrcPlugs[i].node().hasFn(MFn::kLayeredTexture)) { pLayeredTexNode = new MFnDependencyNode(colorSrcPlugs[i].node()); continue; } } // Get inputs to layered texture MPlug inputsPlug = pLayeredTexNode->findPlug("inputs"); // Scan inputs and export textures for (int i=inputsPlug.numElements()-1; i>=0; i--) { MFnDependencyNode* pTextureNode = NULL; // Search for a connected texture inputsPlug[i].child(0).connectedTo(colorSrcPlugs,true,false); for (int j=0; j<colorSrcPlugs.length(); j++) { if (colorSrcPlugs[j].node().hasFn(MFn::kFileTexture)) { pTextureNode = new MFnDependencyNode(colorSrcPlugs[j].node()); continue; } } // Translate the texture if it was found if (pTextureNode) { // Get blend mode TexOpType opType; short bm; inputsPlug[i].child(2).getValue(bm); switch(bm) { case 0: opType = TOT_REPLACE; break; case 1: opType = TOT_ALPHABLEND; break; case 4: opType = TOT_ADD; break; case 6: opType = TOT_MODULATE; break; default: opType = TOT_MODULATE; } stat = loadTexture(pTextureNode,opType,uvsets,params); delete pTextureNode; if (MS::kSuccess != stat) { std::cout << "Error loading layered texture\n"; std::cout.flush(); delete pLayeredTexNode; return MS::kFailure; } } } if (pLayeredTexNode) delete pLayeredTexNode; } // Else translate the single texture else { // Get texture node MFnDependencyNode* pTextureNode = NULL; if (m_type == MT_SURFACE_SHADER) pShader->findPlug("outColor").connectedTo(colorSrcPlugs,true,false); else pShader->findPlug("color").connectedTo(colorSrcPlugs,true,false); for (int i=0; i<colorSrcPlugs.length(); i++) { if (colorSrcPlugs[i].node().hasFn(MFn::kFileTexture)) { pTextureNode = new MFnDependencyNode(colorSrcPlugs[i].node()); continue; } } if (pTextureNode) { TexOpType opType = TOT_MODULATE; stat = loadTexture(pTextureNode,opType,uvsets,params); delete pTextureNode; if (MS::kSuccess != stat) { std::cout << "Error loading texture\n"; std::cout.flush(); return MS::kFailure; } } } } return MS::kSuccess; }
bool PxrUsdTranslators_InstancerWriter::writeInstancerAttrs( const UsdTimeCode& usdTime, const UsdGeomPointInstancer& instancer) { MStatus status = MS::kSuccess; MFnDagNode dagNode(GetDagPath(), &status); CHECK_MSTATUS_AND_RETURN(status, false); // Note: In this function, we don't read instances using the provided // MFnInstancer API. One reason is that it breaks up prototypes into their // constituent shapes, and there's no way to figure out which hierarchy // they came from. Another reason is that it only provides computed matrices // and not separate position, rotation, scale attrs. const SdfPath prototypesGroupPath = instancer.GetPrim().GetPath().AppendChild(_tokens->Prototypes); // At the default time, setup all the prototype instances. if (usdTime.IsDefault()) { const MPlug inputHierarchy = dagNode.findPlug("inputHierarchy", true, &status); CHECK_MSTATUS_AND_RETURN(status, false); // Note that the "Prototypes" prim needs to be a model group to ensure // contiguous model hierarchy. const UsdPrim prototypesGroupPrim = GetUsdStage()->DefinePrim( prototypesGroupPath); UsdModelAPI(prototypesGroupPrim).SetKind(KindTokens->group); _modelPaths.push_back(prototypesGroupPath); UsdRelationship prototypesRel = instancer.CreatePrototypesRel(); const unsigned int numElements = inputHierarchy.numElements(); for (unsigned int i = 0; i < numElements; ++i) { const MPlug plug = inputHierarchy[i]; const MPlug source(UsdMayaUtil::GetConnected(plug)); if (source.isNull()) { TF_WARN("Cannot read prototype: the source plug %s was null", plug.name().asChar()); return false; } MFnDagNode sourceNode(source.node(), &status); CHECK_MSTATUS_AND_RETURN(status, false); MDagPath prototypeDagPath; sourceNode.getPath(prototypeDagPath); // Prototype names are guaranteed unique by virtue of having a // unique numerical suffix _# indicating the prototype index. const TfToken prototypeName( TfStringPrintf("%s_%d", sourceNode.name().asChar(), i)); const SdfPath prototypeUsdPath = prototypesGroupPrim.GetPath() .AppendChild(prototypeName); UsdPrim prototypePrim = GetUsdStage()->DefinePrim( prototypeUsdPath); _modelPaths.push_back(prototypeUsdPath); // Try to be conservative and only create an intermediary xformOp // with the instancerTranslate if we can ensure that we don't need // to compensate for the translation on the prototype root. // // XXX: instancerTranslate does not behave well when added to a // reference that has an existing transform on the far side of the // reference. However, its behavior at least matches the // behavior in UsdMayaTranslatorModelAssembly. If we fix the // behavior there, we need to make sure that this is also // fixed to match. bool instancerTranslateAnimated = false; if (_NeedsExtraInstancerTranslate( prototypeDagPath, &instancerTranslateAnimated)) { UsdGeomXformable xformable(prototypePrim); UsdGeomXformOp newOp = xformable.AddTranslateOp( UsdGeomXformOp::PrecisionDouble, _tokens->instancerTranslate); _instancerTranslateOps.push_back( {prototypeDagPath, newOp, instancerTranslateAnimated}); } // Two notes: // (1) We don't un-instance here, because it's OK for the prototype // to just be a reference to an instance master if the prototype // participates in Maya native instancing. // (2) The prototype root must be visible to match Maya's behavior, // which always vis'es the prototype root, even if it is marked // hidden. _writeJobCtx.CreatePrimWriterHierarchy( prototypeDagPath, prototypeUsdPath, /*forceUninstance*/ false, /*exportRootVisibility*/ false, &_prototypeWriters); prototypesRel.AddTarget(prototypeUsdPath); } _numPrototypes = numElements; } // If there aren't any prototypes, fail and don't export on subsequent // time-sampled exports. if (_numPrototypes == 0) { return false; } // Actual write of prototypes (@ both default time and animated time). for (UsdMayaPrimWriterSharedPtr& writer : _prototypeWriters) { writer->Write(usdTime); if (usdTime.IsDefault()) { // Prototype roots should have kind component or derived. // Calling Write() above may have populated kinds, so don't stomp // over existing component-derived kinds. // (Note that ModelKindWriter's fix-up stage might change this.) if (writer->GetUsdPath().GetParentPath() == prototypesGroupPath) { if (const UsdPrim writerPrim = writer->GetUsdPrim()) { UsdModelAPI primModelAPI(writerPrim); TfToken kind; primModelAPI.GetKind(&kind); if (!KindRegistry::IsA(kind, KindTokens->component)) { primModelAPI.SetKind(KindTokens->component); } } } } } // Write the instancerTranslate xformOp for all prims that need it. // (This should happen @ default time or animated time depending on whether // the xform is animated.) for (const _TranslateOpData& opData : _instancerTranslateOps) { if (opData.isAnimated != usdTime.IsDefault()) { GfVec3d origin; if (_GetTransformedOriginInLocalSpace(opData.mayaPath, &origin)) { UsdGeomXformOp translateOp = opData.op; _SetAttribute(translateOp.GetAttr(), -origin, usdTime); } } } // Grab the inputPoints data from the source plug. // (This attribute's value must come from a source plug; it isn't // directly writeable. Thus reading it directly may not give the right // value depending on Maya's execution behavior.) MPlug inputPointsDest = dagNode.findPlug("inputPoints", true, &status); CHECK_MSTATUS_AND_RETURN(status, false); MPlug inputPointsSrc = UsdMayaUtil::GetConnected(inputPointsDest); if (inputPointsSrc.isNull()) { TF_WARN("inputPoints not connected on instancer '%s'", GetDagPath().fullPathName().asChar()); return false; } auto holder = UsdMayaUtil::GetPlugDataHandle(inputPointsSrc); if (!holder) { TF_WARN("Unable to read inputPoints data handle for instancer '%s'", GetDagPath().fullPathName().asChar()); return false; } MFnArrayAttrsData inputPointsData(holder->GetDataHandle().data(), &status); CHECK_MSTATUS_AND_RETURN(status, false); if (!UsdMayaWriteUtil::WriteArrayAttrsToInstancer( inputPointsData, instancer, _numPrototypes, usdTime, _GetSparseValueWriter())) { return false; } // Load the completed point instancer to compute and set its extent. instancer.GetPrim().GetStage()->Load(instancer.GetPath()); VtArray<GfVec3f> extent(2); if (instancer.ComputeExtentAtTime(&extent, usdTime, usdTime)) { _SetAttribute(instancer.CreateExtentAttr(), &extent, usdTime); } return true; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::processTweaks( modifyPolyData& data ) // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; // Clear tweak undo information (to be rebuilt) // fTweakIndexArray.clear(); fTweakVectorArray.clear(); // Extract the tweaks and place them into a polyTweak node. This polyTweak node // will be placed ahead of the modifier node to maintain the order of operations. // Special care must be taken into recreating the tweaks: // // 1) Copy tweak info (including connections!) // 2) Remove tweak info from both meshNode and a duplicate meshNode (if applicable) // 3) Cache tweak info for undo operations // //if( fHasTweaks && fHasHistory && !speedupTweakProcessing()) if( fHasTweaks && fHasHistory ) { // Declare our function sets // MFnDependencyNode depNodeFn; // Declare our attributes and plugs // MPlug meshTweakPlug; MPlug upstreamTweakPlug; MObject tweakNodeTweakAttr; // Declare our tweak processing variables // MPlug tweak; MPlug tweakChild; MObject tweakData; MObjectArray tweakDataArray; MFloatVector tweakVector; MIntArray tweakSrcConnectionCountArray; MPlugArray tweakSrcConnectionPlugArray; MIntArray tweakDstConnectionCountArray; MPlugArray tweakDstConnectionPlugArray; MPlugArray tempPlugArray; unsigned i; unsigned j; unsigned k; // Create the tweak node and get its attributes // data.tweakNode = fDGModifier.MDGModifier::createNode( "polyTweak" ); depNodeFn.setObject( data.tweakNode ); data.tweakNodeSrcAttr = depNodeFn.attribute( "output" ); data.tweakNodeDestAttr = depNodeFn.attribute( "inputPolymesh" ); tweakNodeTweakAttr = depNodeFn.attribute( "tweak" ); depNodeFn.setObject( data.meshNodeShape ); meshTweakPlug = depNodeFn.findPlug( "pnts" ); // ASSERT: meshTweakPlug should be an array plug! // MStatusAssert( (meshTweakPlug.isArray()), "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" ); unsigned numElements = meshTweakPlug.numElements(); // Gather meshTweakPlug data // for( i = 0; i < numElements; i++ ) { // MPlug::numElements() only returns the number of physical elements // in the array plug. Thus we must use elementByPhysical index when using // the index i. // tweak = meshTweakPlug.elementByPhysicalIndex(i); // If the method fails, the element is NULL. Only append the index // if it is a valid plug. // if( !tweak.isNull() ) { // Cache the logical index of this element plug // unsigned logicalIndex = tweak.logicalIndex(); // Collect tweak data and cache the indices and float vectors // tweak.getValue( tweakData ); tweakDataArray.append( tweakData ); getFloat3PlugValue( tweak, tweakVector ); fTweakIndexArray.append( logicalIndex ); fTweakVectorArray.append( tweakVector ); // Collect tweak connection data // // Parse down to the deepest level of the plug tree and check // for connections - look at the child nodes of the element plugs. // If any connections are found, record the connection and disconnect // it. // // ASSERT: The element plug should be compound! // MStatusAssert( (tweak.isCompound()), "tweak.isCompound() -- Element tweak plug is not compound" ); unsigned numChildren = tweak.numChildren(); for( j = 0; j < numChildren; j++ ) { tweakChild = tweak.child(j); if( tweakChild.isConnected() ) { // Get all connections with this plug as source, if they exist // tempPlugArray.clear(); if( tweakChild.connectedTo( tempPlugArray, false, true ) ) { unsigned numSrcConnections = tempPlugArray.length(); tweakSrcConnectionCountArray.append( numSrcConnections ); for( k = 0; k < numSrcConnections; k++ ) { tweakSrcConnectionPlugArray.append( tempPlugArray[k] ); fDGModifier.disconnect( tweakChild, tempPlugArray[k] ); } } else { tweakSrcConnectionCountArray.append(0); } // Get the connection with this plug as destination, if it exists // tempPlugArray.clear(); if( tweakChild.connectedTo( tempPlugArray, true, false ) ) { // ASSERT: tweakChild should only have one connection as destination! // MStatusAssert( (tempPlugArray.length() == 1), "tempPlugArray.length() == 1 -- 0 or >1 connections on tweakChild" ); tweakDstConnectionCountArray.append(1); tweakDstConnectionPlugArray.append( tempPlugArray[0] ); fDGModifier.disconnect( tempPlugArray[0], tweakChild ); } else { tweakDstConnectionCountArray.append(0); } } else { tweakSrcConnectionCountArray.append(0); tweakDstConnectionCountArray.append(0); } } } } // Apply meshTweakPlug data to our polyTweak node // MPlug polyTweakPlug( data.tweakNode, tweakNodeTweakAttr ); unsigned numTweaks = fTweakIndexArray.length(); int srcOffset = 0; int dstOffset = 0; //Progress initialisieren progressBar progress("Processing Tweaks", numTweaks); for( i = 0; i < numTweaks; i++ ) { // Apply tweak data // tweak = polyTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( tweakDataArray[i] ); // ASSERT: Element plug should be compound! // MStatusAssert( (tweak.isCompound()), "tweak.isCompound() -- Element plug, 'tweak', is not compound" ); unsigned numChildren = tweak.numChildren(); for( j = 0; j < numChildren; j++ ) { tweakChild = tweak.child(j); // Apply tweak source connection data // if( 0 < tweakSrcConnectionCountArray[i*numChildren + j] ) { for( k = 0; k < (unsigned) tweakSrcConnectionCountArray[i*numChildren + j]; k++ ) { fDGModifier.connect( tweakChild, tweakSrcConnectionPlugArray[srcOffset] ); srcOffset++; } } // Apply tweak destination connection data // if( 0 < tweakDstConnectionCountArray[i*numChildren + j] ) { fDGModifier.connect( tweakDstConnectionPlugArray[dstOffset], tweakChild ); dstOffset++; } } if(i%50 == 0) { progress.set(i); } } // Now, set the tweak values on the meshNode(s) to zero (History dependent) // MFnNumericData numDataFn; MObject nullVector; // Create a NULL vector (0,0,0) using MFnNumericData to pass into the plug // numDataFn.create( MFnNumericData::k3Float ); numDataFn.setData( 0, 0, 0 ); nullVector = numDataFn.object(); for( i = 0; i < numTweaks; i++ ) { // Access using logical indices since they are the only plugs guaranteed // to hold tweak data. // tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( nullVector ); } // Only have to clear the tweaks off the duplicate mesh if we do not have history // and we want history. // if( !fHasHistory && fHasRecordHistory ) { depNodeFn.setObject( data.upstreamNodeShape ); upstreamTweakPlug = depNodeFn.findPlug( "pnts" ); if( !upstreamTweakPlug.isNull() ) { for( i = 0; i < numTweaks; i++ ) { tweak = meshTweakPlug.elementByLogicalIndex( fTweakIndexArray[i] ); tweak.setValue( nullVector ); } } } } else fHasTweaks = false; return status; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::cacheMeshTweaks() // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; // Clear tweak undo information (to be rebuilt) // fTweakIndexArray.clear(); fTweakVectorArray.clear(); // Extract the tweaks and store them in our local tweak cache members // if( fHasTweaks ) { // Declare our function sets // MFnDependencyNode depNodeFn; MObject meshNode = fDagPath.node(); MPlug meshTweakPlug; // Declare our tweak processing variables // MPlug tweak; MPlug tweakChild; MObject tweakData; MObjectArray tweakDataArray; MFloatVector tweakVector; MPlugArray tempPlugArray; unsigned i; depNodeFn.setObject( meshNode ); meshTweakPlug = depNodeFn.findPlug( "pnts" ); // ASSERT: meshTweakPlug should be an array plug! // MStatusAssert( (meshTweakPlug.isArray()), "meshTweakPlug.isArray() -- meshTweakPlug is not an array plug" ); unsigned numElements = meshTweakPlug.numElements(); // Gather meshTweakPlug data // for( i = 0; i < numElements; i++ ) { // MPlug::numElements() only returns the number of physical elements // in the array plug. Thus we must use elementByPhysical index when using // the index i. // tweak = meshTweakPlug.elementByPhysicalIndex(i); // If the method fails, the element is NULL. Only append the index // if it is a valid plug. // if( !tweak.isNull() ) { // Cache the logical index of this element plug // unsigned logicalIndex = tweak.logicalIndex(); // Collect tweak data and cache the indices and float vectors // getFloat3PlugValue( tweak, tweakVector ); fTweakIndexArray.append( logicalIndex ); fTweakVectorArray.append( tweakVector ); } } } return status; }