public MSelectionList RestoreSelectionOnList(MSelectionList targetList = null, bool selectResult = false) { if (targetList == null || targetList.length == 0) { targetList = BasicFunc.GetSelectedList(); } MSelectionList resultSelection = new MSelectionList(); for (int i = 0; i < targetList.length; i++) { if (i >= selectedIndicesList.Count) { break; } MDagPath dag = new MDagPath(); targetList.getDagPath((uint)i, dag); MFnSingleIndexedComponent sic = new MFnSingleIndexedComponent(); MObject components = sic.create(MFn.Type.kMeshPolygonComponent); sic.addElements(new MIntArray(selectedIndicesList[i])); resultSelection.add(dag, components); //resultSelection.add(dag); } if (selectResult) { BasicFunc.Select(resultSelection); } return(resultSelection); }
public override bool updateCompleteVertexGroup(MObject component) // // Description // Make sure complete vertex group data is up-to-date. // Returns true if the component was updated, false if it was already ok. // // This is used by deformers when deforming the "whole" object and // not just selected components. // { MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(component); // Make sure there is non-null geometry and that the component // is "complete". A "complete" component represents every // vertex in the shape. // if ((null != fGeometry) && (fnComponent.isComplete)) { int maxVerts; fnComponent.getCompleteData(out maxVerts); int numVertices = (int)fGeometry.vertices.length; if ((numVertices > 0) && (maxVerts != numVertices)) { // Set the component to be complete, i.e. the elements in // the component will be [0:numVertices-1] // fnComponent.setCompleteData(numVertices); return(true); } } return(false); }
public MSelectionList RestoreSelectionOnDag(MDagPath targetDag = null, bool selectResult = false) { if (targetDag == null) { return(null); } MSelectionList resultSelection = new MSelectionList(); MFnSingleIndexedComponent sic = new MFnSingleIndexedComponent(); MObject components = sic.create(MFn.Type.kMeshPolygonComponent); sic.addElements(new MIntArray(selectedIndicesList[0])); resultSelection.add(targetDag, components); //resultSelection.add(targetDag); if (selectResult) { BasicFunc.Select(resultSelection); } return(resultSelection); }
public override void tweakUsing( MMatrix mat, MObjectArray componentList, MVertexCachingMode cachingMode, MPointArray pointCache, MArrayDataHandle handle ) // // Description // // Transforms the given components. This method is used by // the move, rotate, and scale tools in component mode when the // tweaks for the shape are stored on a separate tweak node. // 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 // handle - handle to the attribute on the tweak node where the // tweaks should be stored // { apiMeshGeom geomPtr = meshGeom(); bool savePoints = (cachingMode == MVertexCachingMode.kSavePoints); bool updatePoints = (cachingMode == MVertexCachingMode.kUpdatePoints); MArrayDataBuilder builder = handle.builder(); MPoint delta = new MPoint(); MPoint currPt = new MPoint(); MPoint newPt = new MPoint(); int i=0; uint len = componentList.length; int cacheIndex = 0; uint cacheLen = (null != pointCache) ? pointCache.length : 0; if (cachingMode == MVertexCachingMode.kRestorePoints) { // restore points from the pointCache // if (len > 0) { // traverse the component list // 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 && cacheIndex < cacheLen; idx++, cacheIndex++) { int elemIndex = fnComp.element( idx ); MDataHandle hdl = builder.addElement((uint)elemIndex); double[] pt = hdl.Double3; MPoint cachePt = pointCache[cacheIndex]; pt[0] += cachePt.x; pt[1] += cachePt.y; pt[2] += cachePt.z; hdl.Double3 = pt; } } } else { // if the component list is of zero-length, it indicates that we // should transform the entire surface // len = geomPtr.vertices.length; for ( uint idx = 0; idx < len && idx < cacheLen; ++idx ) { MDataHandle hdl = builder.addElement(idx); double[] pt = hdl.Double3; MPoint cachePt = pointCache[cacheIndex]; pt[0] += cachePt.x; pt[1] += cachePt.y; pt[2] += cachePt.z; hdl.Double3 = pt; } } } else { // Tweak the points. If savePoints is true, also save the tweaks in the // pointCache. If updatePoints is true, add the new tweaks to the existing // data in the pointCache. // if (len > 0) { for ( i=0; i<len; i++ ) { MObject comp = componentList[i]; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( comp ); int elemCount = fnComp.elementCount; if (savePoints) { pointCache.sizeIncrement = (uint)elemCount; } for ( int idx=0; idx<elemCount; idx++ ) { int elemIndex = fnComp.element( idx ); MDataHandle hdl = builder.addElement((uint)elemIndex); double[] pt = hdl.Double3; currPt = newPt = geomPtr.vertices[elemIndex]; newPt.multiplyEqual( mat ); delta.x = newPt.x - currPt.x; delta.y = newPt.y - currPt.y; delta.z = newPt.z - currPt.z; pt[0] += delta.x; pt[1] += delta.y; pt[2] += delta.z; hdl.Double3 = pt; if (savePoints) { // store the points in the pointCache for undo // pointCache.append(delta*(-1.0)); } else if (updatePoints && cacheIndex < cacheLen) { MPoint cachePt = pointCache[cacheIndex]; cachePt[0] -= delta.x; cachePt[1] -= delta.y; cachePt[2] -= delta.z; cacheIndex++; } } } } 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 ) { MDataHandle hdl = builder.addElement((uint)idx); double[] pt = hdl.Double3; currPt = newPt = geomPtr.vertices[idx]; newPt.multiplyEqual( mat ); delta.x = newPt.x - currPt.x; delta.y = newPt.y - currPt.y; delta.z = newPt.z - currPt.z; pt[0] += delta.x; pt[1] += delta.y; pt[2] += delta.z; hdl.Double3 = pt; if (savePoints) { // store the points in the pointCache for undo // pointCache.append(delta*-1.0); } else if (updatePoints && idx < cacheLen) { MPoint cachePt = pointCache[idx]; cachePt[0] -= delta.x; cachePt[1] -= delta.y; cachePt[2] -= delta.z; } } } } // Set the builder into the handle. // handle.set(builder); // Tell Maya the bounding box for this object has changed // and thus "boundingBox()" needs to be called. // childChanged( MChildChanged.kBoundingBoxChanged ); }
// Support deformers (components) // public override MObject createFullVertexGroup() // // Description // This method is used by Maya when it needs to create a component // containing every vertex (or control point) in the shape. // This will get called if you apply some deformer to the whole // shape, i.e. select the shape in object mode and add a deformer to it. // // Returns // // A "complete" component representing all vertices in the shape. // { // Create a vertex component // MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(); MObject fullComponent = fnComponent.create( MFn.Type.kMeshVertComponent ); // Set the component to be complete, i.e. the elements in // the component will be [0:numVertices-1] // int numVertices = (int)meshGeom().vertices.length; fnComponent.setCompleteData( numVertices ); return fullComponent; }
public override MatchResult matchComponent(MSelectionList item, MAttributeSpecArray spec, MSelectionList list) // // Description: // // Component/attribute matching method. // This method validates component names and indices which are // specified as a string and adds the corresponding component // to the passed in selection list. // // For instance, select commands such as "select shape1.vtx[0:7]" // are validated with this method and the corresponding component // is added to the selection list. // // Arguments // // item - DAG selection item for the object being matched // spec - attribute specification object // list - list to add components to // // Returns // // the result of the match // { MatchResult result = MatchResult.kMatchOk; MAttributeSpec attrSpec = spec[0]; int dim = attrSpec.dimensions; // Look for attributes specifications of the form : // vtx[ index ] // vtx[ lower:upper ] // if ( (1 == spec.length) && (dim > 0) && (attrSpec.name == "vtx") ) { int numVertices = (int)meshGeom().vertices.length; MAttributeIndex attrIndex = attrSpec[0]; int upper = 0; int lower = 0; if ( attrIndex.hasLowerBound ) { attrIndex.getLower( out lower ); } if ( attrIndex.hasUpperBound ) { attrIndex.getUpper( out upper ); } // Check the attribute index range is valid // if ( (lower > upper) || (upper >= numVertices) ) { result = MatchResult.kMatchInvalidAttributeRange; } else { MDagPath path = new MDagPath(); item.getDagPath( 0, path ); MFnSingleIndexedComponent fnVtxComp = new MFnSingleIndexedComponent(); MObject vtxComp = fnVtxComp.create( MFn.Type.kMeshVertComponent ); for ( int i=lower; i<=upper; i++ ) { fnVtxComp.addElement( i ); } list.add( path, vtxComp ); } } else { // Pass this to the parent class return base.matchComponent( item, spec, list ); } return result; }
public override void componentToPlugs(MObject component, MSelectionList list) // // Description // // Converts the given component values into a selection list of plugs. // This method is used to map components to attributes. // // Arguments // // component - the component to be translated to a plug/attribute // list - a list of plugs representing the passed in component // { if ( component.hasFn(MFn.Type.kSingleIndexedComponent) ) { MFnSingleIndexedComponent fnVtxComp = new MFnSingleIndexedComponent( component ); MObject thisNode = thisMObject(); MPlug plug = new MPlug( thisNode, mControlPoints ); // If this node is connected to a tweak node, reset the // plug to point at the tweak node. // convertToTweakNodePlug(plug); int len = fnVtxComp.elementCount; for ( int i = 0; i < len; i++ ) { plug.selectAncestorLogicalIndex((uint)fnVtxComp.element(i), plug.attribute); list.add(plug); } } }
public void drawVertices(MDrawRequest request, M3dView view) { MDrawData data = request.drawData(); MVectorArray geom = data.geometry() as MVectorArray; view.beginGL(); // Query current state so it can be restored // bool lightingWasOn = OpenGL.glIsEnabled(OpenGL.GL_LIGHTING) != 0 ? true : false; if (lightingWasOn) { OpenGL.glDisable(OpenGL.GL_LIGHTING); } float lastPointSize; getLastPointSize(out lastPointSize); // Set the point size of the vertices // OpenGL.glPointSize(POINT_SIZE); // If there is a component specified by the draw request // then loop over comp (using an MFnComponent class) and draw the // active vertices, otherwise draw all vertices. // MObject comp = request.component; if (!comp.isNull) { MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(comp); for (int i = 0; i < fnComponent.elementCount; i++) { int index = fnComponent.element(i); OpenGL.glBegin(OpenGL.GL_POINTS); MVector point = geom[index]; OpenGL.glVertex3f((float)point[0], (float)point[1], (float)point[2]); OpenGL.glEnd(); MPoint mp = new MPoint(point); view.drawText(String.Format("{0}", index), mp); } } else { for (int i = 0; i < geom.length; i++) { OpenGL.glBegin(OpenGL.GL_POINTS); MVector point = geom[i]; OpenGL.glVertex3f((float)point[0], (float)point[1], (float)point[2]); OpenGL.glEnd(); } } // Restore the state // if (lightingWasOn) { OpenGL.glEnable(OpenGL.GL_LIGHTING); } OpenGL.glPointSize(lastPointSize); view.endGL(); }
// // Description // This method is used by Maya when it needs to create a component // containing every vertex (or control point) in the shape. // This will get called if you apply some deformer to the whole // shape, i.e. select the shape in object mode and add a deformer to it. // // Returns // // A "complete" component representing all vertices in the shape. // // Support deformers (components) // public override MObject createFullVertexGroup() { // Create a vertex component // MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(); MObject fullComponent = fnComponent.create( MFn.Type.kMeshVertComponent ); // Set the component to be complete, i.e. the elements in // the component will be [0:numVertices-1] // int numVertices = (int)meshGeom().vertices.length; fnComponent.setCompleteData( numVertices ); return fullComponent; }
public bool selectVertices(MSelectInfo selectInfo, MSelectionList selectionList, MPointArray worldSpaceSelectPts) // // Description: // // Vertex selection. // // Arguments: // // selectInfo - the selection state information // selectionList - the list of selected items to add to // worldSpaceSelectPts - // { bool selected = false; M3dView view = selectInfo.view; MPoint xformedPoint = new MPoint(); MPoint selectionPoint = new MPoint(); double z = 0.0; double previousZ = 0.0; int closestPointVertexIndex = -1; MDagPath path = selectInfo.multiPath; // Create a component that will store the selected vertices // MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(); MObject surfaceComponent = fnComponent.create(MFn.Type.kMeshVertComponent); uint vertexIndex; // if the user did a single mouse click and we find > 1 selection // we will use the alignmentMatrix to find out which is the closest // MMatrix alignmentMatrix = new MMatrix(); MPoint singlePoint = new MPoint(); bool singleSelection = selectInfo.singleSelection; if (singleSelection) { alignmentMatrix = selectInfo.alignmentMatrix; } // Get the geometry information // apiMesh meshNode = (apiMesh)surfaceShape; apiMeshGeom geom = meshNode.meshGeom(); // Loop through all vertices of the mesh and // see if they lie withing the selection area // uint numVertices = geom.vertices.length; for (vertexIndex = 0; vertexIndex < numVertices; vertexIndex++) { MPoint currentPoint = geom.vertices[(int)vertexIndex]; // Sets OpenGL's render mode to select and stores // selected items in a pick buffer // view.beginSelect(); OpenGL.glBegin(OpenGL.GL_POINTS); OpenGL.glVertex3f((float)currentPoint[0], (float)currentPoint[1], (float)currentPoint[2]); OpenGL.glEnd(); if (view.endSelect() > 0) // Hit count > 0 { selected = true; if (singleSelection) { xformedPoint = currentPoint; xformedPoint.homogenize(); xformedPoint.multiplyEqual(alignmentMatrix); z = xformedPoint.z; if (closestPointVertexIndex < 0 || z > previousZ) { closestPointVertexIndex = (int)vertexIndex; singlePoint = currentPoint; previousZ = z; } } else { // multiple selection, store all elements // fnComponent.addElement((int)vertexIndex); } } } // If single selection, insert the closest point into the array // if (selected && selectInfo.singleSelection) { fnComponent.addElement(closestPointVertexIndex); // need to get world space position for this vertex // selectionPoint = singlePoint; selectionPoint.multiplyEqual(path.inclusiveMatrix); } // Add the selected component to the selection list // if (selected) { MSelectionList selectionItem = new MSelectionList(); selectionItem.add(path, surfaceComponent); MSelectionMask mask = new MSelectionMask(MSelectionMask.SelectionType.kSelectComponentsMask); selectInfo.addSelection( selectionItem, selectionPoint, selectionList, worldSpaceSelectPts, mask, true); } return(selected); }
// // 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 ); }
// // Description: // // Vertex selection. // // Arguments: // // selectInfo - the selection state information // selectionList - the list of selected items to add to // worldSpaceSelectPts - // public bool selectVertices( MSelectInfo selectInfo, MSelectionList selectionList, MPointArray worldSpaceSelectPts) { bool selected = false; M3dView view = selectInfo.view; MPoint xformedPoint = new MPoint(); MPoint selectionPoint = new MPoint(); double z = 0.0; double previousZ = 0.0; int closestPointVertexIndex = -1; MDagPath path = selectInfo.multiPath; // Create a component that will store the selected vertices // MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(); MObject surfaceComponent = fnComponent.create( MFn.Type.kMeshVertComponent ); uint vertexIndex; // if the user did a single mouse click and we find > 1 selection // we will use the alignmentMatrix to find out which is the closest // MMatrix alignmentMatrix = new MMatrix(); MPoint singlePoint = new MPoint(); bool singleSelection = selectInfo.singleSelection; if( singleSelection ) { alignmentMatrix = selectInfo.alignmentMatrix; } // Get the geometry information // apiMesh meshNode = (apiMesh)surfaceShape; apiMeshGeom geom = meshNode.meshGeom(); // Loop through all vertices of the mesh and // see if they lie withing the selection area // uint numVertices = geom.vertices.length; for ( vertexIndex=0; vertexIndex<numVertices; vertexIndex++ ) { MPoint currentPoint = geom.vertices[ (int)vertexIndex ]; // Sets OpenGL's render mode to select and stores // selected items in a pick buffer // view.beginSelect(); OpenGL.glBegin(OpenGL.GL_POINTS); OpenGL.glVertex3f((float)currentPoint[0], (float)currentPoint[1], (float)currentPoint[2] ); OpenGL.glEnd(); if ( view.endSelect() > 0 ) // Hit count > 0 { selected = true; if ( singleSelection ) { xformedPoint = currentPoint; xformedPoint.homogenize(); xformedPoint.multiplyEqual( alignmentMatrix ); z = xformedPoint.z; if ( closestPointVertexIndex < 0 || z > previousZ ) { closestPointVertexIndex = (int)vertexIndex; singlePoint = currentPoint; previousZ = z; } } else { // multiple selection, store all elements // fnComponent.addElement( (int)vertexIndex ); } } } // If single selection, insert the closest point into the array // if ( selected && selectInfo.singleSelection ) { fnComponent.addElement(closestPointVertexIndex); // need to get world space position for this vertex // selectionPoint = singlePoint; selectionPoint.multiplyEqual( path.inclusiveMatrix ); } // Add the selected component to the selection list // if ( selected ) { MSelectionList selectionItem = new MSelectionList(); selectionItem.add( path, surfaceComponent ); MSelectionMask mask = new MSelectionMask( MSelectionMask.SelectionType.kSelectComponentsMask ); selectInfo.addSelection( selectionItem, selectionPoint, selectionList, worldSpaceSelectPts, mask, true ); } return selected; }
// // Description: // // Component (vertex) drawing routine // // Arguments: // // request - request to be drawn // view - view to draw into // public void drawVertices( MDrawRequest request, M3dView view ) { MDrawData data = request.drawData(); apiMeshGeom geom = (apiMeshGeom)data.geometry(); if (geom == null) return; view.beginGL(); // Query current state so it can be restored // bool lightingWasOn = OpenGL.glIsEnabled(OpenGL.GL_LIGHTING) != 0; if ( lightingWasOn ) { OpenGL.glDisable(OpenGL.GL_LIGHTING); } float[] lastPointSize = new float[1]; OpenGL.glGetFloatv(OpenGL.GL_POINT_SIZE, lastPointSize); // Set the point size of the vertices // OpenGL.glPointSize(POINT_SIZE); // If there is a component specified by the draw request // then loop over comp (using an MFnComponent class) and draw the // active vertices, otherwise draw all vertices. // MObject comp = request.component; if ( ! comp.isNull ) { MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent( comp ); for ( int i=0; i<fnComponent.elementCount; i++ ) { int index = fnComponent.element( i ); OpenGL.glBegin(OpenGL.GL_POINTS); MPoint vertex = geom.vertices[ index ]; OpenGL.glVertex3f((float)vertex[0], (float)vertex[1], (float)vertex[2] ); OpenGL.glEnd(); string annotation = index.ToString(); view.drawText( annotation, vertex ); } } else { int vid = 0; for ( int i=0; i<geom.faceCount; i++ ) { OpenGL.glBegin(OpenGL.GL_POINTS); for ( int v=0; v<geom.face_counts[i]; v++ ) { MPoint vertex = geom.vertices[ geom.face_connects[vid++] ]; OpenGL.glVertex3f((float)vertex[0], (float)vertex[1], (float)vertex[2] ); } OpenGL.glEnd(); } } // Restore the state // if ( lightingWasOn ) { OpenGL.glEnable(OpenGL.GL_LIGHTING); } OpenGL.glPointSize(lastPointSize[0]); view.endGL(); }
// // Description // Make sure complete vertex group data is up-to-date. // Returns true if the component was updated, false if it was already ok. // // This is used by deformers when deforming the "whole" object and // not just selected components. // public override bool updateCompleteVertexGroup( MObject component ) { MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent( component ); // Make sure there is non-null geometry and that the component // is "complete". A "complete" component represents every // vertex in the shape. // if ( (null != fGeometry) && (fnComponent.isComplete) ) { int maxVerts ; fnComponent.getCompleteData( out maxVerts ); int numVertices = (int)fGeometry.vertices.length; if ( (numVertices > 0) && (maxVerts != numVertices) ) { // Set the component to be complete, i.e. the elements in // the component will be [0:numVertices-1] // fnComponent.setCompleteData( numVertices ); return true; } } return false; }
public void Load(string name) { List <StaticObjectVertex> vertices = GetVertices(); List <uint> indices = GetIndices(); MIntArray polygonIndexCounts = new MIntArray((uint)indices.Count / 3); MIntArray polygonIndices = new MIntArray((uint)indices.Count); MFloatPointArray meshVertices = new MFloatPointArray((uint)vertices.Count); MFloatArray arrayU = new MFloatArray((uint)vertices.Count); MFloatArray arrayV = new MFloatArray((uint)vertices.Count); MFnMesh mesh = new MFnMesh(); MDagPath meshDagPath = new MDagPath(); MDGModifier modifier = new MDGModifier(); MFnSet set = new MFnSet(); for (int i = 0; i < indices.Count / 3; i++) { polygonIndexCounts[i] = 3; } for (int i = 0; i < indices.Count; i++) { polygonIndices[i] = (int)indices[i]; } for (int i = 0; i < vertices.Count; i++) { StaticObjectVertex vertex = vertices[i]; meshVertices[i] = new MFloatPoint(vertex.Position.X, vertex.Position.Y, vertex.Position.Z); arrayU[i] = vertex.UV.X; arrayV[i] = 1 - vertex.UV.Y; } //Assign mesh data mesh.create(vertices.Count, indices.Count / 3, meshVertices, polygonIndexCounts, polygonIndices, arrayU, arrayV, MObject.kNullObj); mesh.getPath(meshDagPath); mesh.assignUVs(polygonIndexCounts, polygonIndices); //Set names mesh.setName(name); MFnTransform transformNode = new MFnTransform(mesh.parent(0)); transformNode.setName("transform_" + name); //Get render partition MFnPartition renderPartition = MayaHelper.FindRenderPartition(); //Create Materials uint startIndex = 0; for (int i = 0; i < this.Submeshes.Count; i++) { MFnDependencyNode dependencyNode = new MFnDependencyNode(); MFnLambertShader lambertShader = new MFnLambertShader(); StaticObjectSubmesh submesh = this.Submeshes[i]; lambertShader.create(true); lambertShader.setName(submesh.Name); lambertShader.color = MaterialProvider.GetMayaColor(i); MObject shadingEngine = dependencyNode.create("shadingEngine", submesh.Name + "_SG"); MObject materialInfo = dependencyNode.create("materialInfo", submesh.Name + "_MaterialInfo"); MPlug partitionPlug = new MFnDependencyNode(shadingEngine).findPlug("partition"); MPlug setsPlug = MayaHelper.FindFirstNotConnectedElement(renderPartition.findPlug("sets")); modifier.connect(partitionPlug, setsPlug); MPlug outColorPlug = lambertShader.findPlug("outColor"); MPlug surfaceShaderPlug = new MFnDependencyNode(shadingEngine).findPlug("surfaceShader"); modifier.connect(outColorPlug, surfaceShaderPlug); MPlug messagePlug = new MFnDependencyNode(shadingEngine).findPlug("message"); MPlug shadingGroupPlug = new MFnDependencyNode(materialInfo).findPlug("shadingGroup"); modifier.connect(messagePlug, shadingGroupPlug); modifier.doIt(); MFnSingleIndexedComponent component = new MFnSingleIndexedComponent(); MObject faceComponent = component.create(MFn.Type.kMeshPolygonComponent); MIntArray groupPolygonIndices = new MIntArray(); uint endIndex = (startIndex + (uint)submesh.Indices.Count) / 3; for (uint j = startIndex / 3; j < endIndex; j++) { groupPolygonIndices.append((int)j); } component.addElements(groupPolygonIndices); set.setObject(shadingEngine); set.addMember(meshDagPath, faceComponent); startIndex += (uint)submesh.Indices.Count; } mesh.updateSurface(); }
// // Description // // Returns offsets for the given components to be used my the // move tool in normal/u/v mode. // // Arguments // // component - components to calculate offsets for // direction - array of offsets to be filled // mode - the type of offset to be calculated // normalize - specifies whether the offsets should be normalized // // Returns // // true if the offsets could be calculated, false otherwise // // Support the move tools normal/u/v mode (components) // public override bool vertexOffsetDirection( MObject component, MVectorArray direction, MVertexOffsetMode mode, bool normalize) { bool offsetOkay = false ; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( component ); if ( component.apiType != MFn.Type.kMeshVertComponent ) { return false; } offsetOkay = true ; apiMeshGeom geomPtr = meshGeom(); if ( null == geomPtr ) { return false; } // For each vertex add the appropriate offset // int count = fnComp.elementCount; for ( int idx=0; idx<count; idx++ ) { MVector normal = geomPtr.normals[ fnComp.element(idx) ]; if( mode == MVertexOffsetMode.kNormal ) { if( normalize ) normal.normalize() ; direction.append( normal ); } else { // Construct an orthonormal basis from the normal // uAxis, and vAxis are the new vectors. // MVector uAxis = new MVector(); MVector vAxis = new MVector(); uint i, j, k; double a; normal.normalize(); i = 0; a = Math.Abs( normal[0] ); if ( a < Math.Abs(normal[1]) ) { i = 1; a = Math.Abs(normal[1]); } if ( a < Math.Abs(normal[2]) ) { i = 2; } j = (i+1)%3; k = (j+1)%3; a = Math.Sqrt(normal[i]*normal[i] + normal[j]*normal[j]); uAxis[i] = -normal[j]/a; uAxis[j] = normal[i]/a; uAxis[k] = 0.0; vAxis = normal.crossProduct( uAxis ); if ( mode == MVertexOffsetMode.kUTangent || mode == MVertexOffsetMode.kUVNTriad ) { if( normalize ) uAxis.normalize() ; direction.append( uAxis ); } if ( mode == MVertexOffsetMode.kVTangent || mode == MVertexOffsetMode.kUVNTriad ) { if( normalize ) vAxis.normalize() ; direction.append( vAxis ); } if ( mode == MVertexOffsetMode.kUVNTriad ) { if( normalize ) normal.normalize() ; direction.append( normal ); } } } return offsetOkay; }
public void Create(SKLFile skl) { MSelectionList currentSelection = MGlobal.activeSelectionList; MItSelectionList currentSelectionIterator = new MItSelectionList(currentSelection, MFn.Type.kMesh); MDagPath meshDagPath = new MDagPath(); if (currentSelectionIterator.isDone) { MGlobal.displayError("SKNFile:Create - No mesh selected!"); throw new Exception("SKNFile:Create - No mesh selected!"); } else { currentSelectionIterator.getDagPath(meshDagPath); currentSelectionIterator.next(); if (!currentSelectionIterator.isDone) { MGlobal.displayError("SKNFile:Create - More than one mesh selected!"); throw new Exception("SKNFile:Create - More than one mesh selected!"); } } MFnMesh mesh = new MFnMesh(meshDagPath); //Find Skin Cluster MPlug inMeshPlug = mesh.findPlug("inMesh"); MPlugArray inMeshConnections = new MPlugArray(); inMeshPlug.connectedTo(inMeshConnections, true, false); if (inMeshConnections.length == 0) { MGlobal.displayError("SKNFile:Create - Failed to find Skin Cluster!"); throw new Exception("SKNFile:Create - Failed to find Skin Cluster!"); } MPlug outputGeometryPlug = inMeshConnections[0]; MFnSkinCluster skinCluster = new MFnSkinCluster(outputGeometryPlug.node); MDagPathArray influenceDagPaths = new MDagPathArray(); uint influenceCount = skinCluster.influenceObjects(influenceDagPaths); MGlobal.displayInfo("SKNFile:Create - Influence Count: " + influenceCount); //Get SKL Influence Indices MIntArray sklInfluenceIndices = new MIntArray(influenceCount); for (int i = 0; i < influenceCount; i++) { MDagPath jointDagPath = influenceDagPaths[i]; MGlobal.displayInfo(jointDagPath.fullPathName); //Loop through Joint DAG Paths, if we find a math for the influence, write the index for (int j = 0; j < skl.JointDagPaths.Count; j++) { if (jointDagPath.equalEqual(skl.JointDagPaths[j])) { MGlobal.displayInfo("Found coresponding DAG path"); sklInfluenceIndices[i] = j; break; } } } //Add Influence indices to SKL File MIntArray maskInfluenceIndex = new MIntArray(influenceCount); for (int i = 0; i < influenceCount; i++) { maskInfluenceIndex[i] = i; skl.Influences.Add((short)sklInfluenceIndices[i]); } MObjectArray shaders = new MObjectArray(); MIntArray polygonShaderIndices = new MIntArray(); mesh.getConnectedShaders(meshDagPath.isInstanced ? meshDagPath.instanceNumber : 0, shaders, polygonShaderIndices); uint shaderCount = shaders.length; if (shaderCount > 32) //iirc 32 is the limit of how many submeshes there can be for an SKN file { MGlobal.displayError("SKNFile:Create - You've exceeded the maximum limit of 32 shaders"); throw new Exception("SKNFile:Create - You've exceeded the maximum limit of 32 shaders"); } MIntArray vertexShaders = new MIntArray(); ValidateMeshTopology(mesh, meshDagPath, polygonShaderIndices, ref vertexShaders, shaderCount); //Get Weights MFnSingleIndexedComponent vertexIndexedComponent = new MFnSingleIndexedComponent(); MObject vertexComponent = vertexIndexedComponent.create(MFn.Type.kMeshVertComponent); MIntArray groupVertexIndices = new MIntArray((uint)mesh.numVertices); for (int i = 0; i < mesh.numVertices; i++) { groupVertexIndices[i] = i; } vertexIndexedComponent.addElements(groupVertexIndices); MDoubleArray weights = new MDoubleArray(); uint weightsInfluenceCount = 0; skinCluster.getWeights(meshDagPath, vertexComponent, weights, ref weightsInfluenceCount); //Check if vertices don't have more than 4 influences and normalize weights for (int i = 0; i < mesh.numVertices; i++) { int vertexInfluenceCount = 0; double weightSum = 0; for (int j = 0; j < weightsInfluenceCount; j++) { double weight = weights[(int)(i * weightsInfluenceCount) + j]; if (weight != 0) { vertexInfluenceCount++; weightSum += weight; } } if (vertexInfluenceCount > 4) { MGlobal.displayError("SKNFile:Create - Mesh contains a vertex with more than 4 influences"); throw new Exception("SKNFile:Create - Mesh contains a vertex with more than 4 influences"); } //Normalize weights for (int j = 0; j < weightsInfluenceCount; j++) { weights[(int)(i * influenceCount) + j] /= weightSum; } } List <MIntArray> shaderVertexIndices = new List <MIntArray>(); List <List <SKNVertex> > shaderVertices = new List <List <SKNVertex> >(); List <MIntArray> shaderIndices = new List <MIntArray>(); for (int i = 0; i < shaderCount; i++) { shaderVertexIndices.Add(new MIntArray()); shaderVertices.Add(new List <SKNVertex>()); shaderIndices.Add(new MIntArray()); } MItMeshVertex meshVertexIterator = new MItMeshVertex(meshDagPath); for (meshVertexIterator.reset(); !meshVertexIterator.isDone; meshVertexIterator.next()) { int index = meshVertexIterator.index(); int shader = vertexShaders[index]; if (shader == -1) { MGlobal.displayWarning("SKNFile:Create - Mesh contains a vertex with no shader"); continue; } MPoint pointPosition = meshVertexIterator.position(MSpace.Space.kWorld); Vector3 position = new Vector3((float)pointPosition.x, (float)pointPosition.y, (float)pointPosition.z); MVectorArray normals = new MVectorArray(); MIntArray uvIndices = new MIntArray(); Vector3 normal = new Vector3(); byte[] weightIndices = new byte[4]; float[] vertexWeights = new float[4]; meshVertexIterator.getNormals(normals); //Normalize normals for (int i = 0; i < normals.length; i++) { normal.X += (float)normals[i].x; normal.Y += (float)normals[i].y; normal.Z += (float)normals[i].z; } normal.X /= normals.length; normal.Y /= normals.length; normal.Z /= normals.length; //Get Weight Influences and Weights int weightsFound = 0; for (int j = 0; j < weightsInfluenceCount && weightsFound < 4; j++) { double weight = weights[(int)(index * weightsInfluenceCount) + j]; if (weight != 0) { weightIndices[weightsFound] = (byte)maskInfluenceIndex[j]; vertexWeights[weightsFound] = (float)weight; weightsFound++; } } //Get unique UVs meshVertexIterator.getUVIndices(uvIndices); if (uvIndices.length != 0) { List <int> seen = new List <int>(); for (int j = 0; j < uvIndices.length; j++) { int uvIndex = uvIndices[j]; if (!seen.Contains(uvIndex)) { seen.Add(uvIndex); float u = 0; float v = 0; mesh.getUV(uvIndex, ref u, ref v); SKNVertex vertex = new SKNVertex(position, weightIndices, vertexWeights, normal, new Vector2(u, 1 - v)); vertex.UVIndex = uvIndex; shaderVertices[shader].Add(vertex); shaderVertexIndices[shader].append(index); } } } else { MGlobal.displayError("SKNFile:Create - Mesh contains a vertex with no UVs"); throw new Exception("SKNFile:Create - Mesh contains a vertex with no UVs"); } } //Convert from Maya indices to data indices int currentIndex = 0; MIntArray dataIndices = new MIntArray((uint)mesh.numVertices, -1); for (int i = 0; i < shaderCount; i++) { for (int j = 0; j < shaderVertexIndices[i].length; j++) { int index = shaderVertexIndices[i][j]; if (dataIndices[index] == -1) { dataIndices[index] = currentIndex; shaderVertices[i][j].DataIndex = currentIndex; } else { shaderVertices[i][j].DataIndex = dataIndices[index]; } currentIndex++; } this.Vertices.AddRange(shaderVertices[i]); } MItMeshPolygon polygonIterator = new MItMeshPolygon(meshDagPath); for (polygonIterator.reset(); !polygonIterator.isDone; polygonIterator.next()) { int polygonIndex = (int)polygonIterator.index(); int shaderIndex = polygonShaderIndices[polygonIndex]; MIntArray indices = new MIntArray(); MPointArray points = new MPointArray(); polygonIterator.getTriangles(points, indices); if (polygonIterator.hasUVsProperty) { MIntArray vertices = new MIntArray(); MIntArray newIndices = new MIntArray(indices.length, -1); polygonIterator.getVertices(vertices); for (int i = 0; i < vertices.length; i++) { int dataIndex = dataIndices[vertices[i]]; int uvIndex; polygonIterator.getUVIndex(i, out uvIndex); if (dataIndex == -1 || dataIndex >= this.Vertices.Count) { MGlobal.displayError("SKNFIle:Create - Data Index outside of range"); throw new Exception("SKNFIle:Create - Data Index outside of range"); } for (int j = dataIndex; j < this.Vertices.Count; j++) { if (this.Vertices[j].DataIndex != dataIndex) { MGlobal.displayError("SKNFIle:Create - Can't find corresponding face vertex in data"); throw new Exception("SKNFIle:Create - Can't find corresponding face vertex in data"); } else if (this.Vertices[j].UVIndex == uvIndex) { for (int k = 0; k < indices.length; k++) { if (indices[k] == vertices[i]) { newIndices[k] = j; } } break; } } } for (int i = 0; i < newIndices.length; i++) { shaderIndices[shaderIndex].append(newIndices[i]); } } else { for (int i = 0; i < indices.length; i++) { shaderIndices[shaderIndex].append(dataIndices[indices[i]]); } } } uint startIndex = 0; uint startVertex = 0; for (int i = 0; i < shaderCount; i++) { MPlug shaderPlug = new MFnDependencyNode(shaders[i]).findPlug("surfaceShader"); MPlugArray plugArray = new MPlugArray(); shaderPlug.connectedTo(plugArray, true, false); string name = new MFnDependencyNode(plugArray[0].node).name; uint indexCount = shaderIndices[i].length; uint vertexCount = shaderVertexIndices[i].length; //Copy indices to SKLFile for (int j = 0; j < indexCount; j++) { this.Indices.Add((ushort)shaderIndices[i][j]); } this.Submeshes.Add(new SKNSubmesh(name, startVertex, vertexCount, startIndex, indexCount)); startIndex += indexCount; startVertex += vertexCount; } MGlobal.displayInfo("SKNFile:Create - Created SKN File"); }
public void drawVertices(MDrawRequest request, M3dView view) // // Description: // // Component (vertex) drawing routine // // Arguments: // // request - request to be drawn // view - view to draw into // { MDrawData data = request.drawData(); apiMeshGeom geom = (apiMeshGeom)data.geometry(); if (geom == null) { return; } view.beginGL(); // Query current state so it can be restored // bool lightingWasOn = OpenGL.glIsEnabled(OpenGL.GL_LIGHTING) != 0; if (lightingWasOn) { OpenGL.glDisable(OpenGL.GL_LIGHTING); } float[] lastPointSize = new float[1]; OpenGL.glGetFloatv(OpenGL.GL_POINT_SIZE, lastPointSize); // Set the point size of the vertices // OpenGL.glPointSize(POINT_SIZE); // If there is a component specified by the draw request // then loop over comp (using an MFnComponent class) and draw the // active vertices, otherwise draw all vertices. // MObject comp = request.component; if (!comp.isNull) { MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent(comp); for (int i = 0; i < fnComponent.elementCount; i++) { int index = fnComponent.element(i); OpenGL.glBegin(OpenGL.GL_POINTS); MPoint vertex = geom.vertices[index]; OpenGL.glVertex3f((float)vertex[0], (float)vertex[1], (float)vertex[2]); OpenGL.glEnd(); string annotation = index.ToString(); view.drawText(annotation, vertex); } } else { int vid = 0; for (int i = 0; i < geom.faceCount; i++) { OpenGL.glBegin(OpenGL.GL_POINTS); for (int v = 0; v < geom.face_counts[i]; v++) { MPoint vertex = geom.vertices[geom.face_connects[vid++]]; OpenGL.glVertex3f((float)vertex[0], (float)vertex[1], (float)vertex[2]); } OpenGL.glEnd(); } } // Restore the state // if (lightingWasOn) { OpenGL.glEnable(OpenGL.GL_LIGHTING); } OpenGL.glPointSize(lastPointSize[0]); view.endGL(); }
// // Description // // Transforms the given components. This method is used by // the move, rotate, and scale tools in component mode when the // tweaks for the shape are stored on a separate tweak node. // 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 // handle - handle to the attribute on the tweak node where the // tweaks should be stored // public override void tweakUsing( MMatrix mat, MObjectArray componentList, MVertexCachingMode cachingMode, MPointArray pointCache, MArrayDataHandle handle) { apiMeshGeom geomPtr = meshGeom(); bool savePoints = (cachingMode == MVertexCachingMode.kSavePoints); bool updatePoints = (cachingMode == MVertexCachingMode.kUpdatePoints); MArrayDataBuilder builder = handle.builder(); MPoint delta = new MPoint(); MPoint currPt = new MPoint(); MPoint newPt = new MPoint(); int i=0; uint len = componentList.length; int cacheIndex = 0; uint cacheLen = (null != pointCache) ? pointCache.length : 0; if (cachingMode == MVertexCachingMode.kRestorePoints) { // restore points from the pointCache // if (len > 0) { // traverse the component list // 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 && cacheIndex < cacheLen; idx++, cacheIndex++) { int elemIndex = fnComp.element( idx ); MDataHandle hdl = builder.addElement((uint)elemIndex); double[] pt = hdl.Double3; MPoint cachePt = pointCache[cacheIndex]; pt[0] += cachePt.x; pt[1] += cachePt.y; pt[2] += cachePt.z; hdl.Double3 = pt; } } } else { // if the component list is of zero-length, it indicates that we // should transform the entire surface // len = geomPtr.vertices.length; for ( uint idx = 0; idx < len && idx < cacheLen; ++idx ) { MDataHandle hdl = builder.addElement(idx); double[] pt = hdl.Double3; MPoint cachePt = pointCache[cacheIndex]; pt[0] += cachePt.x; pt[1] += cachePt.y; pt[2] += cachePt.z; hdl.Double3 = pt; } } } else { // Tweak the points. If savePoints is true, also save the tweaks in the // pointCache. If updatePoints is true, add the new tweaks to the existing // data in the pointCache. // if (len > 0) { for ( i=0; i<len; i++ ) { MObject comp = componentList[i]; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( comp ); int elemCount = fnComp.elementCount; if (savePoints) { pointCache.sizeIncrement = (uint)elemCount; } for ( int idx=0; idx<elemCount; idx++ ) { int elemIndex = fnComp.element( idx ); MDataHandle hdl = builder.addElement((uint)elemIndex); double[] pt = hdl.Double3; currPt = newPt = geomPtr.vertices[elemIndex]; newPt.multiplyEqual( mat ); delta.x = newPt.x - currPt.x; delta.y = newPt.y - currPt.y; delta.z = newPt.z - currPt.z; pt[0] += delta.x; pt[1] += delta.y; pt[2] += delta.z; hdl.Double3 = pt; if (savePoints) { // store the points in the pointCache for undo // pointCache.append(delta*(-1.0)); } else if (updatePoints && cacheIndex < cacheLen) { MPoint cachePt = pointCache[cacheIndex]; cachePt[0] -= delta.x; cachePt[1] -= delta.y; cachePt[2] -= delta.z; cacheIndex++; } } } } 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 ) { MDataHandle hdl = builder.addElement((uint)idx); double[] pt = hdl.Double3; currPt = newPt = geomPtr.vertices[idx]; newPt.multiplyEqual( mat ); delta.x = newPt.x - currPt.x; delta.y = newPt.y - currPt.y; delta.z = newPt.z - currPt.z; pt[0] += delta.x; pt[1] += delta.y; pt[2] += delta.z; hdl.Double3 = pt; if (savePoints) { // store the points in the pointCache for undo // pointCache.append(delta*-1.0); } else if (updatePoints && idx < cacheLen) { MPoint cachePt = pointCache[idx]; cachePt[0] -= delta.x; cachePt[1] -= delta.y; cachePt[2] -= delta.z; } } } } // Set the builder into the handle. // handle.set(builder); // Tell Maya the bounding box for this object has changed // and thus "boundingBox()" needs to be called. // childChanged( MChildChanged.kBoundingBoxChanged ); }
public void Load(string name, SKLFile skl = null) { MIntArray polygonIndexCounts = new MIntArray((uint)this.Indices.Count / 3); MIntArray polygonIndices = new MIntArray((uint)this.Indices.Count); MFloatPointArray vertices = new MFloatPointArray((uint)this.Vertices.Count); MFloatArray arrayU = new MFloatArray((uint)this.Vertices.Count); MFloatArray arrayV = new MFloatArray((uint)this.Vertices.Count); MVectorArray normals = new MVectorArray((uint)this.Vertices.Count); MIntArray normalIndices = new MIntArray((uint)this.Vertices.Count); MFnMesh mesh = new MFnMesh(); MDagPath meshDagPath = new MDagPath(); MDGModifier modifier = new MDGModifier(); MFnSet set = new MFnSet(); for (int i = 0; i < this.Indices.Count / 3; i++) { polygonIndexCounts[i] = 3; } for (int i = 0; i < this.Indices.Count; i++) { polygonIndices[i] = this.Indices[i]; } for (int i = 0; i < this.Vertices.Count; i++) { SKNVertex vertex = this.Vertices[i]; vertices[i] = new MFloatPoint(vertex.Position.X, vertex.Position.Y, vertex.Position.Z); arrayU[i] = vertex.UV.X; arrayV[i] = 1 - vertex.UV.Y; normals[i] = new MVector(vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z); normalIndices[i] = i; } //Assign mesh data mesh.create(this.Vertices.Count, this.Indices.Count / 3, vertices, polygonIndexCounts, polygonIndices, arrayU, arrayV, MObject.kNullObj); mesh.setVertexNormals(normals, normalIndices); mesh.getPath(meshDagPath); mesh.assignUVs(polygonIndexCounts, polygonIndices); //Set names mesh.setName(name); MFnTransform transformNode = new MFnTransform(mesh.parent(0)); transformNode.setName("transform_" + name); //Get render partition MGlobal.displayInfo("SKNFile:Load - Searching for Render Partition"); MItDependencyNodes itDependencyNodes = new MItDependencyNodes(MFn.Type.kPartition); MFnPartition renderPartition = new MFnPartition(); bool foundRenderPartition = false; for (; !itDependencyNodes.isDone; itDependencyNodes.next()) { renderPartition.setObject(itDependencyNodes.thisNode); MGlobal.displayInfo("SKNFile:Load - Iterating through partition: " + renderPartition.name + " IsRenderPartition: " + renderPartition.isRenderPartition); if (renderPartition.name == "renderPartition" && renderPartition.isRenderPartition) { MGlobal.displayInfo("SKNFile:Load - Found render partition"); foundRenderPartition = true; break; } } //Create Materials for (int i = 0; i < this.Submeshes.Count; i++) { MFnDependencyNode dependencyNode = new MFnDependencyNode(); MFnLambertShader lambertShader = new MFnLambertShader(); SKNSubmesh submesh = this.Submeshes[i]; MObject shader = lambertShader.create(true); lambertShader.setName(submesh.Name); lambertShader.color = MaterialProvider.GetMayaColor(i); MObject shadingEngine = dependencyNode.create("shadingEngine", submesh.Name + "_SG"); MObject materialInfo = dependencyNode.create("materialInfo", submesh.Name + "_MaterialInfo"); if (foundRenderPartition) { MPlug partitionPlug = new MFnDependencyNode(shadingEngine).findPlug("partition"); MPlug setsPlug = MayaHelper.FindFirstNotConnectedElement(renderPartition.findPlug("sets")); modifier.connect(partitionPlug, setsPlug); } else { MGlobal.displayInfo("SKNFile:Load - Couldn't find Render Partition for mesh: " + name + "." + submesh.Name); } MPlug outColorPlug = lambertShader.findPlug("outColor"); MPlug surfaceShaderPlug = new MFnDependencyNode(shadingEngine).findPlug("surfaceShader"); modifier.connect(outColorPlug, surfaceShaderPlug); MPlug messagePlug = new MFnDependencyNode(shadingEngine).findPlug("message"); MPlug shadingGroupPlug = new MFnDependencyNode(materialInfo).findPlug("shadingGroup"); modifier.connect(messagePlug, shadingGroupPlug); modifier.doIt(); MFnSingleIndexedComponent component = new MFnSingleIndexedComponent(); MObject faceComponent = component.create(MFn.Type.kMeshPolygonComponent); MIntArray groupPolygonIndices = new MIntArray(); uint endIndex = (submesh.StartIndex + submesh.IndexCount) / 3; for (uint j = submesh.StartIndex / 3; j < endIndex; j++) { groupPolygonIndices.append((int)j); } component.addElements(groupPolygonIndices); set.setObject(shadingEngine); set.addMember(meshDagPath, faceComponent); } if (skl == null) { mesh.updateSurface(); } else { MFnSkinCluster skinCluster = new MFnSkinCluster(); MSelectionList jointPathsSelectionList = new MSelectionList(); jointPathsSelectionList.add(meshDagPath); for (int i = 0; i < skl.Influences.Count; i++) { short jointIndex = skl.Influences[i]; SKLJoint joint = skl.Joints[jointIndex]; jointPathsSelectionList.add(skl.JointDagPaths[jointIndex]); MGlobal.displayInfo(string.Format("SKNFile:Load:Bind - Added joint [{0}] {1} to binding selection", joint.ID, joint.Name)); } MGlobal.selectCommand(jointPathsSelectionList); MGlobal.executeCommand("skinCluster -mi 4 -tsb -n skinCluster_" + name); MPlug inMeshPlug = mesh.findPlug("inMesh"); MPlugArray inMeshConnections = new MPlugArray(); inMeshPlug.connectedTo(inMeshConnections, true, false); if (inMeshConnections.length == 0) { MGlobal.displayError("SKNFile:Load:Bind - Failed to find the created Skin Cluster"); throw new Exception("SKNFile:Load:Bind - Failed to find the created Skin Cluster"); } MPlug outputGeometryPlug = inMeshConnections[0]; MDagPathArray influencesDagPaths = new MDagPathArray(); skinCluster.setObject(outputGeometryPlug.node); skinCluster.influenceObjects(influencesDagPaths); MIntArray influenceIndices = new MIntArray((uint)skl.Influences.Count); for (int i = 0; i < skl.Influences.Count; i++) { MDagPath influencePath = skl.JointDagPaths[skl.Influences[i]]; for (int j = 0; j < skl.Influences.Count; j++) { if (influencesDagPaths[j].partialPathName == influencePath.partialPathName) { influenceIndices[i] = j; MGlobal.displayInfo("SKNReader:Load:Bind - Added Influence Joint: " + i + " -> " + j); break; } } } MFnSingleIndexedComponent singleIndexedComponent = new MFnSingleIndexedComponent(); MObject vertexComponent = singleIndexedComponent.create(MFn.Type.kMeshVertComponent); MIntArray groupVertexIndices = new MIntArray((uint)this.Vertices.Count); for (int i = 0; i < this.Vertices.Count; i++) { groupVertexIndices[i] = i; } singleIndexedComponent.addElements(groupVertexIndices); MGlobal.executeCommand(string.Format("setAttr {0}.normalizeWeights 0", skinCluster.name)); MDoubleArray weights = new MDoubleArray((uint)(this.Vertices.Count * skl.Influences.Count)); for (int i = 0; i < this.Vertices.Count; i++) { SKNVertex vertex = this.Vertices[i]; for (int j = 0; j < 4; j++) { double weight = vertex.Weights[j]; int influence = vertex.BoneIndices[j]; if (weight != 0) { weights[(i * skl.Influences.Count) + influence] = weight; } } } skinCluster.setWeights(meshDagPath, vertexComponent, influenceIndices, weights, false); MGlobal.executeCommand(string.Format("setAttr {0}.normalizeWeights 1", skinCluster.name)); MGlobal.executeCommand(string.Format("skinPercent -normalize true {0} {1}", skinCluster.name, mesh.name)); mesh.updateSurface(); } }
// // Description // // Converts the given component values into a selection list of plugs. // This method is used to map components to attributes. // // Arguments // // component - the component to be translated to a plug/attribute // list - a list of plugs representing the passed in component // public override void componentToPlugs(MObject component, MSelectionList list) { if ( component.hasFn(MFn.Type.kSingleIndexedComponent) ) { MFnSingleIndexedComponent fnVtxComp = new MFnSingleIndexedComponent( component ); MObject thisNode = thisMObject(); MPlug plug = new MPlug( thisNode, mControlPoints ); // If this node is connected to a tweak node, reset the // plug to point at the tweak node. // convertToTweakNodePlug(plug); int len = fnVtxComp.elementCount; for ( int i = 0; i < len; i++ ) { plug.selectAncestorLogicalIndex((uint)fnVtxComp.element(i), plug.attribute); list.add(plug); } } }
// Support the move tools normal/u/v mode (components) // public override bool vertexOffsetDirection( MObject component, MVectorArray direction, MVertexOffsetMode mode, bool normalize ) // // Description // // Returns offsets for the given components to be used my the // move tool in normal/u/v mode. // // Arguments // // component - components to calculate offsets for // direction - array of offsets to be filled // mode - the type of offset to be calculated // normalize - specifies whether the offsets should be normalized // // Returns // // true if the offsets could be calculated, false otherwise // { bool offsetOkay = false ; MFnSingleIndexedComponent fnComp = new MFnSingleIndexedComponent( component ); if ( component.apiType != MFn.Type.kMeshVertComponent ) { return false; } offsetOkay = true ; apiMeshGeom geomPtr = meshGeom(); if ( null == geomPtr ) { return false; } // For each vertex add the appropriate offset // int count = fnComp.elementCount; for ( int idx=0; idx<count; idx++ ) { MVector normal = geomPtr.normals[ fnComp.element(idx) ]; if( mode == MVertexOffsetMode.kNormal ) { if( normalize ) normal.normalize() ; direction.append( normal ); } else { // Construct an orthonormal basis from the normal // uAxis, and vAxis are the new vectors. // MVector uAxis = new MVector(); MVector vAxis = new MVector(); uint i, j, k; double a; normal.normalize(); i = 0; a = Math.Abs( normal[0] ); if ( a < Math.Abs(normal[1]) ) { i = 1; a = Math.Abs(normal[1]); } if ( a < Math.Abs(normal[2]) ) { i = 2; } j = (i+1)%3; k = (j+1)%3; a = Math.Sqrt(normal[i]*normal[i] + normal[j]*normal[j]); uAxis[i] = -normal[j]/a; uAxis[j] = normal[i]/a; uAxis[k] = 0.0; vAxis = normal.crossProduct( uAxis ); if ( mode == MVertexOffsetMode.kUTangent || mode == MVertexOffsetMode.kUVNTriad ) { if( normalize ) uAxis.normalize() ; direction.append( uAxis ); } if ( mode == MVertexOffsetMode.kVTangent || mode == MVertexOffsetMode.kUVNTriad ) { if( normalize ) vAxis.normalize() ; direction.append( vAxis ); } if ( mode == MVertexOffsetMode.kUVNTriad ) { if( normalize ) normal.normalize() ; direction.append( normal ); } } } return offsetOkay; }
// // Description: // // Component/attribute matching method. // This method validates component names and indices which are // specified as a string and adds the corresponding component // to the passed in selection list. // // For instance, select commands such as "select shape1.vtx[0:7]" // are validated with this method and the corresponding component // is added to the selection list. // // Arguments // // item - DAG selection item for the object being matched // spec - attribute specification object // list - list to add components to // // Returns // // the result of the match // public override MatchResult matchComponent(MSelectionList item, MAttributeSpecArray spec, MSelectionList list) { MatchResult result = MatchResult.kMatchOk; MAttributeSpec attrSpec = spec[0]; int dim = attrSpec.dimensions; // Look for attributes specifications of the form : // vtx[ index ] // vtx[ lower:upper ] // if ( (1 == spec.length) && (dim > 0) && (attrSpec.name == "vtx") ) { int numVertices = (int)meshGeom().vertices.length; MAttributeIndex attrIndex = attrSpec[0]; int upper = 0; int lower = 0; if ( attrIndex.hasLowerBound ) { attrIndex.getLower( out lower ); } if ( attrIndex.hasUpperBound ) { attrIndex.getUpper( out upper ); } // Check the attribute index range is valid // if ( (lower > upper) || (upper >= numVertices) ) { result = MatchResult.kMatchInvalidAttributeRange; } else { MDagPath path = new MDagPath(); item.getDagPath( 0, path ); MFnSingleIndexedComponent fnVtxComp = new MFnSingleIndexedComponent(); MObject vtxComp = fnVtxComp.create( MFn.Type.kMeshVertComponent ); for ( int i=lower; i<=upper; i++ ) { fnVtxComp.addElement( i ); } list.add( path, vtxComp ); } } else { // Pass this to the parent class return base.matchComponent( item, spec, list ); } return result; }
public override bool updateCompleteVertexGroup( MObject component ) // // Description // Make sure complete vertex group data is up-to-date. // Returns true if the component was updated, false if it was already ok. // // This is used by deformers when deforming the "whole" object and // not just selected components. // { MFnSingleIndexedComponent fnComponent = new MFnSingleIndexedComponent( component ); // Make sure there is non-null geometry and that the component // is "complete". A "complete" component represents every // vertex in the shape. // if ( (null != fGeometry) && (fnComponent.isComplete) ) { int maxVerts ; fnComponent.getCompleteData( out maxVerts ); int numVertices = (int)fGeometry.vertices.length; if ( (numVertices > 0) && (maxVerts != numVertices) ) { // Set the component to be complete, i.e. the elements in // the component will be [0:numVertices-1] // fnComponent.setCompleteData( numVertices ); return true; } } return false; }