Strategies for performing lots of world coordinate calculations in Blender

I have a lot of calculations I need to do on meshes using global coordinates (distances between vertices, surface areas regions, etc.), and my script is getting slow. I am wondering if there are any useful strategies to avoid having to constantly re-multiply vertex coordinates by matrix_world every time I need to loop over a set of vertices. For example, it would be great if there were an "operate in world coordinates" mode, or a way to convert all local coordinates to their global coordinates.

# loop outline that is performed often
mat1 = ob1.matrix_world
mat2 = ob2.matrix_world
for v1_ind in verts1:
v1 = mat1 * ob1.data.vertices[v1_ind].co
for v2_ind in verts2:
v2 = mat2 * ob2.data.vertices[v2_ind].co
# computations


Further, is a way to use Blender's polygon.area to obtain the area of a face in global coordinates, or do I have to calculate it myself using the global coordinates of each vertex defining the face (slower)?

Thanks!

You could simply apply transformation, scale and rotation to the object before doing vertex calculations. This transforms all vertices to world coordinates (and pretty fast as well!).

bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)


You probably need to copy the object first if you want to keep the old transformations though.

• Thanks Parkuhr. In my case I only ever care about the global coordinates, so this is the best solution for me. – Animik Jan 29 '16 at 11:06

You should cache the result of the inner loop.

verts2 = [mat2 * ob2.data.vertices[v2_ind].co for v2_ind in verts2]


and might do this for the outer loop as well

verts1 = [mat1 * ob1.data.vertices[v1_ind].co for v1_ind in verts1]


Generally you might gain performance by keeping python objects rather than doing an attribute / index lookup each time.

Tested with suzanne subdivided 3 times:

import bpy
import timeit
log = bpy.data.texts['log']
log.clear()

stmt_setup = """
import bpy
obj = bpy.context.active_object
vertices = obj.data.vertices
mat_world = obj.matrix_world
indices = range(len(vertices))"""

stmt_vertex_iter = """
verts_world = [mat_world * v.co for v in vertices]"""

stmt_index_lu = """
verts_world = [mat_world * obj.data.vertices[i].co for i in indices]"""

time_lc = timeit.timeit(stmt=stmt_vertex_iter, setup=stmt_setup, number=100)
time_il = timeit.timeit(stmt=stmt_index_lu,    setup=stmt_setup, number=100)

log.write("Vertex Iterator %.4f \n" % time_lc)
log.write("Index Look Up %.4f \n" % time_il)


yields

Vertex Iterator 2.5746
Index Look Up 4.8094

• Discussion on Blenderartists – pink vertex Jan 24 '16 at 22:10
• Thanks pink vertex, storing the vertices as a python list is undoubtedly the most general solution to this problem. (And I'll vote for your answer as soon as I have enough reputation for the system to allow it...) – Animik Jan 29 '16 at 11:05