private void setMeshData(MObject transform, MObject dataWrapper) { // Get the mesh node. MFnDagNode dagFn = new MFnDagNode(transform); MObject mesh = dagFn.child(0); // The mesh node has two geometry inputs: 'inMesh' and 'cachedInMesh'. // 'inMesh' is only used when it has an incoming connection, otherwise // 'cachedInMesh' is used. Unfortunately, the docs say that 'cachedInMesh' // is for internal use only and that changing it may render Maya // unstable. // // To get around that, we do the little dance below... // Use a temporary MDagModifier to create a temporary mesh attribute on // the node. MFnTypedAttribute tAttr = new MFnTypedAttribute(); MObject tempAttr = tAttr.create("tempMesh", "tmpm", MFnData.Type.kMesh); MDagModifier tempMod = new MDagModifier(); tempMod.addAttribute(mesh, tempAttr); tempMod.doIt(); // Set the geometry data onto the temp attribute. dagFn.setObject(mesh); MPlug tempPlug = dagFn.findPlug(tempAttr); tempPlug.setValue(dataWrapper); // Use the temporary MDagModifier to connect the temp attribute to the // node's 'inMesh'. MPlug inMeshPlug = dagFn.findPlug("inMesh"); tempMod.connect(tempPlug, inMeshPlug); tempMod.doIt(); // Force the mesh to update by grabbing its output geometry. dagFn.findPlug("outMesh").asMObject(); // Undo the temporary modifier. tempMod.undoIt(); }
// // Description // // Whenever a connection is made to this node, this method // will get called. // public override bool connectionMade(MPlug plug, MPlug otherPlug, bool asSrc) { if ( plug.attribute.equalEqual(inputSurface) ) { MObject thisObj = thisMObject(); MPlug historyPlug = new MPlug( thisObj, mHasHistoryOnCreate ); historyPlug.setValue( true ); } return base.connectionMade( plug, otherPlug, asSrc ); }
// // Description // // Transforms the given components. This method is used by // the move, rotate, and scale tools in component mode. // The bounding box has to be updated here, so do the normals and // any other attributes that depend on vertex positions. // // Arguments // mat - matrix to transform the components by // componentList - list of components to be transformed, // or an empty list to indicate the whole surface // cachingMode - how to use the supplied pointCache // pointCache - if non-null, save or restore points from this list base // on the cachingMode // public override void transformUsing(MMatrix mat, MObjectArray componentList, MVertexCachingMode cachingMode, MPointArray pointCache) { apiMeshGeom geomPtr = meshGeom(); bool savePoints = (cachingMode == MVertexCachingMode.kSavePoints); int i = 0, j = 0; uint len = componentList.length; if (cachingMode == MVertexCachingMode.kRestorePoints) { // restore the points based on the data provided in the pointCache attribute // uint cacheLen = pointCache.length; if (len > 0) { // traverse the component list // for ( i = 0; i < len && j < cacheLen; i++ ) { MObject comp = componentList[i]; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( comp ); int elemCount = fnComp.elementCount; for ( int idx=0; idx<elemCount && j < cacheLen; idx++, ++j ) { int elemIndex = fnComp.element( idx ); geomPtr.vertices[elemIndex] = pointCache[j]; } } } else { // if the component list is of zero-length, it indicates that we // should transform the entire surface // len = geomPtr.vertices.length; for ( int idx = 0; idx < len && j < cacheLen; ++idx, ++j ) { geomPtr.vertices[idx] = pointCache[j]; } } } else { // Transform the surface vertices with the matrix. // If savePoints is true, save the points to the pointCache. // if (len > 0) { // Traverse the componentList // for ( i=0; i<len; i++ ) { MObject comp = componentList[i]; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( comp ); uint elemCount = (uint)fnComp.elementCount; if (savePoints && 0 == i) { pointCache.sizeIncrement = elemCount; } for ( int idx=0; idx<elemCount; idx++ ) { int elemIndex = fnComp.element( (int)idx ); if (savePoints) { pointCache.append(geomPtr.vertices[elemIndex]); } geomPtr.vertices[elemIndex].multiplyEqual( mat ); geomPtr.normals[idx] = geomPtr.normals[idx].transformAsNormal( mat ); } } } else { // If the component list is of zero-length, it indicates that we // should transform the entire surface // len = geomPtr.vertices.length; if (savePoints) { pointCache.sizeIncrement = len; } for ( int idx = 0; idx < len; ++idx ) { if (savePoints) { pointCache.append(geomPtr.vertices[idx]); } geomPtr.vertices[idx].multiplyEqual( mat ); geomPtr.normals[idx] = geomPtr.normals[idx].transformAsNormal( mat ); } } } // Retrieve the value of the cached surface attribute. // We will set the new geometry data into the cached surface attribute // // Access the datablock directly. This code has to be efficient // and so we bypass the compute mechanism completely. // NOTE: In general we should always go though compute for getting // and setting attributes. // MDataBlock datablock = _forceCache(); MDataHandle cachedHandle = datablock.outputValue( cachedSurface ); apiMeshData cached = cachedHandle.asPluginData as apiMeshData; MDataHandle dHandle = datablock.outputValue( mControlPoints ); // If there is history then calculate the tweaks necessary for // setting the final positions of the vertices. // if ( hasHistory() && (null != cached) ) { // Since the shape has history, we need to store the tweaks (deltas) // between the input shape and the tweaked shape in the control points // attribute. // buildControlPoints( datablock, (int)geomPtr.vertices.length ); MArrayDataHandle cpHandle = new MArrayDataHandle( dHandle ); // Loop through the component list and transform each vertex. // for ( i=0; i<len; i++ ) { MObject comp = componentList[i]; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( comp ); int elemCount = fnComp.elementCount; for ( int idx=0; idx<elemCount; idx++ ) { int elemIndex = fnComp.element( idx ); cpHandle.jumpToElement( (uint)elemIndex ); MDataHandle pntHandle = cpHandle.outputValue(); double[] pnt = pntHandle.Double3; MPoint oldPnt = cached.fGeometry.vertices[elemIndex]; MPoint newPnt = geomPtr.vertices[elemIndex]; MVector offset = newPnt.minus( oldPnt ); pnt[0] += offset[0]; pnt[1] += offset[1]; pnt[2] += offset[2]; pntHandle.Double3 = pnt; } } } // Copy outputSurface to cachedSurface // if ( null == cached ) { MGlobal.displayInfo("NULL cachedSurface data found"); } else { cached.fGeometry = geomPtr; } MPlug pCPs = new MPlug( thisMObject(), mControlPoints ); pCPs.setValue(dHandle); // Moving vertices will likely change the bounding box. // computeBoundingBox( datablock ); // Tell Maya the bounding box for this object has changed // and thus "boundingBox()" needs to be called. // childChanged( MChildChanged.kBoundingBoxChanged ); }
public override bool connectionBroken(MPlug plug, MPlug otherPlug, bool asSrc) // // Description // // Whenever a connection to this node is broken, this method // will get called. // { if ( plug.attribute.equalEqual(inputSurface) ) { MObject thisObj = thisMObject(); MPlug historyPlug = new MPlug( thisObj, mHasHistoryOnCreate ); historyPlug.setValue( false ); } return base.connectionBroken( plug, otherPlug, asSrc ); }
public override void redoIt() { MObject dependNode = new MObject(); MOStream stdoutstream = MStreamUtils.stdOutStream(); for (; !iter.isDone; iter.next()) { // Get the selected dependency node and create // a function set for it // try { iter.getDependNode(dependNode); } catch (System.Exception) { MStreamUtils.writeCharBuffer(MStreamUtils.stdErrorStream(), "Error getting the dependency node"); continue; } MFnDependencyNode fnDN; try { fnDN = new MFnDependencyNode(dependNode); } catch (System.Exception) { MStreamUtils.writeCharBuffer(MStreamUtils.stdErrorStream(), "Error creating MFnDependencyNode"); continue; } MFnTypedAttribute fnAttr = new MFnTypedAttribute(); MObject newAttr = fnAttr.create("blindDoubleData", "BDD", blindDoubleData.tid); try { fnDN.addAttribute(newAttr, MFnDependencyNode.MAttrClass.kLocalDynamicAttr); } catch (System.Exception) { // do nothing // addAttribute only need call once, the redundant calls will return false (throw exception) } // Create a plug to set and retrieve value off the node. // MPlug plug = new MPlug(dependNode, newAttr); // ----------------------------------- Attention ------------------------------------ // --------------------------------- Downcast Begin ----------------------------------- // the following codes are used to get the c# object // MFnPluginData pdFnCreator = new MFnPluginData(); // 1. you cannot gain blindDoubleData by the following code // {code} // blindDoubleData newData = new blindDoubleData() // {code} // As we need to keep the relationship between c# impl and c++ instance pointer // We cannot use the above ctor codes, otherwise, the mandatory information used for down casting is omitted // 2. you cannot use the tempData gained by the following code // {code} // MObject tempData = pdFnCreator.create(blindDoubleData.tid); // {code} // reason: // tempData is useless, we cannot use tempData to do downcast // the create function gains the tempData by the following code // // {code} // newHandle = new MObject(mayaHandle); // {code} // // the mayaHandle is the actual pointer, which we store. But we have no information about the newHandle // the return object is useless. the data we needed is stored in pdFnCreator pdFnCreator.create(blindDoubleData.tid); // 3. get "the data" we needed blindDoubleData newData = pdFnCreator.data() as blindDoubleData; // ---------------------------------- Downcast End ----------------------------------- if (newData == null) { continue; } newData.value = 3.2; plug.setValue(newData); // Now try to retrieve the value of the plug as an MObject. // MObject sData = new MObject(); try { plug.getValue(sData); } catch (System.Exception) { continue; } // Convert the data back to MPxData. // MFnPluginData pdFn = new MFnPluginData(sData); blindDoubleData data = pdFn.data() as blindDoubleData; // Get the value. // if (null == data) { // error MStreamUtils.writeCharBuffer(MStreamUtils.stdErrorStream(), "error: failed to retrieve data."); } MStreamUtils.writeLine(stdoutstream); MStreamUtils.writeCharBuffer(stdoutstream, ">>>>>>>>>>>>>>>>>>>>>>>> blindDoubleData binary >>>>>>>>>>>>>>>>>>>>"); MStreamUtils.writeLine(stdoutstream); data.writeBinary(stdoutstream); MStreamUtils.writeLine(stdoutstream); MStreamUtils.writeCharBuffer(stdoutstream, ">>>>>>>>>>>>>>>>>>>>>>>> blindDoubleData ascii >>>>>>>>>>>>>>>>>>>>"); MStreamUtils.writeLine(stdoutstream); data.writeASCII(stdoutstream); } return; }
public override void redoIt() { MObject dependNode = new MObject(); MOStream stdoutstream = MStreamUtils.stdOutStream(); for(; !iter.isDone; iter.next()) { // Get the selected dependency node and create // a function set for it // try { iter.getDependNode(dependNode); } catch (System.Exception) { MStreamUtils.writeCharBuffer(MStreamUtils.stdErrorStream(), "Error getting the dependency node"); continue; } MFnDependencyNode fnDN; try { fnDN = new MFnDependencyNode(dependNode); } catch(System.Exception) { MStreamUtils.writeCharBuffer(MStreamUtils.stdErrorStream(), "Error creating MFnDependencyNode"); continue; } MFnTypedAttribute fnAttr = new MFnTypedAttribute(); MObject newAttr = fnAttr.create("blindDoubleData", "BDD", blindDoubleData.tid); try { fnDN.addAttribute(newAttr, MFnDependencyNode.MAttrClass.kLocalDynamicAttr); } catch (System.Exception) { // do nothing // addAttribute only need call once, the redundant calls will return false (throw exception) } // Create a plug to set and retrieve value off the node. // MPlug plug = new MPlug(dependNode, newAttr); // ----------------------------------- Attention ------------------------------------ // --------------------------------- Downcast Begin ----------------------------------- // the following codes are used to get the c# object // MFnPluginData pdFnCreator = new MFnPluginData(); // 1. you cannot gain blindDoubleData by the following code // {code} // blindDoubleData newData = new blindDoubleData() // {code} // As we need to keep the relationship between c# impl and c++ instance pointer // We cannot use the above ctor codes, otherwise, the mandatory information used for down casting is omitted // 2. you cannot use the tempData gained by the following code // {code} // MObject tempData = pdFnCreator.create(blindDoubleData.tid); // {code} // reason: // tempData is useless, we cannot use tempData to do downcast // the create function gains the tempData by the following code // // {code} // newHandle = new MObject(mayaHandle); // {code} // // the mayaHandle is the actual pointer, which we store. But we have no information about the newHandle // the return object is useless. the data we needed is stored in pdFnCreator pdFnCreator.create(blindDoubleData.tid); // 3. get "the data" we needed blindDoubleData newData = pdFnCreator.data() as blindDoubleData; // ---------------------------------- Downcast End ----------------------------------- if (newData == null) continue; newData.value = 3.2; plug.setValue(newData); // Now try to retrieve the value of the plug as an MObject. // MObject sData = new MObject(); try { plug.getValue( sData ); } catch (System.Exception) { continue; } // Convert the data back to MPxData. // MFnPluginData pdFn = new MFnPluginData( sData ); blindDoubleData data = pdFn.data() as blindDoubleData; // Get the value. // if ( null == data ) { // error MStreamUtils.writeCharBuffer(MStreamUtils.stdErrorStream(), "error: failed to retrieve data."); } MStreamUtils.writeLine(stdoutstream); MStreamUtils.writeCharBuffer(stdoutstream, ">>>>>>>>>>>>>>>>>>>>>>>> blindDoubleData binary >>>>>>>>>>>>>>>>>>>>"); MStreamUtils.writeLine(stdoutstream); data.writeBinary(stdoutstream); MStreamUtils.writeLine(stdoutstream); MStreamUtils.writeCharBuffer(stdoutstream, ">>>>>>>>>>>>>>>>>>>>>>>> blindDoubleData ascii >>>>>>>>>>>>>>>>>>>>"); MStreamUtils.writeLine(stdoutstream); data.writeASCII(stdoutstream); } return; }