MFnMesh.getFloatPoints() inconsistent return values?

MFnMesh.getFloatPoints() inconsistent return values?

Anonymous
Not applicable
932 Views
5 Replies
Message 1 of 6

MFnMesh.getFloatPoints() inconsistent return values?

Anonymous
Not applicable
So, I'm seeing some very odd behavior in Maya 2017
(Not sure if this affects other versions, but this is the version I'm testing with)
 
import maya.api.OpenMaya as om
import maya.cmds as cmds
sphere = cmds.polySphere(name="sphere")
compare = cmds.polySphere(name="compare")
cmds.xform("{}.vtx[10]".format(sphere[0]), translation=(1,1,1))
 
selectionList = om.MSelectionList()
selectionList.add(sphere[0])
selectionList.add(compare[0])
sphereDagPath = selectionList.getDagPath(0)
compareDagPath = selectionList.getDagPath(1)
sphereMeshFn = om.MFnMesh(sphereDagPath)
compareMeshFn = om.MFnMesh(compareDagPath)
sphereMeshFn.getFloatPoints()[10].distanceTo(compareMeshFn.getFloatPoints()[10])
 
So, if you enter all the above in the Script Editor, and execute the last line, you'll sometimes get the correct answer: 2.485206365585327, and other times 0.0
So, you can test this by selecting the last line in the Script Editor, and press-and-hold CTRL-ENTER and watching the results go by in the Script Editor.
 
If you select just the  sphereMeshFn.getFloatPoints()[10]part, and press-and-hold CTRL-ENTER, the vertex position will not change.  Similarly, with the compareMeshFn.getFloatPoints()[10])part 
 
If we enter these lines
x = sphereMeshFn.getFloatPoints()[10]
y = compareMeshFn.getFloatPoints()[10]
 
Sometimes, the value of x will change when y is assigned.
 
I really can't comprehend this particular behavior, and it seems like a bug to me.
 
0 Likes
Accepted solutions (1)
933 Views
5 Replies
Replies (5)
Message 2 of 6

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

I think it is a bug and logged in our system on your behalf. I've sent you defect id via email earlier. Please check it out.

 

Yours,

Li

0 Likes
Message 3 of 6

Anonymous
Not applicable

Cheng Xi Li,

Thank you for the prompt response.  I've replied to the e-mail with the defect id with additional information.

Regards,

Nate

0 Likes
Message 4 of 6

Anonymous
Not applicable
Accepted solution

It's part of the documented behaviour of M*Array types in the Maya Python API. A careful reading of this page should help you out. In particular:

 

"Maya's array types do not provide reference counting for individual elements. This means that a Python script which holds a reference to an array element may suddenly find that reference invalid if the corresponding array element is destroyed."

 

When you do this:

x = sphereMeshFn.getFloatPoints()[10]

The following happens:

  1. getFloatPoints() returns an MFloatPointArray.
  2. x is assigned a reference to element 10 of the returned array.
  3. Since there are no longer any references to the MFloatPointArray itself (as opposed to its elements) Python destroys it.
  4. x is now left with a reference to a destroyed object.

To resolve the problem you need to hold a reference to the entire MFloatPointArray so long as you hold references to any of its elements. E.g:

spherePoints = sphereMeshFn.getFloatPoints()
comparePoints = compareMeshFn.getFloatPoints()

x = spherePoints[10];
y = comparePoints[10]
dist = y.distanceTo(x)

x = None

// It's now safe to destroy spherePoints, but we must hang onto comparePoints
// until the reference held by y is destroyed. spherePoints = None

The document I linked to above explains why it works this way. As is the case with most such oddities, the answer is "performance".

An alternative approach is to copy the value of the array element so that you're not left holding a reference to it. E.g:

x = om.MFloatPoint(sphereMeshFn.getPoints()[10])
y = om.MFloatPoint(compareMeshFn.getPoints()[10])
Message 5 of 6

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

Yes, you are right. I totally overlooked referencing mechanism. Thanks for pointing out.

 

Yours,

Li

0 Likes
Message 6 of 6

Anonymous
Not applicable

Hi @Anonymous

Thanks for the in-depth explanation, and reference to the relevant documentation that illustrates the crux of the issue.

I sort of figured something was happening with referencing behind-the-scenes as a performance optimization when dealing with these types.  I suppose it's may not be possible for operations like

x = sphereMeshFn.getFloatPoints()[10]

 to realize that a copy should be made of that reference, without having to explicitly make a copy using the MFloatPoint constructor.

 

 

0 Likes