stript performance (Maya vs Max)

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
  11 November 2013
stript performance (Maya vs Max)

i'm moving some of my tools from max to maya and i already met some problems...
here is a test scene and object (poly cube with ~25K verts)
cmds.file(f=1,new=1)
cmds.polyCube(n='pCube1',w=1,h=1,d=1,sx=64,sy=64,s  z=64)


this is python API version to get all vert positions:
def getMeshPoints(meshFn):
	meshFnPoints = OpenMaya.MPointArray()
	meshFn.getPoints(meshFnPoints, OpenMaya.MSpace.kWorld)
	points = []
	for i in xrange(meshFnPoints.length()): points.append([meshFnPoints[i][0], meshFnPoints[i][1], meshFnPoints[i][2]])
	return points

list = OpenMaya.MSelectionList()
list.add('pCube1Shape')
meshPath = OpenMaya.MDagPath()
list.getDagPath(0,meshPath)
meshFn = OpenMaya.MFnMesh(meshPath)
t1 = cmds.timerX()
pp = getPoints(meshPath) 
print cmds.timerX(startTime = t1) 
# 0.24 


it takes 0.24 sec to collect all points. i'm not sure that i can do it faster with a script.
it's not technically very bad, but the same test with using only pure maxscript does do it for ~0.02 sec.
(
	n = box widthsegs:64 lengthsegs:64 heightsegs:64
	m = snapshotasmesh n
	t1 = timestamp()
	for v=1 to m.numverts collect (getvert m v)
	print ((timestamp()-t1)*.001)
)
-- 0.02


this is a 10 times difference. is it an expected performance? does it mean that i have to go with maya c++ API?
 
  11 November 2013
10 time is the dramatic difference for me. it means that my tool looses real-time performance. and the tool makes no sense after that. am i really wasting my time with python or python API...
or there are some tricks to speed it up which i don't know about?

Last edited by denisT : 11 November 2013 at 03:52 PM.
 
  11 November 2013
Why are you converting this to a Python list? Is there a particular reason to not use the native MPointArray that's returned?

If you comment out that portion of your script, it runs very quickly. All of your time is spent extracting the 3 floats from each point and copying them into a Python list. If you were to do the same thing in MaxScript I'd imagine it'd slow down too.

import time
      import maya.OpenMaya as OpenMaya
      
      def getMeshPoints(path):
      	meshFn = OpenMaya.MFnMesh(path)
      	meshFnPoints = OpenMaya.MPointArray()
      	meshFn.getPoints(meshFnPoints, OpenMaya.MSpace.kWorld)
      	return meshFnPoints
      	#points = []
      	#for i in xrange(meshFnPoints.length()): points.append([meshFnPoints[i][0], meshFnPoints[i][1], meshFnPoints[i][2]])
      	#return points
      
      list = OpenMaya.MSelectionList()
      list.add('pCube1Shape')
      meshPath = OpenMaya.MDagPath()
      list.getDagPath(0,meshPath)
      start = time.clock()
      pp = getMeshPoints(meshPath) 
      end = time.clock()
      print end-start
     # 0.00456523622086

Last edited by Keilun : 11 November 2013 at 04:26 PM.
 
  11 November 2013
Originally Posted by Keilun: Why are you converting this to a Python list? Is there a particular reason to not use the native MPointArray that's returned?

i knew it and did it in purpose.
Quote: If you comment out that portion of your script, it runs very quickly. All of your time is spent extracting the 3 floats from each point and copying them into a Python list. If you were to do the same thing in MaxScript I'd imagine it'd slow down too.

in max i put all points in mxs array to make the test fair.

the thing that have to avoid is probably do any API to native python type conversion if it's possible. but anyway as i said i'm enjoying the script+API very much.
 
  11 November 2013
let's remove the appending to the list, but keep taking a data... for ... let me say... export, or get an average, or calculate a bounding box (i'm sure there are API methods for it, but it's a sample)
def getPoints(meshPath):
 	meshFnPoints = OpenMaya.MPointArray()
 	meshFn = OpenMaya.MFnMesh(meshPath)
 	meshFn.getPoints(meshFnPoints, OpenMaya.MSpace.kWorld)
 	for i in xrange(meshFnPoints.length()): 
 		meshFnPoints[i][0]
 		meshFnPoints[i][1]
 		meshFnPoints[i][2]
 	return points
 
 list = OpenMaya.MSelectionList()
 list.add('pCube1Shape')
 meshPath = OpenMaya.MDagPath()
 list.getDagPath(0,meshPath)
 meshFn = OpenMaya.MFnMesh(meshPath)
 t1 = cmds.timerX()
 pp = getPoints(meshPath) 
 print cmds.timerX(startTime = t1)
 # 0.22
 

Last edited by denisT : 11 November 2013 at 05:24 PM.
 
  11 November 2013
So one of the issues with the Python API 1.0 implementation is its basis on Swig which although automatic doesn't always make the most efficient conversion.

You can instead explore the Python API 2.0 if you're looking for something more performance critical. There are cases (this one included) where performance is up to 10x as fast as Python API 1.0.

The only caveat here is that since everything for Python API 2.0 was handcoded, not all C++ API classes have Python API 2.0 representations and you cannot interchange the two APIs. They cannot interpret each others objects. You can run them side by side however as long as they aren't trying to read objects from the other API.

For this case however, MFnMesh is supported as are the classes involved in this sample. You can read more about support here:

http://docs.autodesk.com/MAYAUL/201...-api/index.html

Here's the example converted to Python API 2.0:

import time
   import maya.api.OpenMaya as OpenMaya
   
   def getMeshPoints(path):
   	meshFn = OpenMaya.MFnMesh(path)
   	meshFnPoints = meshFn.getPoints(OpenMaya.MSpace.kWorld)
   	points = []
   	for i in xrange(len(meshFnPoints)): points.append([meshFnPoints[i][0], meshFnPoints[i][1], meshFnPoints[i][2]])
   	return points
   
   list = OpenMaya.MSelectionList()
   list.add('pCube1Shape')
   meshPath = list.getDagPath(0)
   start = time.clock()
   pp = getMeshPoints(meshPath) 
   end = time.clock()
   print end-start
   # 0.0197645971875
 
  11 November 2013
thanks a lot Keilun for you guiding. python API 2.0 is the thing what i'm exploring now.
 
  11 November 2013
cmds.polyCube(n='pCube1',w=1,h=1,d=1,sx=64,sy=64,s  z=64)

import maya.api.OpenMaya as api
def getMeshPoints(mesh, space = api.MSpace.kWorld):
	meshFn = api.MFnMesh(mesh)
	points = meshFn.getPoints(space)
	for i in xrange(len(points)):
		points[i][0]
		points[i][1]
		points[i][2]
	return points
	
import maya.OpenMaya as OpenMaya
def getPoints( mesh, space = OpenMaya.MSpace.kWorld):
	points = OpenMaya.MPointArray()
	meshFn = OpenMaya.MFnMesh(mesh)
	meshFn.getPoints(points,space)
	for i in xrange(points.length()):
		points[i][0]
		points[i][1]
		points[i][2]
	return points	 

list = api.MSelectionList()
list.add('pCube1Shape')
mesh = list.getDagPath(0)
t1 = cmds.timerX()
pp = getMeshPoints(mesh) 
print cmds.timerX(startTime = t1) 
# 0.01


list = OpenMaya.MSelectionList()
list.add('pCube1Shape')
meshPath = OpenMaya.MDagPath()
list.getDagPath(0,meshPath)
t1 = cmds.timerX()
pp = getPoints(meshPath) 
print cmds.timerX(startTime = t1) 
# 0.18


the big difference 0.01 vs 0.18... i can work with it now... unfortunately there is a blocker. it seems like there is no OpenMayaAnim in 2.0 :(
 
  11 November 2013
Dont know if it helps you with your python approach but if using the API i recognised that the MFnMesh.getPoints() method is damn slow compared with multiplying the raw points with the transforms world matrix. Here an example, maybe you can translate it efficiently into python:
MDagPath dagPath = MDagPath::getAPathTo( mesh ); // mesh: the MObject
MFnMesh meshFn(dagPath);

const unsigned int numVertices = meshFn.numVertices();
MMatrix matrix = dagPath.exclusiveMatrix();
double mtx[16];
for(unsigned int m=0; m<=3; m++){
	double* ptr = matrix[m];
	for(unsigned int n=0; n<=3; n++){
		mtx[m * 4 + n] = ptr[n];
	};
};
const float* rawPts = meshFn.getRawPoints(&stat);
float x, y, z;
MFloatPointArray fPts(numVertices);
for(unsigned int k=0; k<numVertices; ++k)
{
	x = *rawPts;
	++rawPts;
	y = *rawPts;
	++rawPts;
	z = *rawPts;
	++rawPts;
	fPts[k].x = float(x * mtx[0] + y * mtx[4] + z * mtx[8] + mtx[12]);
	fPts[k].y = float(x * mtx[1] + y * mtx[5] + z * mtx[9] + mtx[13]);
	fPts[k].z = float(x * mtx[2] + y * mtx[6] + z * mtx[10] + mtx[14]);
};
 
  11 November 2013
thank you so much. i will dig into it for sure. i'm absolutelly sure that this maya community knows a lot of tricks which can make an impossible to be possible. if you would need any help with MAX you will be welcome on the MAX branch on this forum. most of my 6K whists were made there
 
  11 November 2013
Originally Posted by zaskar: Dont know if it helps you with your python approach but if using the API i recognised that the MFnMesh.getPoints() method is damn slow compared with multiplying the raw points with the transforms world matrix.

i have no idea what the raw points is yet. but i will.
interesting... according to the documentation
MStatus getPoints (MFloatPointArray &vertexArray, MSpace::Space space=MSpace::kObject) const 

they make this array on the fly... but what can be easier than just multiply a point and a matrix?
 
  11 November 2013
Python is not exactly designed (especially the pythonic api) to work with this kind of / amount of data. You really should look into the C++ api.
 
  11 November 2013
Thread automatically closed

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
__________________
CGTalk Policy/Legalities
Note that as CGTalk Members, you agree to the terms and conditions of using this website.
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 12:01 PM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.