[Closed] Fastest way to get all vertices in float array?
I need to get the XYZ data of all vertices of a mesh into a simple array that only contains float values.
Right now, I am doing this (s is the Editable Mesh)
v = #()
v[s.numVerts*3] = 0
c = 1
for i = 1 to s.numVerts do (
p = getVert s i
v[c] = p.x
v[c+1] = p.y
v[c+2] = p.z
c+=3
)
but that’s still somewhat slow. For a 64seg teapot (131330 verts), for example, it takes about one second. I also tried using append() but get the same speed.
Does anyone have a better idea on how to build such an array?
Thanks!
– MartinB
I don’t think there is a better way.
It would be good to know a bit more about the performance bottlenecks, so I timed some variations of your code:
*For loop without actually getting the vertex into p and adding to the array: 110 ms.
*For loop with getting the vertex into p but not writing to the array: 312 ms.
*For loop with getting the vertex into p but writing as Point3 to the array and incrementing by 1: 640ms. Thus the overhead of writing one value to the array is 640-312 = 328 ms or around 300 ms per write.
*For loop with getting the vertex into p but outputting only X and Y to array: 828 ms.
*Original code: 1125 ms.
From the above code it seems that the for loop itself takes 110 ms, with getting and storing the values 312+3*300 = 1212 ms. So this estimate is very close to the actually measured time.
Unless you find a way to live with Point3 values in the array, I don’t think there is a faster way to get the values into memory. But of course I could be wrong.
(I tried some esoteric tricks and they were all slower, some 2x slower, some orders of magnitude slower.)
yea theres no way (that i could discover ) faster than this i mean even the .3ds exporter is slow, infact it wont save if the number of segments in teapot is more than 32 :S “teapot has too many faces, more than 64K” but then again the exporter has to save not only the verts i think but also the face vertice numbers the texture coords and other data.
I tried your script 3 runs and got:
_828 ms
_860 ms
_844 ms
but with gc light:true
_688 ms
_672 ms
_688 ms
and this:
(
gc light:true
local ru = #()
local p
-- ru.count = $.verts.count*3
st = timestamp()
for s in 1 to $.verts.count do
(
p = getVert $ s
-- ru [s] = p[1]
-- ru [s+1] = p[2]
-- ru [s+2] = p[3]
append ru p[1]
append ru p[2]
append ru p[3]
)
timestamp()-st
)
547 ms
531 ms
547 ms
the loop alone last 47 ms
and getting the vert, but not appending it to the array last 266 ms
First, the measurement depends on the machine’s speed.
Second, you cannot measure the time AFTER the gc(), you HAVE TO include the gc light:true in the measurement because depending on how much memory had to be reclaimed, that could ADD up to several seconds to the execution time.
Also, the first time I run the script, it takes up to 30 seconds due to automatic Heap increases. Once there is enough memory, it gets faster again…
yes thank you Bobo, your right, I noticed only a very minimal benefit using gc,
edit: doing some more test, in fact I don’t see a benefit with it
I did 3 runs :
_828 ms
_860 ms
_844 ms
just to show the difference in machines(a starting point), to compare, and not to show a benefit.
I increased the heap size to get a relative accurate measure from the start
and append is definitely faster
Thanks very much for taking the time to look into this!
One way to speed this up (I guess) would be to get all vertex positions at once instead of one by one in a loop, so I looked into the VertexSelection value generated by mesh.verts, since the online help says for these:
“A VertexSelection represents a set of vertices for a scene mesh node as a virtual array. As such, you can access a vertex by index, iterate over the vertices, and apply mapped functions to the vertices. See also Editable_Mesh. The VertexSelection array is dynamic, i.e., its contents will change as the vertices or selected vertices of the mesh node change. VertexSelection values are mappable.”
Unfortunately, I had no success so far to create a mappable function that operates on a VertexSelection (only node collections) – anyone got an idea?
In theory, the VertexSelection class is derived from the Collection class, which is mappable, but I cannot get it to work. Could that be a bug in the documentation or MAXScript itself, or am I missing something?
I am slowly considering writing a MAXScript C++ plugin just for this – get all verts off an editable mesh and return a 1D array of floats with the coordinates. Can’t be that hard, can it?
– MartinB
vertexselection is a collection of vertices. Every vertex has #index and #pos properties. You can’t easy convert vertexCollection to array of vertex positions. Get vert #pos property works slower then getVert method. So you can’t get any benefits using vertexCollection.
with max SDK and c++ you can get any mesh data much-much faster and save memory. That’s a reason why all serious exporters are written in c++ (SDK)
That would have been my next suggestion too.
If you want it to be faster than a second, MAXScript is the wrong approach.
If you can live with 1 second access time, then it is all ok…