top of page

Copy Weights between Asymmetrical Meshes Using Barycentric Coordinates (Maya API)

Updated: Jul 7, 2021

Hey guys,


So I have been using Barycentric Coordinates a lot these days and thought I would use it for something useful that could also help everyone.


We all been in situation where we need to calculate the weight of a point on one mesh from the deformer that is on another mesh, same goes for skinCluster which is a bit more complicated as there are multiple influence. But for now let’s do something about it on a deformer.


For example, in the image below I have a cluster on a sphere and I have weighted these 4 points of a face as they are drawn on the image.



Alright so in the next image of the same sphere there is a locator in the that face.




Consider this locator as a point of another mesh that you need to calculate the weights of using the sphere weights.


So for the start we create our OpenMaya.MSelectionList() and get the dagPaths and MObjects necessary.

import maya.cmds as cmds
import maya.OpenMaya as OpenMaya
 
meshName = "pSphereShape1"
locName = "locatorShape1"
defName = "cluster1"
 
list = OpenMaya.MSelectionList()
list.add(meshName)
list.add(locName)
list.add(defName)
 
meshDag = OpenMaya.MDagPath()
locDag = OpenMaya.MDagPath()
defObj = OpenMaya.MObject()
 
list.getDagPath(0, meshDag)
list.getDagPath(1, locDag)
list.getDependNode(2, defObj)

So that now we have the basic information we need, let’s get our hands dirty and dive into this.

First let’s get weights of the deformer i.e,”cluster1″ in this example.


We create MFnDependencyNode of the cluster so that we can get to the Attribute Plug and extract all the weights per vertex.


defFn = OpenMaya.MFnDependencyNode(defObj)
weightsPlug = defFn.findPlug("weightList") # "cluster1.weightList"
 
for i in xrange(weightsPlug.numElements()):
weightIdxPlug = weightsPlug.elementByPhysicalIndex(i) # "cluster1.weightList[0]"
 
for j in xrange(weightIdxPlug.numChildren()):
weights = weightIdxPlug.child(j) # "cluster1.weightList[0].weights"
 
weightList = {}
 
for i in xrange(weights.numElements()):
val = weights.elementByPhysicalIndex(i).asFloat()
weightList[i] = val

Now that we have weights of each vertex in our dictionary “weightList”, we can start the process to work barycentric coordinates using the position of the locator.


So for this we are going to use MMeshIntersector.closestPoint() API function, as this is faster than MFnMesh.closestPoint() and we get way more information from MMeshIntersector that we need.


# Creating the MMeshIntersector and PointOnMesh
meshIntersector = OpenMaya.MMeshIntersector()
pointInfo = OpenMaya.MPointOnMesh()
 
meshIntersector.create(meshDag.node(), meshDag.exclusiveMatrix())

So now as we have created out MMeshIntersector, lets get the locator’s position as well in our next step.


# Getting the matrix of the locator to get its exact position in world space
mMatrix = locDag.exclusiveMatrix()
locMatrix = OpenMaya.MTransformationMatrix( mMatrix )
locPoint = OpenMaya.MPoint( locMatrix.getTranslation( OpenMaya.MSpace.kWorld ))

Now next, we need to create our MScriptUtil for extracting the u and v coordinates.


uUtil = OpenMaya.MScriptUtil(0.0)
uPtr = uUtil.asFloatPtr()
vUtil = OpenMaya.MScriptUtil(0.0)
vPtr = vUtil.asFloatPtr()
 
dummy = OpenMaya.MScriptUtil()
dummyIntPtr = dummy.asIntPtr()

Alright now let’s get the u and v coords, also from this we will get the face index and triangle index of that corresponding face closest to the position of our locator.


meshIntersector.getClosestPoint(locPoint, pointInfo)
 
pointInfo.getBarycentricCoords(uPtr,vPtr)
u = uUtil.getFloat(uPtr)
v = vUtil.getFloat(vPtr)
w = 1-u-v
 
faceId = pointInfo.faceIndex()
triId = pointInfo.triangleIndex()

For those who don’t understand barycentric coordinates, you can search on wiki or just google it and there are tons of information on it.


Alright so now as we have our face and triangle index let use MItMeshPolygon iterator to get the vertex ids of that triangle.


currentFace = OpenMaya.MItMeshPolygon(meshDag)
 
pointArray = OpenMaya.MPointArray()
vertIdList = OpenMaya.MIntArray()
 
currentFace.setIndex(faceId, dummyIntPtr)
currentFace.getTriangle(triId, pointArray, vertIdList, OpenMaya.MSpace.kWorld )

Now that we got out vertices of the triangle and we have already calculated the weights of these points from before in our dictionary weightList. Let’s use the formula like in the image below and get our value.




P0 = weightList[vertIdList[0]]
P1 = weightList[vertIdList[1]]
P2 = weightList[vertIdList[2]]
 
P = u*P0 + v*P1 + w*P2

And now we have our value in P.


This principle can be used on any deformer using it appropriate attributes and if you like the challenge why not try to do it skinCluster as well.


Feel free to ask questions and share if you found this useful.


Until next time!


Comments


Contact me

so we can create creative & technical projects together
  • Github
  • LinkedIn
  • Instagram
  • Vimeo
  • YouTube
Join my mailing list

Thanks for submitting!

© 2023 by Dilen Shah

bottom of page