Can't get correct points position from reference mesh

python
maya

#1

Hi. I want to create cusrom node that replicate the original mesh partially and that update its point position in real-time if the original mesh changed as well. So here is the code of the custom node:

createCsPoly Command and csPoly node
import sys
import maya.api.OpenMaya as om2

def maya_useNewAPI():
    pass

class csPoly( om2.MPxNode ):

    kPluginNodeName = "csPoly"
    kPluginNodeClassify = "utility/general"
    kPluginNodeId = om2.MTypeId( 0x86027 )

    @staticmethod
    def nodeCreator():
        return csPoly()

    @staticmethod
    def nodeInitializer():

        tAttr = om2.MFnTypedAttribute()
        nAttr = om2.MFnNumericAttribute()
        cAttr = om2.MFnCompoundAttribute()

        csPoly.inMesh = tAttr.create("inMesh", "inm", om2.MFnMeshData.kMesh)
        tAttr.readable = False
        tAttr.keyable = False
        csPoly.addAttribute(csPoly.inMesh)

        csPoly.faceIDs = tAttr.create("faceIDs", "fid", om2.MFnData.kString)
        csPoly.addAttribute(csPoly.faceIDs)

        csPoly.controlPts = nAttr.create("controlPts", "cpt", om2.MFnNumericData.k3Double )
        nAttr.array = True
        csPoly.addAttribute( csPoly.controlPts )

        csPoly.controlVts = nAttr.create("controlVts", "cvt", om2.MFnNumericData.k3Double )
        nAttr.array = True
        csPoly.addAttribute( csPoly.controlVts )

        csPoly.outMesh = tAttr.create("outMesh", "onm", om2.MFnMeshData.kMesh)
        tAttr.writable = True
        tAttr.storable = True
        tAttr.keyable = False
        csPoly.addAttribute(csPoly.outMesh)

        csPoly.attributeAffects( csPoly.inMesh, csPoly.outMesh )
        csPoly.attributeAffects( csPoly.controlPts, csPoly.outMesh )
        csPoly.attributeAffects( csPoly.controlVts, csPoly.outMesh )

    def __init__( self ):
        om2.MPxNode.__init__( self )
        self.collectFlag = 1
        self.faceVertsId = None

    def collectData( self ):
        self.inFaceIDs = om2.MPlug( self.thisMObject(), self.faceIDs ).asString()
        listStrIDs = self.inFaceIDs.split(",")
        listIDs = [ int(x) for x in listStrIDs ]
        self.mFnMeshSrc = om2.MFnMesh( om2.MPlug( self.thisMObject(), self.inMesh ).asMDataHandle().asMesh() )

        outVertConects = [ x for p in listIDs for x in list(self.mFnMeshSrc.getPolygonVertices(p)) ]
        self.faceVertsId = set(outVertConects)
        listSorted = list(set(outVertConects))
        listSequental = range(len(listSorted))
        self.outVertConectsOrdered = [ x + ( listSequental[listSorted.index(x)] - listSorted[listSorted.index(x)] ) for x in outVertConects]
        self.outVertCounts = [ self.mFnMeshSrc.getPolygonVertices(p).__len__() for p in listIDs]

        self.vValues = [ 0.0 ] * len(listIDs)
        self.resultMesh = om2.MFnMeshData().create()
        self.outFnMesh = om2.MFnMesh()
        inMeshPointArray = self.mFnMeshSrc.getPoints(om2.MSpace.kWorld )
        outPoints = [ inMeshPointArray[k] for k in self.faceVertsId ]
        self.outFnMesh.create( outPoints, self.outVertCounts, self.outVertConectsOrdered, self.vValues, self.vValues, self.resultMesh)

    def compute( self, plug, data ):

        pntsInArray = data.inputArrayValue( self.controlPts )
        vrtsInArray = data.inputArrayValue( self.controlVts )
        outMeshPlug = data.outputValue( self.outMesh )

        if self.collectFlag:
            self.collectData()
            self.collectFlag = 0
        elif self.collectFlag == 0:
            self.inMeshPoint = []
            self.resultMeshData = om2.MFnMesh( self.resultMesh )
            for p in xrange(pntsInArray.__len__()):
                pntsInArray.jumpToLogicalElement(p)
                vrtsInArray.jumpToLogicalElement(p)
                pts = pntsInArray.inputValue().asDouble3()
                vts = vrtsInArray.inputValue().asDouble3()
                vec = om2.MVector(pts) + om2.MVector(vts)
                self.inMeshPoint.append( om2.MPoint( vec ) )
            self.resultMeshData.setPoints( self.inMeshPoint, om2.MSpace.kObject  )

        outMeshPlug.setMObject(self.resultMesh)

        data.setClean( self.outMesh )
        pntsInArray.setAllClean()
        outMeshPlug.setClean()

controller_flag_short = "-c"
controller_flag_long = "-controller"
name = "createCsPoly"

class createcsPolyPoly(om2.MPxCommand):
    def __init__(self):
        om2.MPxCommand.__init__(self)
        self.nameCsPoints = "csPoints"
        self.namecsPoly = "csPoly"
        self.csPoints = om2.MObject()
        self.csPoly = om2.MObject()
        self.dgmod = om2.MDGModifier()
        self.dagmod = om2.MDagModifier()
        self.connectedNodes = None
        self.optimized = 1

    def doIt(self, args):

        sel = om2.MGlobal.getActiveSelectionList()
        if sel.length() == 0:
            return

        argData = om2.MArgParser(self.syntax(), args)

        dp = om2.MDagPath()
        comp = om2.MObject()
        dp, comp = sel.getComponent( 0 )
        argData.getObjectStrings()

        if argData.isFlagSet(controller_flag_short):
            self.controller = argData.flagArgumentString(controller_flag_short, 0)

        selLength = sel.length()
        if selLength == 2:
            try:
                mItVtx = om2.MItMeshPolygon( dp, comp )
                parentController = sel.getDagPath( 1 )
                parentCntMobject = sel.getDependNode(1)
                mesh = dp.extendToShape(0)
            except:
                dp, comp = sel.getComponent( 1 )
                mItVtx = om2.MItMeshPolygon( dp, comp )
                parentController = sel.getDagPath( 0 )
                parentCntMobject = sel.getDependNode(0)
                mesh = dp.extendToShape(0)
        else:
            mItVtx = om2.MItMeshPolygon( dp, comp )
            mesh = dp.extendToShape(0)
            selList = om2.MSelectionList()
            selList.add(self.controller)
            parentController = selList.getDagPath(0)
            parentCntMobject = selList.getDependNode(0)

        idx = []
        while not mItVtx.isDone():
            point = mItVtx.index()
            idx.append(int(point))
            mItVtx.next(0)
        componentList = list( sorted( set( idx ) ) )

        if len( componentList ) > 0 and len( str( parentController ) ) > 0:
            outMeshPlig = om2.MFnDependencyNode( mesh.node() ).findPlug( "outMesh", 1 )
            self.connectedNodes = [ x for x in outMeshPlig.connectedTo( 1, 1 ) if self.nameCsPoints in x.name() ]
            csPointsNodes = [ x.node() for x in outMeshPlig.connectedTo( 1, 1 ) if "csPoints" in x.name() ]

            fnTrGeo = om2.MFnDependencyNode()
            fnTrGeo_node = fnTrGeo.create("transformGeometry")

            self.csPoly = self.dgmod.createNode( om2.MTypeId(0x86027 ) )
            fn_Poly_node = om2.MFnDependencyNode( self.csPoly )
            fn_Poly_node.findPlug( "faceIDs", 0 ).setString( (", ".join(str(i) for i in componentList) ) )

            outVertConects = [ x for p in componentList for x in list(om2.MFnMesh(mesh.node()).getPolygonVertices(p)) ]
            sortedOutVerts = list(set(outVertConects))
            for o in xrange(len(sortedOutVerts)):
                meshPnts = om2.MFnDependencyNode( mesh.node() ).findPlug( "pnts", 0 ).elementByLogicalIndex(sortedOutVerts[o])
                polyPoints = fn_Poly_node.findPlug( "controlPts", 0 ).elementByLogicalIndex(o)
                meshVnts = om2.MFnDependencyNode( mesh.node() ).findPlug( "vrts", 0 ).elementByLogicalIndex(sortedOutVerts[o])
                polyVerts = fn_Poly_node.findPlug( "controlVts", 0 ).elementByLogicalIndex(o)
                self.dgmod.connect( meshPnts, polyPoints )
                self.dgmod.connect( meshVnts, polyVerts )

            self.dgmod.connect( outMeshPlig, fn_Poly_node.findPlug( "inMesh", 0 ) )

            objPolyShp = om2.MFnDagNode().create("mesh", "polyCube", parentCntMobject)
            self.dgmod.connect( fn_Poly_node.findPlug( "outMesh", 0 ), om2.MFnDependencyNode(fnTrGeo_node).findPlug( "inputGeometry", 0 ) )
            self.dgmod.connect( om2.MFnDependencyNode(parentCntMobject).findPlug( "worldInverseMatrix", 0 ).elementByLogicalIndex(0), om2.MFnDependencyNode(fnTrGeo_node).findPlug( "transform", 0 ) )
            self.dgmod.connect( om2.MFnDependencyNode(fnTrGeo_node).findPlug( "outputGeometry", 0 ), om2.MFnDependencyNode(objPolyShp).findPlug( "inMesh", 0 ) )
        return self.redoIt()

    def redoIt(self):
        self.clearResult()
        self.dgmod.doIt()
        fn_csPoints_node = om2.MFnDependencyNode(self.csPoints)
        if self.nameCsPoints and self.nameCsPoints != "csPoints#":
            pass
        else:
            name = fn_csPoints_node.name()
            self.setResult(name)

        fn_csPoly_node = om2.MFnDependencyNode(self.csPoly)
        if self.namecsPoly and self.namecsPoly != "csPoly#":
            name2 = fn_csPoly_node.setName(self.namecsPoly)
        else:
            name2 = fn_csPoly_node.name()
        self.setResult(name2)

    def undoIt(self):
        if not self.connectedNodes:
            self.dgmod.undoIt()
        self.dagmod.doIt()

    def isUndoable(self):
        return True

    def hasSyntax(self):
        return True

def creator():
    return createcsPolyPoly()


def syntaxCreator():
    syntax = om2.MSyntax()
    syntax.setObjectType( om2.MSyntax.kStringObjects )
    syntax.addFlag( controller_flag_short, controller_flag_long, om2.MSyntax.kString )
    return syntax


def initializePlugin( mobject ):
    mplugin = om2.MFnPlugin( mobject, "Alex Smirnov", "1.0", "Any" )

    try:
        mplugin.registerCommand( name, creator, syntaxCreator )
    except:
        sys.stderr.write( "Failed to register command: " + name )
        raise

    try:
        mplugin.registerNode( csPoly.kPluginNodeName, csPoly.kPluginNodeId, csPoly.nodeCreator, csPoly.nodeInitializer )
    except:
        sys.stderr.write( "Failed to register node: " + csPoly.kPluginNodeName )
        raise

def uninitializePlugin( mobject ):
    mplugin = om2.MFnPlugin( mobject )

    try:
        mplugin.deregisterCommand( name )
    except:
        sys.stderr.write( "Failed to deregister command: " + name )

    try:
        mplugin.deregisterNode( csPoly.kPluginNodeId )
    except:
        sys.stderr.write( "Failed to deregister node: " + csPoly.kPluginNodeName )
        raise

The main trouble in 90-94 lines, where I can’t get correct poins position
Here is the code that quickly setup the scene, just run in script editor:

Quick setup scene code - creates all nodes automatically
mc.file( new=1, f=1 )
mc.unloadPlugin( 'createCsPoly' )
mc.loadPlugin( 'createCsPoly' )
sphereObj = mc.polySphere()
cir = mc.circle()
mc.delete( sphereObj[0], ch=1 )
mc.select( sphereObj[0] + '.f[10:50]', r=1 )
mc.select( cir[0], add=1 )
mc.createCsPoly()

This node returned very small values of the points positions, however if I repeat it manually, it works ok.

Here is the manual check code:

Points positions qiuick test
mc.file( new=1, f=1 )
sphereObj = mc.polySphere( sx=6,sy=6)
mc.delete( sphereObj[0], ch=1 )

count = mc.polyEvaluate( sphereObj[0], vertex=1 )
shape = mc.listRelatives( sphereObj[0], s=1 )[0]
for x in xrange(count):
    initPos = mc.getAttr( shape + '.vrts[%1.0f]' %x)[0] 
    relPos = mc.getAttr( shape + '.pnts[%1.0f]' %x)[0]
    finPos = initPos[0]+relPos[0], initPos[1]+relPos[1], initPos[2]+relPos[2]
    loc = mc.spaceLocator()
    mc.xform( loc, ws=1, t=finPos)

I know that I should add world matrix to the points positions, but even without that it doesn’t work properly