MStatus polyModifierCmd::undoModifyPoly() { MStatus status = MS::kSuccess; if( !fHasHistory && !fHasRecordHistory ) { status = undoDirectModifier(); } else { fDGModifier.undoIt(); // undoCachedMesh must be called before undoTweakProcessing because // undoCachedMesh copies the original mesh *without* tweaks back onto // the existing mesh. Any changes done before the copy will be lost. // if( !fHasHistory ) { status = undoCachedMesh(); MCheckStatus( status, "undoCachedMesh" ); fDagModifier.undoIt(); } status = undoTweakProcessing(); MCheckStatus( status, "undoTweakProcessing" ); } return status; }
MStatus polyModifierCmd::cacheMeshData() { MStatus status = MS::kSuccess; MFnDependencyNode depNodeFn; MFnDagNode dagNodeFn; MObject meshNode = fDagPath.node(); MObject dupMeshNode; MPlug dupMeshNodeOutMeshPlug; // Duplicate the mesh // dagNodeFn.setObject( meshNode ); dupMeshNode = dagNodeFn.duplicate(); MDagPath dupMeshDagPath; MDagPath::getAPathTo( dupMeshNode, dupMeshDagPath ); dupMeshDagPath.extendToShape(); depNodeFn.setObject( dupMeshDagPath.node() ); dupMeshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status ); MCheckStatus( status, "Could not retrieve outMesh" ); // Retrieve the meshData // status = dupMeshNodeOutMeshPlug.getValue( fMeshData ); MCheckStatus( status, "Could not retrieve meshData" ); // Delete the duplicated node // MGlobal::deleteNode( dupMeshNode ); return status; }
MStatus polyModifierCmd::redoModifyPoly() { MStatus status = MS::kSuccess; if( !fHasHistory && !fHasRecordHistory ) { MObject meshNode = fDagPath.node(); // Call the directModifier - No need to pre-process the mesh data again // since we already have it. // status = directModifier( meshNode ); } else { // Call the redo on the DG and DAG modifiers // if( !fHasHistory ) { //########################################################################### tima/ status = tima_tempForUndoDeleteDuplicate_modifier.undoIt(); /*#ifdef _DEBUG if(status)cout<<endl<<"tima_tempForUndoDeleteDuplicate_modifier.undoIt - success"<<endl; else cout<<endl<<"tima_tempForUndoDeleteDuplicate_modifier.undoIt - failed"<<endl; #endif*/ MCheckStatus( status, "tima_tempForUndoDeleteDuplicate_modifier.undoIt" ); //########################################################################### /tima fDagModifier.doIt(); } status = fDGModifier.doIt(); setZeroTweaks(); } return status; }
MStatus splatDeformer::initialize() { // local attribute initialization MStatus status; MFnTypedAttribute mAttr; deformingMesh=mAttr.create( "deformingMesh", "dm", MFnMeshData::kMesh); mAttr.setStorable(true); // deformation attributes status = addAttribute( deformingMesh ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( deformingMesh, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); return MStatus::kSuccess; }
MStatus sseDeformer::initialize() { // local attribute initialization MStatus status; MFnNumericAttribute mSSEAttr; sseEnabled=mSSEAttr.create( "enableSSE", "sse", MFnNumericData::kBoolean, 0, &status); mSSEAttr.setStorable(true); // deformation attributes status = addAttribute( sseEnabled ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( sseEnabled, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); return MStatus::kSuccess; }
MStatus splitUV::pruneUVs( MIntArray& validUVIndices ) // // Description: // // This method will remove any invalid UVIds from the component list and UVId array. // The benefit of this is to reduce the amount of extra processing that the node would // have to perform. It will result in less iterations through the mesh as there are // less UVs to search for. // { MStatus status; unsigned i; MIntArray validUVIds; for( i = 0; i < validUVIndices.length(); i++ ) { int uvIndex = validUVIndices[i]; validUVIds.append( fSelUVs[uvIndex] ); } // Replace the local int array of UVIds // fSelUVs.clear(); fSelUVs = validUVIds; // Build the list of valid components // MFnSingleIndexedComponent compFn; compFn.create( MFn::kMeshMapComponent, &status ); MCheckStatus( status, "compFn.create( MFn::kMeshMapComponent )" ); status = compFn.addElements( validUVIds ); MCheckStatus( status, "compFn.addElements( validUVIds )" ); MObject component = compFn.object(); // Replace the component list // MFnComponentListData compListFn; compListFn.create(); status = compListFn.add( component ); MCheckStatus( status, "compListFn.add( component )" ); fComponentList = compListFn.object(); return status; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::undoModifyPoly() // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; if( !fHasHistory && !fHasRecordHistory ) { status = undoDirectModifier(); } else { // Merke: Das MObject zur ModifierNode sollte jetzt zerstrt werden, da es ungueltig wird, wenn der modifier rueckgngig gemacht wird. // Ansonsten gibts nen absturz myModifierNode = MObject::kNullObj; if(createAnimCurves) { createSlideAnim.undoIt(); } fDGModifier.undoIt(); // undoCachedMesh must be called before undoTweakProcessing because // undoCachedMesh copies the original mesh *without* tweaks back onto // the existing mesh. Any changes done before the copy will be lost. // if( !fHasHistory ) { status = undoCachedMesh(); MCheckStatus( status, "undoCachedMesh" ); //fDagModifier.undoIt(); deleteDuplicate.undoIt(); reparentDuplicate.undoIt(); createDuplicate.undoIt(); } status = undoTweakProcessing(); MCheckStatus( status, "undoTweakProcessing" ); } return status; }
MStatus polyModifierCmd::undoModifyPoly() { MStatus status = MS::kSuccess; if( !fHasHistory && !fHasRecordHistory ) { status = undoDirectModifier(); } else { fDGModifier.undoIt(); // undoCachedMesh must be called before undoTweakProcessing because // undoCachedMesh copies the original mesh *without* tweaks back onto // the existing mesh. Any changes done before the copy will be lost. // if( !fHasHistory ) { status = undoCachedMesh(); MCheckStatus( status, "undoCachedMesh" ); //by_tima: fDagModifier.undoIt(); //########################################################################### tima/ MFnDagNode tmpDagNodeFn( fDuplicateDagPath); tima_tempForUndoDeleteDuplicate_modifier.deleteNode(tmpDagNodeFn.object()); status = tima_tempForUndoDeleteDuplicate_modifier.doIt(); /*#ifdef _DEBUG MGlobal::displayInfo( "tima_upstreamNodeTransform_name = " + tmpDagNodeFn.name()); if(status)cout<<endl<<"tima_tempForUndoDeleteDuplicate_modifier.doIt - success"<<endl; else cout<<endl<<"tima_tempForUndoDeleteDuplicate_modifier.doIt - failed"<<endl; #endif*/ MCheckStatus( status, "tima_tempForUndoDeleteDuplicate_modifier.doIt" ); //########################################################################### /tima } status = undoTweakProcessing(); MCheckStatus( status, "undoTweakProcessing" ); } return status; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::processModifierNode( MObject modifierNode, modifyPolyData& data ) // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; MFnDependencyNode depNodeFn ( modifierNode ); data.modifierNodeSrcAttr = depNodeFn.attribute( "outMesh" , &status); MCheckStatus( status, "Finden des outMesh Attributes" ); data.modifierNodeDestAttr = depNodeFn.attribute( "inMesh" , &status ); return status; }
MStatus PolyColourNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { //MDataHandle inputMesh = data.inputValue( m_inMesh, &status ); //MCheckStatus(status,"ERROR getting inMesh"); //MDataHandle outputMesh = data.outputValue( m_outMesh, &status ); //MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // //outputMesh.set(inputMesh.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (1) { } else { status = MS::kUnknownParameter; } } return status; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::connectNodes( MObject modifierNode ) // -------------------------------------------------------------------------------------------- // // Description: // // This method connects up the modifier nodes, while accounting for DG factors // such as construction history and tweaks. The method has a series of steps which // it runs through to process nodes under varying circumstances: // // 1) Gather meshNode connection data (ie. attributes and plugs) // // 2) Gather upstreamNode data - This is history-dependent. If the node has history, // an actual upstreamNode exists and that is used to // drive the input of our modifierNode. // // Otherwise, if the node ds not have history, the // meshNode is duplicated, set as an intermediate object // and regarded as our new upstreamNode which will drive // the input of our modifierNode. The case with history // already has this duplicate meshNode at the top, driving // all other history nodes and serving as a reference // to the "original state" of the node before any // modifications. // // 3) Gather modifierNode connection data // // 4) Process tweak data (if it exists) - This is history-dependent. If there is // history, the tweak data is extracted and deleted // from the meshNode and encapsulated inside a // polyTweak node. The polyTweak node is then // inserted ahead of the modifier node. // // If there is no history, the same is done as // in the history case, except the tweaks are // deleted from the duplicate meshNode in addition // to the actual meshNode. // // 5) Connect the nodes // // 6) Collapse/Bake nodes into the actual meshNode if the meshNode had no previous // construction history and construction history recording is turned off. // (ie. (!fHasHistory && !fHasRecordHistory) == true ) // { MStatus status; // Declare our internal processing data structure (see polyModifierCmd.h for definition) // modifyPolyData data; //->jetzt als ElementVariable // Get the mesh node, plugs and attributes // status = processMeshNode( data ); MCheckStatus( status, "processMeshNode" ); // Get upstream node, plugs and attributes // status = processUpstreamNode( data ); MCheckStatus( status, "processUpstreamNode" ); // Get the modifierNode attributes // status = processModifierNode( modifierNode, data ); MCheckStatus( status, "processModifierNode" ); // Process tweaks on the meshNode // status = processTweaks( data ); MCheckStatus( status, "processTweaks" ); if( fHasTweaks ) { status = fDGModifier.connect( data.upstreamNodeShape, data.upstreamNodeSrcAttr, data.tweakNode, data.tweakNodeDestAttr ); MCheckStatus( status, "upstream-tweak connect failed" ); status = fDGModifier.connect( data.tweakNode, data.tweakNodeSrcAttr, modifierNode, data.modifierNodeDestAttr ); MCheckStatus( status, "tweak-modifier connect failed" ); } else { //hier muessen die Plugs verwendet werden, weil die Attribute eventuell multis sind MPlug destPlug(modifierNode,data.modifierNodeDestAttr ); INVIS(cout<<data.upstreamNodeSrcPlug.name().asChar()<<" --> "<<destPlug.name().asChar()<<endl); status = fDGModifier.connect( data.upstreamNodeSrcPlug, destPlug ); MCheckStatus( status, "upstream-modifier connect failed" ); } // outMesh mit inputMesh verbinden // fDGModifier.connect(MPlug(modifierNode,data.modifierNodeSrcAttr), data.meshNodeDestPlug); // Ausserdem das MatrixAttribut des Meshes mit dem meshMatrix Attr der Node verbinden // MFnDependencyNode depFn( modifierNode ); MPlug meshMatrix( modifierNode, depFn.attribute("meshMatrix") ); depFn.setObject(data.meshNodeTransform); MPlug shapeMatrix( data.meshNodeTransform, depFn.attribute("worldMatrix") ); fDGModifier.connect(shapeMatrix.elementByLogicalIndex( 0 ), meshMatrix ); // Jetzt die ModifierNode mit der VisNode connecten /* status = fDGModifier.connect( modifierNode, data.modifierNodeSrcAttr, data.meshNodeShape, data.meshNodeDestAttr ); */ // MCheckStatus( status, "modifier-mesh connect failed" ); status = fDGModifier.doIt(); MCheckStatus( status, "modifier-mesh DOIT failed" ); if(createAnimCurves) { //AnimCurve erstellen(dies ist nur hier moeglich, da die Node erst nach dem DoIt wirklich existiert (scheinbar) MFnAnimCurve aCurve; MFnDependencyNode myDepNodeFn(modifierNode); aCurve.create(modifierNode,myDepNodeFn.attribute("csl"),MFnAnimCurve::kAnimCurveUU,&createSlideAnim,&status); } return status; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::processUpstreamNode( modifyPolyData& data ) // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; // Declare our function sets - Although dagNodeFn derives from depNodeFn, we need // both since dagNodeFn can only refer to DAG objects. // We will use depNodeFn for all times other when dealing // with the DAG. // MFnDependencyNode depNodeFn; MFnDagNode dagNodeFn; // Use the selected node's plug connections to find the upstream plug. // Since we are looking at the selected node's inMesh attribute, it will // always have only one connection coming in if it has history, and none // otherwise. // // If there is no history, copy the selected node and place it ahead of the // modifierNode as the new upstream node so that the modifierNode has an // input mesh to operate on. // //save the meshDagPath for later use MDagPath::getAPathTo(data.meshNodeShape,myMeshPath); MPlugArray tempPlugArray; if( fHasHistory ) { // Since we have history, look for what connections exist on the // meshNode "inMesh" plug. "inMesh" plugs should only ever have one // connection. // data.meshNodeDestPlug.connectedTo( tempPlugArray, true, false); // ASSERT: Only one connection should exist on meshNodeShape.inMesh! // MStatusAssert( (tempPlugArray.length() == 1), "tempPlugArray.length() == 1 -- 0 or >1 connections on meshNodeShape.inMesh" ); data.upstreamNodeSrcPlug = tempPlugArray[0]; // Construction history only deals with shapes, so we can grab the // upstreamNodeShape off of the source plug. // // Dieser Bereich muss bleiben, weil diese Attribute noch bentigt werden data.upstreamNodeShape = data.upstreamNodeSrcPlug.node(); depNodeFn.setObject( data.upstreamNodeShape ); data.upstreamNodeSrcAttr = data.upstreamNodeSrcPlug.attribute(); // Disconnect the upstream node and the selected node, so we can // replace them with our own connections below. // MPlug nodePlug(data.meshNodeShape,data.meshNodeDestAttr ) ; INVIS(cout<<data.upstreamNodeSrcPlug.name().asChar()<<" --|-- "<<nodePlug.name().asChar()<<endl); status = fDGModifier.disconnect( data.upstreamNodeSrcPlug, nodePlug ); MCheckStatus( status, "Disconnect Upstream mit meshNode" ); } else // No History (!fHasHistory) { // Use the DAG node function set to duplicate the shape of the meshNode. // The duplicate method will return an MObject handle to the transform // of the duplicated shape, so traverse the dag to locate the shape. Store // this duplicate shape as our "upstream" node to drive the input for the // modifierNode. // depNodeFn.setObject( data.meshNodeShape ); data.upstreamNodeTransform = createDuplicate.createNode("mesh"); createDuplicate.doIt(); dagNodeFn.setObject( data.upstreamNodeTransform ); // Ensure that our upstreamNode is pointing to a shape. // MStatusAssert( (0 < dagNodeFn.childCount()), "0 < dagNodeFn.childCount() -- Duplicate meshNode transform has no shape." ); data.upstreamNodeShape = dagNodeFn.child(0); MPlug outMeshPlug = depNodeFn.findPlug("outMesh"); depNodeFn.setObject(data.upstreamNodeShape); //jetzt inMesh upstreamNodeShape mit outMesh meshShape füllen MDGModifier tempMod; tempMod.connect(outMeshPlug,depNodeFn.findPlug("inMesh")); tempMod.doIt(); //force DGEVAL MString cmd = "dgeval -src "; cmd += depNodeFn.name(); cmd += ".outMesh"; MGlobal::executeCommand(cmd,false,false); tempMod.undoIt(); // Re-parent the upstreamNodeShape under our original transform // reparentDuplicate.reparentNode( data.upstreamNodeShape, data.meshNodeTransform ); reparentDuplicate.doIt(); deleteDuplicate.deleteNode( data.upstreamNodeTransform ); deleteDuplicate.doIt(); /* status = fDagModifier.reparentNode( data.upstreamNodeShape, data.meshNodeTransform ); MCheckStatus( status, "reparentNode" ); // Perform the DAG re-parenting // // Note: This reparent must be performed before the deleteNode() is called. // See polyModifierCmd.h (see definition of fDagModifier) for more details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); */ // Mark the upstreamNodeShape (the original shape) as an intermediate object // (making it invisible to the user) // dagNodeFn.setObject( data.upstreamNodeShape ); dagNodeFn.setIntermediateObject( true ); // Get the upstream node source attribute // data.upstreamNodeSrcAttr = dagNodeFn.attribute( "outMesh" ); data.upstreamNodeSrcPlug = MPlug(data.upstreamNodeShape, data.upstreamNodeSrcAttr); /* // Remove the duplicated transform node (clean up) // status = fDagModifier.deleteNode( data.upstreamNodeTransform ); MCheckStatus( status, "deleteNode" ); // Perform the DAG delete node // // Note: This deleteNode must be performed after the reparentNode() method is // completed. See polyModifierCmd.h (see definition of fDagModifier) for // details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); */ // Cache the DAG path to the duplicate shape // dagNodeFn.getPath( fDuplicateDagPath ); //finally delete the tweaks to avoid double transformation deleteTweaks(); } return status; }
MStatus meshOpNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Now, we get the value of the component list and the operation // type and use it to perform the mesh operation on this mesh // MDataHandle inputIDs = data.inputValue( cpList, &status); MCheckStatus(status,"ERROR getting componentList"); MDataHandle opTypeData = data.inputValue( opType, &status); MCheckStatus(status,"ERROR getting opType"); // Copy the inMesh to the outMesh, so you can // perform operations directly on outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); // Retrieve the ID list from the component list. // // Note, we use a component list to store the components // because it is more compact memory wise. (ie. comp[81:85] // is smaller than comp[81], comp[82],...,comp[85]) // MObject compList = inputIDs.data(); MFnComponentListData compListFn( compList ); // Get what operation is requested and // what type of component is expected for this operation. MeshOperation operationType = (MeshOperation) opTypeData.asShort(); MFn::Type componentType = meshOpFty::getExpectedComponentType(operationType); unsigned i; int j; MIntArray cpIds; for( i = 0; i < compListFn.length(); i++ ) { MObject comp = compListFn[i]; if( comp.apiType() == componentType ) { MFnSingleIndexedComponent siComp( comp ); for( j = 0; j < siComp.elementCount(); j++ ) cpIds.append( siComp.element(j) ); } } // Set the mesh object and component List on the factory // fmeshOpFactory.setMesh( mesh ); fmeshOpFactory.setComponentList( compList ); fmeshOpFactory.setComponentIDs( cpIds ); fmeshOpFactory.setMeshOperation( operationType ); // Now, perform the meshOp // status = fmeshOpFactory.doIt(); // Mark the output mesh as clean // outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
MStatus sseDeformer::compute(const MPlug& plug, MDataBlock& data) { MStatus status; if (plug.attribute() != outputGeom) { printf("Ignoring requested plug\n"); return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } MObject iSurf = inputData.asMesh() ; MFnMesh inMesh; inMesh.setObject( iSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MObject oSurf = outputData.asMesh() ; if(oSurf.isNull()) { printf("Output surface is NULL\n"); return MStatus::kFailure; } MFnMesh outMesh; outMesh.setObject( oSurf ) ; MCheckStatus(status, "ERROR setting points\n"); // get all points at once for demo purposes. Really should get points from the current group using iterator MFloatPointArray pts; outMesh.getPoints(pts); int nPoints = pts.length(); MDataHandle envData = data.inputValue(envelope, &status); float env = envData.asFloat(); MDataHandle sseData = data.inputValue(sseEnabled, &status); bool sseEnabled = (bool) sseData.asBool(); // NOTE: Using MTimer and possibly other classes disables // autovectorization with Intel <=10.1 compiler on OSX and Linux!! // Must compile this function with -fno-exceptions on OSX and // Linux to guarantee autovectorization is done. Use -fvec_report2 // to check for vectorization status messages with Intel compiler. MTimer timer; timer.beginTimer(); if(sseEnabled) { // Innter loop will autovectorize. Around 3x faster than the // loop below it. It would be faster if first element was // guaranteed to be aligned on 16 byte boundary. for(int i=0; i<nPoints; i++) { float* ptPtr = &pts[i].x; for(int j=0; j<4; j++) { ptPtr[j] = env * (cosf(ptPtr[j]) * sinf(ptPtr[j]) * tanf(ptPtr[j])); } } } else { // This inner loop will not autovectorize. for(int i=0; i<nPoints; i++) { MFloatPoint& pt = pts[i]; for(int j=0; j<3; j++) { pt[j] = env * (cosf(pt[j]) * sinf(pt[j]) * tanf(pt[j])); } } } timer.endTimer(); if(sseEnabled) { printf("SSE enabled, runtime %f\n", timer.elapsedTime()); } else { printf("SSE disabled, runtime %f\n", timer.elapsedTime()); } outMesh.setPoints(pts); return status; }
//---------------------------------------------------------------------------- MStatus BPT_InsertVtx::initialize() //---------------------------------------------------------------------------- { MFnEnumAttribute FnEnumAttr; MFnTypedAttribute FnTypedAttr; MFnNumericAttribute FnFloatAttr; MStatus status; IVinMesh = FnTypedAttr.create("inMesh","in",MFnData::kMesh); FnTypedAttr.setStorable(true); //FnTypedAttr.setCached(false); FnTypedAttr.setInternal(true); IVoutMesh = FnTypedAttr.create("outMesh","out",MFnData::kMesh); FnTypedAttr.setStorable(true); FnTypedAttr.setWritable(false); IVcount = FnFloatAttr.create("count","c",MFnNumericData::kLong); FnFloatAttr.setStorable(true); FnFloatAttr.setInternal(true); FnFloatAttr.setKeyable(true); FnFloatAttr.setMin(1); FnFloatAttr.setSoftMax(15); IVselEdgeIDs = FnTypedAttr.create("edgeIDs","eID",MFnData::kIntArray); FnTypedAttr.setStorable(true); FnTypedAttr.setHidden(true); FnTypedAttr.setConnectable(false); IVselVertIDs = FnTypedAttr.create("vertIDs","vID",MFnData::kIntArray); FnTypedAttr.setStorable(true); FnTypedAttr.setHidden(true); FnTypedAttr.setConnectable(false); IVoptions = FnTypedAttr.create("options","op",MFnData::kIntArray); FnTypedAttr.setStorable(true); FnTypedAttr.setHidden(true); FnTypedAttr.setConnectable(false); IVslide = FnFloatAttr.create("slide","sl",MFnNumericData::kDouble); FnFloatAttr.setStorable(true); FnFloatAttr.setInternal(true); // FnFloatAttr.setMin(0.0); // FnFloatAttr.setMax(1.0); FnFloatAttr.setKeyable(true); IVnormal = FnFloatAttr.create("alongNormal","an",MFnNumericData::kDouble); FnFloatAttr.setStorable(true); FnFloatAttr.setDefault(0.0); FnFloatAttr.setKeyable(true); IVslideRelative = FnFloatAttr.create("slideRelative","sr",MFnNumericData::kLong); FnFloatAttr.setStorable(true); FnFloatAttr.setMin(0.0); FnFloatAttr.setMax(1.0); FnFloatAttr.setKeyable(true); IVnormalRelative = FnFloatAttr.create("normalRelative","nr",MFnNumericData::kLong); FnFloatAttr.setStorable(true); FnFloatAttr.setMin(0.0); FnFloatAttr.setMax(1.0); FnFloatAttr.setKeyable(true); IVwhichSide = FnFloatAttr.create("side","si",MFnNumericData::kLong); FnFloatAttr.setStorable(true); FnFloatAttr.setMin(0.0); FnFloatAttr.setMax(1.0); FnFloatAttr.setKeyable(true); IVSlideLimited = FnFloatAttr.create("slideLimited","sll",MFnNumericData::kLong); FnFloatAttr.setStorable(true); FnFloatAttr.setMin(0.0); FnFloatAttr.setMax(1.0); FnFloatAttr.setKeyable(false); IVspin = FnFloatAttr.create("spin","sp",MFnNumericData::kLong); FnFloatAttr.setStorable(true); FnFloatAttr.setMin(0.0); FnFloatAttr.setKeyable(true); FnFloatAttr.setInternal(true); // Add attributes status = addAttribute(IVslideRelative); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVnormalRelative); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVwhichSide); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVnormal); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVslide); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVSlideLimited); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVoptions); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVspin); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVcount); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVselEdgeIDs); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVselVertIDs); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVoutMesh); MCheckStatus(status, "AddAttrIVNode"); status = addAttribute(IVinMesh); MCheckStatus(status, "AddAttrIVNode"); // Add attribute affects status = attributeAffects( IVspin, IVoutMesh ); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVcount, IVoutMesh ); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVinMesh, IVoutMesh ); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVslide, IVoutMesh); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVslideRelative, IVoutMesh); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVnormalRelative, IVoutMesh); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVwhichSide, IVoutMesh); MCheckStatus(status, "AddAttrAffectsIVNode"); status = attributeAffects( IVnormal, IVoutMesh); MCheckStatus(status, "AddAttrAffectsIVNode"); // Zuletzt die SoftTransformationAttribute hinzufuegen // Per Macro - dirty, aber funktioniert - wie machen die ALIAS Typen das ??? Die leiten auch stuendig von einer BaseNode ab, und da gehen dann keine Attribute flueten // Oder werden unbrauchbar so wie bei mir, so dass im Endeffekt suemtliche Attribute ein eindeutiges statisches Attribut haben muessen STE_ADD_ATTRIBUTES(IV) return status; }
MStatus polyModifierCmd::connectNodes( MObject modifierNode ) // // Description: // // This method connects up the modifier nodes, while accounting for DG factors // such as construction history and tweaks. The method has a series of steps which // it runs through to process nodes under varying circumstances: // // 1) Gather meshNode connection data (ie. attributes and plugs) // // 2) Gather upstreamNode data - This is history-dependent. If the node has history, // an actual upstreamNode exists and that is used to // drive the input of our modifierNode. // // Otherwise, if the node does not have history, the // meshNode is duplicated, set as an intermediate object // and regarded as our new upstreamNode which will drive // the input of our modifierNode. The case with history // already has this duplicate meshNode at the top, driving // all other history nodes and serving as a reference // to the "original state" of the node before any // modifications. // // 3) Gather modifierNode connection data // // 4) Process tweak data (if it exists) - This is history-dependent. If there is // history, the tweak data is extracted and deleted // from the meshNode and encapsulated inside a // polyTweak node. The polyTweak node is then // inserted ahead of the modifier node. // // If there is no history, the same is done as // in the history case, except the tweaks are // deleted from the duplicate meshNode in addition // to the actual meshNode. // // 5) Connect the nodes // // 6) Collapse/Bake nodes into the actual meshNode if the meshNode had no previous // construction history and construction history recording is turned off. // (ie. (!fHasHistory && !fHasRecordHistory) == true ) // { MStatus status; // Declare our internal processing data structure (see polyModifierCmd.h for definition) // modifyPolyData data; // Get the mesh node, plugs and attributes // status = processMeshNode( data ); MCheckStatus( status, "processMeshNode" ); // Get upstream node, plugs and attributes // status = processUpstreamNode( data ); MCheckStatus( status, "processUpstreamNode" ); // Get the modifierNode attributes // status = processModifierNode( modifierNode, data ); MCheckStatus( status, "processModifierNode" ); // Process tweaks on the meshNode // status = processTweaks( data ); MCheckStatus( status, "processTweaks" ); // Connect the nodes // if( fHasTweaks ) { status = fDGModifier.connect( data.upstreamNodeShape, data.upstreamNodeSrcAttr, data.tweakNode, data.tweakNodeDestAttr ); MCheckStatus( status, "upstream-tweak connect failed" ); status = fDGModifier.connect( data.tweakNode, data.tweakNodeSrcAttr, modifierNode, data.modifierNodeDestAttr ); MCheckStatus( status, "tweak-modifier connect failed" ); } else { status = fDGModifier.connect( data.upstreamNodeShape, data.upstreamNodeSrcAttr, modifierNode, data.modifierNodeDestAttr ); MCheckStatus( status, "upstream-modifier connect failed" ); } status = fDGModifier.connect( modifierNode, data.modifierNodeSrcAttr, data.meshNodeShape, data.meshNodeDestAttr ); MCheckStatus( status, "modifier-mesh connect failed" ); status = fDGModifier.doIt(); return status; }
MStatus polyModifierCmd::processUpstreamNode( modifyPolyData& data ) { MStatus status = MS::kSuccess; // Declare our function sets - Although dagNodeFn derives from depNodeFn, we need // both since dagNodeFn can only refer to DAG objects. // We will use depNodeFn for all times other when dealing // with the DAG. // MFnDependencyNode depNodeFn; MFnDagNode dagNodeFn; // Use the selected node's plug connections to find the upstream plug. // Since we are looking at the selected node's inMesh attribute, it will // always have only one connection coming in if it has history, and none // otherwise. // // If there is no history, copy the selected node and place it ahead of the // modifierNode as the new upstream node so that the modifierNode has an // input mesh to operate on. // MPlugArray tempPlugArray; if( fHasHistory ) { // Since we have history, look for what connections exist on the // meshNode "inMesh" plug. "inMesh" plugs should only ever have one // connection. // data.meshNodeDestPlug.connectedTo( tempPlugArray, true, false); // ASSERT: Only one connection should exist on meshNodeShape.inMesh! // MStatusAssert( (tempPlugArray.length() == 1), "tempPlugArray.length() == 1 -- 0 or >1 connections on meshNodeShape.inMesh" ); data.upstreamNodeSrcPlug = tempPlugArray[0]; // Construction history only deals with shapes, so we can grab the // upstreamNodeShape off of the source plug. // data.upstreamNodeShape = data.upstreamNodeSrcPlug.node(); depNodeFn.setObject( data.upstreamNodeShape ); data.upstreamNodeSrcAttr = data.upstreamNodeSrcPlug.attribute(); // Disconnect the upstream node and the selected node, so we can // replace them with our own connections below. // fDGModifier.disconnect( data.upstreamNodeShape, data.upstreamNodeSrcAttr, data.meshNodeShape, data.meshNodeDestAttr ); } else // No History (!fHasHistory) { // Use the DAG node function set to duplicate the shape of the meshNode. // The duplicate method will return an MObject handle to the transform // of the duplicated shape, so traverse the dag to locate the shape. Store // this duplicate shape as our "upstream" node to drive the input for the // modifierNode. // dagNodeFn.setObject( data.meshNodeShape ); data.upstreamNodeTransform = dagNodeFn.duplicate( false, false ); dagNodeFn.setObject( data.upstreamNodeTransform ); // Ensure that our upstreamNode is pointing to a shape. // MStatusAssert( (0 < dagNodeFn.childCount()), "0 < dagNodeFn.childCount() -- Duplicate meshNode transform has no shape." ); data.upstreamNodeShape = dagNodeFn.child(0); // Re-parent the upstreamNodeShape under our original transform // status = fDagModifier.reparentNode( data.upstreamNodeShape, data.meshNodeTransform ); MCheckStatus( status, "reparentNode" ); // Perform the DAG re-parenting // // Note: This reparent must be performed before the deleteNode() is called. // See polyModifierCmd.h (see definition of fDagModifier) for more details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); // Mark the upstreamNodeShape (the original shape) as an intermediate object // (making it invisible to the user) // dagNodeFn.setObject( data.upstreamNodeShape ); dagNodeFn.setIntermediateObject( true ); // Get the upstream node source attribute // data.upstreamNodeSrcAttr = dagNodeFn.attribute( "outMesh" ); // Remove the duplicated transform node (clean up) // status = fDagModifier.deleteNode( data.upstreamNodeTransform ); MCheckStatus( status, "deleteNode" ); // Perform the DAG delete node // // Note: This deleteNode must be performed after the reparentNode() method is // completed. See polyModifierCmd.h (see definition of fDagModifier) for // details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); // Cache the DAG path to the duplicate shape // dagNodeFn.getPath( fDuplicateDagPath ); } return status; }
MStatus splatDeformer::compute(const MPlug& plug, MDataBlock& data) { // do this if we are using an OpenMP implementation that is not the same as Maya's. // Even if it is the same, it does no harm to make this call. MThreadUtils::syncNumOpenMPThreads(); MStatus status = MStatus::kUnknownParameter; if (plug.attribute() != outputGeom) { return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } // get the input groupId - ignored for now... MDataHandle hGroup = inputData.child(groupId); unsigned int groupId = hGroup.asLong(); // get deforming mesh MDataHandle deformData = data.inputValue(deformingMesh, &status); MCheckStatus(status, "ERROR getting deforming mesh\n"); if (deformData.type() != MFnData::kMesh) { printf("Incorrect deformer geometry type %d\n", deformData.type()); return MStatus::kFailure; } MObject dSurf = deformData.asMeshTransformed(); MFnMesh fnDeformingMesh; fnDeformingMesh.setObject( dSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MItGeometry iter(outputData, groupId, false); // create fast intersector structure MMeshIntersector intersector; intersector.create(dSurf); // get all points at once. Faster to query, and also better for // threading than using iterator MPointArray verts; iter.allPositions(verts); int nPoints = verts.length(); // use bool variable as lightweight object for failure check in loop below bool failed = false; MTimer timer; timer.beginTimer(); #ifdef _OPENMP #pragma omp parallel for #endif for(int i=0; i<nPoints; i++) { // Cannot break out of an OpenMP loop, so if one of the // intersections failed, skip the rest if(failed) continue; // mesh point object must be in loop-local scope to avoid race conditions MPointOnMesh meshPoint; // Do intersection. Need to use per-thread status value as // MStatus has internal state and may trigger race conditions // if set from multiple threads. Probably benign in this case, // but worth being careful. MStatus localStatus = intersector.getClosestPoint(verts[i], meshPoint); if(localStatus != MStatus::kSuccess) { // NOTE - we cannot break out of an OpenMP region, so set // bad status and skip remaining iterations failed = true; continue; } // default OpenMP scheduling breaks traversal into large // chunks, so low risk of false sharing here in array write. verts[i] = meshPoint.getPoint(); } timer.endTimer(); printf("Runtime for threaded loop %f\n", timer.elapsedTime()); // write values back onto output using fast set method on iterator iter.setAllPositions(verts); if(failed) { printf("Closest point failed\n"); return MStatus::kFailure; } return status; }
MStatus splitUVNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes - stored as short) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Now, we get the value of the uvList and use it to perform // the operation on this mesh // MDataHandle inputUVs = data.inputValue( uvList, &status); MCheckStatus(status,"ERROR getting uvList"); // Copy the inMesh to the outMesh, and now you can // perform operations in-place on the outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); // Retrieve the UV list from the component list. // // Note, we use a component list to store the components // because it is more compact memory wise. (ie. comp[81:85] // is smaller than comp[81], comp[82],...,comp[85]) // MObject compList = inputUVs.data(); MFnComponentListData compListFn( compList ); unsigned i; int j; MIntArray uvIds; for( i = 0; i < compListFn.length(); i++ ) { MObject comp = compListFn[i]; if( comp.apiType() == MFn::kMeshMapComponent ) { MFnSingleIndexedComponent uvComp( comp ); for( j = 0; j < uvComp.elementCount(); j++ ) { int uvId = uvComp.element(j); uvIds.append( uvId ); } } } // Set the mesh object and uvList on the factory // fSplitUVFactory.setMesh( mesh ); fSplitUVFactory.setUVIds( uvIds ); // Now, perform the splitUV // status = fSplitUVFactory.doIt(); // Mark the output mesh as clean // outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
MStatus updateTCCDataNode::initialize() // // Description: // This method is called to create and initialize all of the attributes // and attribute dependencies for this node type. This is only called // once when the node type is registered with Maya. // // Return Values: // MS::kSuccess // MS::kFailure // { MStatus status; MFnTypedAttribute attrFn; MFnNumericAttribute attrNum; MIntArray defaultArray; MFnIntArrayData defaultArrayDataFn; defaultArrayDataFn.create( defaultArray ); vtxRemap = attrFn.create("vtxRemap", "vR", MFnData::kIntArray, defaultArrayDataFn.object()); attrFn.setStorable(true); defaultArrayDataFn.create( defaultArray ); polyOrder = attrFn.create("polyOrder", "pO", MFnData::kIntArray, defaultArrayDataFn.object()); attrFn.setStorable(true); defaultArrayDataFn.create( defaultArray ); cShift = attrFn.create("cShift", "cS", MFnData::kIntArray, defaultArrayDataFn.object()); attrFn.setStorable(true); defaultArrayDataFn.create( defaultArray ); delta_F = attrFn.create("delta_F", "dF", MFnData::kIntArray, defaultArrayDataFn.object()); attrFn.setStorable(true); defaultArrayDataFn.create( defaultArray ); delta_nFV = attrFn.create("delta_nFV", "dnFV", MFnData::kIntArray, defaultArrayDataFn.object()); attrFn.setStorable(true); nV = attrNum.create("nV", "nV", MFnNumericData::kInt, 0.0); attrFn.setStorable(true); inMesh = attrFn.create("inMesh", "iM", MFnMeshData::kMesh); attrFn.setStorable(true); outMesh = attrFn.create("outMesh", "om", MFnMeshData::kMesh); attrFn.setStorable(false); attrFn.setWritable(false); status = addAttribute( vtxRemap ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( polyOrder ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( cShift ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( delta_F ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( delta_nFV ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( nV ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( inMesh ); MCheckStatus(status,"ERROR addAttribute"); status = addAttribute( outMesh); MCheckStatus(status,"ERROR addAttribute"); status = attributeAffects( inMesh, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); status = attributeAffects( vtxRemap, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); status = attributeAffects( polyOrder, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); status = attributeAffects( cShift, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); status = attributeAffects( delta_F, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); status = attributeAffects( delta_nFV, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); status = attributeAffects( nV, outMesh ); MCheckStatus(status,"ERROR attributeAffects"); return MS::kSuccess; }
MStatus updateTCCDataNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes - stored as short) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); MIntArray vR = MFnIntArrayData( data.inputValue( vtxRemap ).data() ).array(&status); MCheckStatus(status,"ERROR getting vtxRemap"); MIntArray pO = MFnIntArrayData( data.inputValue( polyOrder ).data() ).array(&status); MCheckStatus(status,"ERROR getting polyOrder"); MIntArray cS = MFnIntArrayData( data.inputValue( cShift ).data() ).array(&status); MCheckStatus(status,"ERROR getting cShift"); MIntArray dnFV = MFnIntArrayData( data.inputValue( delta_nFV ).data() ).array(&status); MCheckStatus(status,"ERROR getting deltanFV"); MIntArray dF = MFnIntArrayData( data.inputValue( delta_F ).data() ).array(&status); MCheckStatus(status,"ERROR getting deltaF"); int nVtx = data.inputValue( nV ).asInt(); MCheckStatus(status,"ERROR getting nV"); // Copy the inMesh to the outMesh, and now you can // perform operations in-place on the outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); fupdateTCCDataFactory.setMesh( mesh ); fupdateTCCDataFactory.setVtxRemap( vR ); fupdateTCCDataFactory.setPolyOrder( pO ); fupdateTCCDataFactory.setCShift( cS ); fupdateTCCDataFactory.setDelta_nFV( dnFV ); fupdateTCCDataFactory.setDelta_F( dF ); fupdateTCCDataFactory.setnV( nVtx ); // Now, perform the updateTCCData // status = fupdateTCCDataFactory.doIt(); // Mark the output mesh as clean // outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }
MStatus finalproject::initialize() { // local attribute initialization MStatus status; MFnTypedAttribute mAttr; deformingMesh=mAttr.create( "deformingMesh", "dm", MFnMeshData::kMesh); MFnNumericAttribute nAttrt; transX = nAttrt.create( "transX", "tx", MFnNumericData::kDouble); nAttrt.setStorable(true); status = addAttribute( transX ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( transX, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); transY = nAttrt.create( "transY", "ty", MFnNumericData::kDouble); nAttrt.setStorable(true); status = addAttribute( transY ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( transY, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); transZ = nAttrt.create( "transZ", "tz", MFnNumericData::kDouble); nAttrt.setStorable(true); status = addAttribute( transZ ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( transZ, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); tesla = nAttrt.create( "tesla", "tes", MFnNumericData::kDouble); nAttrt.setStorable(true); nAttrt.setKeyable(true); nAttrt.setDefault(0.0); nAttrt.setMin(0.0); nAttrt.setMax(300.0); status = addAttribute( tesla ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( tesla, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); positivelycharged = nAttrt.create( "positivelycharged", "pc", MFnNumericData::kBoolean); nAttrt.setStorable(true); nAttrt.setKeyable(true); nAttrt.setDefault(true); status = addAttribute( positivelycharged ); MCheckStatus(status, "ERROR in addAttribute\n"); MCheckStatus(status, "ERROR in attributeAffects\n"); MFnNumericAttribute nAttrO; offload=nAttrO.create( "offload", "ol", MFnNumericData::kBoolean); nAttrO.setStorable(true); nAttrO.setDefault(false); nAttrO.setKeyable(true); // deformation attributes status = addAttribute( deformingMesh ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( deformingMesh, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); status = addAttribute( offload ); MCheckStatus(status, "ERROR in addAttribute\n"); status = attributeAffects( offload, outputGeom ); MCheckStatus(status, "ERROR in attributeAffects\n"); return MStatus::kSuccess; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::undoCachedMesh() // -------------------------------------------------------------------------------------------- { MStatus status; // Only need to restore the cached mesh if there was no history. Also // check to make sure that we are in the record history state. // MStatusAssert( (fHasRecordHistory), "fHasRecordHistory == true" ); if( !fHasHistory ) { MFnDependencyNode depNodeFn; MString meshNodeName; MObject meshNodeShape; MPlug meshNodeDestPlug; MPlug meshNodeOutMeshPlug; MObject dupMeshNodeShape; MPlug dupMeshNodeSrcPlug; meshNodeShape = fDagPath.node(); dupMeshNodeShape = fDuplicateDagPath.node(); depNodeFn.setObject( meshNodeShape ); meshNodeName = depNodeFn.name(); meshNodeDestPlug = depNodeFn.findPlug( "inMesh", &status ); MCheckStatus( status, "Could not retrieve inMesh" ); meshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status ); MCheckStatus( status, "Could not retrieve outMesh" ); depNodeFn.setObject( dupMeshNodeShape ); dupMeshNodeSrcPlug = depNodeFn.findPlug( "outMesh", &status ); MCheckStatus( status, "Could not retrieve outMesh" ); // For the case with tweaks, we cannot write the mesh directly back onto // the cachedInMesh, since the shape can have out of date information from the // cachedInMesh, thus we temporarily connect the duplicate mesh shape to the // mesh shape and force a DG evaluation. // // For the case without tweaks, we can simply write onto the outMesh, since // the shape relies solely on an outMesh when there is no history nor tweaks. // if( fHasTweaks ) { MDGModifier dgModifier; dgModifier.connect( dupMeshNodeSrcPlug, meshNodeDestPlug ); status = dgModifier.doIt(); MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" ); // Need to force a DG evaluation now that the input has been changed. // MString cmd( "dgeval -src " ); cmd += meshNodeName; cmd += ".outMesh"; //outMesh statt inMesh, damit undo (ohne history) funzt status = MGlobal::executeCommand( cmd, false, false ); MCheckStatus( status, "Could not force DG eval" ); // Disconnect the duplicate meshNode now // dgModifier.undoIt(); } else { MObject meshData; status = dupMeshNodeSrcPlug.getValue( meshData ); MCheckStatus( status, "Could not retrieve meshData" ); status = meshNodeOutMeshPlug.setValue( meshData ); MCheckStatus( status, "Could not set outMesh" ); } } return status; }
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::undoDirectModifier() // -------------------------------------------------------------------------------------------- { MStatus status; MFnDependencyNode depNodeFn; MFnDagNode dagNodeFn; MObject meshNode = fDagPath.node(); depNodeFn.setObject( meshNode ); // For the case with tweaks, we cannot write the mesh directly back onto // the cachedInMesh, since the shape can have out of date information from the // cachedInMesh. Thus we temporarily create an duplicate mesh, place our // old mesh on the outMesh attribute of our duplicate mesh, connect the // duplicate mesh shape to the mesh shape, and force a DG evaluation. // // For the case without tweaks, we can simply write onto the outMesh, since // the shape relies solely on an outMesh when there is no history nor tweaks. // if( fHasTweaks ) { // Retrieve the inMesh and name of our mesh node (for the DG eval) // depNodeFn.setObject( meshNode ); MPlug meshNodeInMeshPlug = depNodeFn.findPlug( "inMesh", &status ); MCheckStatus( status, "Could not retrieve inMesh" ); MString meshNodeName = depNodeFn.name(); // Duplicate our current mesh // dagNodeFn.setObject( meshNode ); MObject dupMeshNode = dagNodeFn.duplicate(); // The dagNodeFn::duplicate() returns a transform, but we need a shape // so retrieve the DAG path and extend it to the shape. // MDagPath dupMeshDagPath; MDagPath::getAPathTo( dupMeshNode, dupMeshDagPath ); dupMeshDagPath.extendToShape(); // Retrieve the outMesh of the duplicate mesh and set our mesh data back // on it. // depNodeFn.setObject( dupMeshDagPath.node() ); MPlug dupMeshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status ); MCheckStatus( status, "Could not retrieve outMesh" ); status = dupMeshNodeOutMeshPlug.setValue( fMeshData ); // Temporarily connect the duplicate mesh node to our mesh node // MDGModifier dgModifier; dgModifier.connect( dupMeshNodeOutMeshPlug, meshNodeInMeshPlug ); status = dgModifier.doIt(); MCheckStatus( status, "Could not connect dupMeshNode -> meshNode" ); // Need to force a DG evaluation now that the input has been changed. // MString cmd("dgeval -src "); cmd += meshNodeName; cmd += ".inMesh"; status = MGlobal::executeCommand( cmd, false, false ); MCheckStatus( status, "Could not force DG eval" ); // Disconnect and delete the duplicate mesh node now // dgModifier.undoIt(); MGlobal::deleteNode( dupMeshNode ); // Restore the tweaks on the mesh // status = undoTweakProcessing(); } else { // Restore the original mesh by writing the old mesh data (fMeshData) back // onto the outMesh of our meshNode // depNodeFn.setObject( meshNode ); MPlug meshNodeOutMeshPlug = depNodeFn.findPlug( "outMesh", &status ); MCheckStatus( status, "Could not retrieve outMesh" ); status = meshNodeOutMeshPlug.setValue( fMeshData ); MCheckStatus( status, "Could not set meshData" ); } return status; }
MStatus finalproject::compute(const MPlug& plug, MDataBlock& data) { // do this if we are using an OpenMP implementation that is not the same as Maya's. // Even if it is the same, it does no harm to make this call. MThreadUtils::syncNumOpenMPThreads(); MStatus status = MStatus::kUnknownParameter; if (plug.attribute() != outputGeom) { return status; } unsigned int index = plug.logicalIndex(); MObject thisNode = this->thisMObject(); // get input value MPlug inPlug(thisNode,input); inPlug.selectAncestorLogicalIndex(index,input); MDataHandle hInput = data.inputValue(inPlug, &status); MCheckStatus(status, "ERROR getting input mesh\n"); // get the input geometry MDataHandle inputData = hInput.child(inputGeom); if (inputData.type() != MFnData::kMesh) { printf("Incorrect input geometry type\n"); return MStatus::kFailure; } // get the input groupId - ignored for now... MDataHandle hGroup = inputData.child(groupId); unsigned int groupId = hGroup.asLong(); // get deforming mesh MDataHandle deformData = data.inputValue(deformingMesh, &status); MCheckStatus(status, "ERROR getting deforming mesh\n"); if (deformData.type() != MFnData::kMesh) { printf("Incorrect deformer geometry type %d\n", deformData.type()); return MStatus::kFailure; } MDataHandle offloadData = data.inputValue(offload, &status); //gathers world space positions of the object and the magnet MObject dSurf = deformData.asMeshTransformed(); MObject iSurf = inputData.asMeshTransformed(); MFnMesh fnDeformingMesh, fnInputMesh; fnDeformingMesh.setObject( dSurf ) ; fnInputMesh.setObject( iSurf ) ; MDataHandle outputData = data.outputValue(plug); outputData.copy(inputData); if (outputData.type() != MFnData::kMesh) { printf("Incorrect output mesh type\n"); return MStatus::kFailure; } MItGeometry iter(outputData, groupId, false); // get all points at once. Faster to query, and also better for // threading than using iterator MPointArray objVerts; iter.allPositions(objVerts); int objNumPoints = objVerts.length(); MPointArray magVerts, tempverts; fnDeformingMesh.getPoints(magVerts); fnInputMesh.getPoints(tempverts); int magNumPoints = magVerts.length(); double min = DBL_MAX, max = -DBL_MAX; //finds min and max z-coordinate values to determine middle point (choice of z-axis was ours) for (int i = 0; i < magNumPoints; i++) { min = magVerts[i].z < min ? magVerts[i].z : min; max = magVerts[i].z > max ? magVerts[i].z : max; } double middle = (min + max) / 2; double polarity[magNumPoints]; //assigns polarity based on middle point of mesh for (int i = 0; i < magNumPoints; i++) { polarity[i] = magVerts[i].z > middle ? max / magVerts[i].z : -min / magVerts[i].z; } double* objdVerts = (double *)malloc(sizeof(double) * objNumPoints * 3); double* magdVerts = (double *)malloc(sizeof(double) * magNumPoints * 3); //creates handles to use attribute data MDataHandle vecX = data.inputValue(transX, &status); MDataHandle vecY = data.inputValue(transY, &status); MDataHandle vecZ = data.inputValue(transZ, &status); //gathers previously stored coordinates of the center of the object double moveX = vecX.asFloat(); double moveY = vecY.asFloat(); double moveZ = vecZ.asFloat(); //translates object based on the position stored in the attribute values for (int i=0; i<objNumPoints; i++) { objdVerts[i * 3] = tempverts[i].x + moveX; objdVerts[i * 3 + 1] = tempverts[i].y + moveY; objdVerts[i * 3 + 2] = tempverts[i].z + moveZ; } for (int i=0; i<magNumPoints; i++) { magdVerts[i * 3] = magVerts[i].x; magdVerts[i * 3 + 1] = magVerts[i].y; magdVerts[i * 3 + 2] = magVerts[i].z; } double teslaData = data.inputValue(tesla, &status).asDouble(); MDataHandle posiData = data.inputValue(positivelycharged, &status); double pivot[6] = {DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX}; //finds the pivot point of the object in world space prior to being affected by the magnet for (int i = 0; i < tempverts.length(); i++) { pivot[0] = tempverts[i].x < pivot[0] ? tempverts[i].x : pivot[0]; pivot[1] = tempverts[i].x > pivot[1] ? tempverts[i].x : pivot[1]; pivot[2] = tempverts[i].y < pivot[2] ? tempverts[i].y : pivot[2]; pivot[3] = tempverts[i].y > pivot[3] ? tempverts[i].y : pivot[3]; pivot[4] = tempverts[i].z < pivot[4] ? tempverts[i].z : pivot[4]; pivot[5] = tempverts[i].z > pivot[5] ? tempverts[i].z : pivot[5]; } MTimer timer; timer.beginTimer(); //main function call magnetForce(magNumPoints, objNumPoints, teslaData, magdVerts, objdVerts, polarity, posiData.asBool(), offloadData.asBool()); timer.endTimer(); printf("Runtime for threaded loop %f\n", timer.elapsedTime()); for (int i=0; i<objNumPoints; i++) { objVerts[i].x = objdVerts[i * 3 + 0]; objVerts[i].y = objdVerts[i * 3 + 1]; objVerts[i].z = objdVerts[i * 3 + 2]; } //finds the pivot point of object in world space after being affected by the magnet double objCenter[6] = {DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX}; for (int i = 0; i < tempverts.length(); i++) { objCenter[0] = objVerts[i].x < objCenter[0] ? objVerts[i].x : objCenter[0]; objCenter[1] = objVerts[i].x > objCenter[1] ? objVerts[i].x : objCenter[1]; objCenter[2] = objVerts[i].y < objCenter[2] ? objVerts[i].y : objCenter[2]; objCenter[3] = objVerts[i].y > objCenter[3] ? objVerts[i].y : objCenter[3]; objCenter[4] = objVerts[i].z < objCenter[4] ? objVerts[i].z : objCenter[4]; objCenter[5] = objVerts[i].z > objCenter[5] ? objVerts[i].z : objCenter[5]; } //creates vector based on the two calculated pivot points moveX = (objCenter[0] + objCenter[1]) / 2 - (pivot[0] + pivot[1]) / 2; moveY = (objCenter[2] + objCenter[3]) / 2 - (pivot[2] + pivot[3]) / 2; moveZ = (objCenter[4] + objCenter[5]) / 2 - (pivot[4] + pivot[5]) / 2; //stores pivot vector for next computation if (teslaData) { vecX.setFloat(moveX); vecY.setFloat(moveY); vecZ.setFloat(moveZ); } // write values back onto output using fast set method on iterator iter.setAllPositions(objVerts, MSpace::kWorld); free(objdVerts); free(magdVerts); return status; }
MStatus resetVtxRemapNode::compute( const MPlug& plug, MDataBlock& data ) // // Description: // This method computes the value of the given output plug based // on the values of the input attributes. // // Arguments: // plug - the plug to compute // data - object that provides access to the attributes for this node // { MStatus status = MS::kSuccess; MDataHandle stateData = data.outputValue( state, &status ); MCheckStatus( status, "ERROR getting state" ); // Check for the HasNoEffect/PassThrough flag on the node. // // (stateData is an enumeration standard in all depend nodes - stored as short) // // (0 = Normal) // (1 = HasNoEffect/PassThrough) // (2 = Blocking) // ... // if( stateData.asShort() == 1 ) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Simply redirect the inMesh to the outMesh for the PassThrough effect // outputData.set(inputData.asMesh()); } else { // Check which output attribute we have been asked to // compute. If this node doesn't know how to compute it, // we must return MS::kUnknownParameter // if (plug == outMesh) { MDataHandle inputData = data.inputValue( inMesh, &status ); MCheckStatus(status,"ERROR getting inMesh"); MDataHandle outputData = data.outputValue( outMesh, &status ); MCheckStatus(status,"ERROR getting outMesh"); // Copy the inMesh to the outMesh, and now you can // perform operations in-place on the outMesh // outputData.set(inputData.asMesh()); MObject mesh = outputData.asMesh(); fresetVtxRemapFactory.setMesh( mesh ); status = fresetVtxRemapFactory.doIt(); outputData.setClean(); } else { status = MS::kUnknownParameter; } } return status; }