I'm looking to replace list comprehensions like the following with something more efficient and I was wondering if numpy can be used.
[obj.matrix_world @ v.co for v in obj.data.vertices]
I can do this, which is significantly faster, but still lacks the matrix multiplication, that needs to happen for each coordinate.
coords = np.empty((len(obj.data.vertices), 3), 'f')
obj.data.vertices.foreach_get('co', np.reshape(coords, len(obj.data.vertices) * 3))
I was hoping it would just be
np.matrix(obj.matrix_world) @ coords
But that fails with (FWIW, It's just a cube, hence (8, 3))
ValueError: shapes (4,4) and (8,3) not aligned: 4 (dim 1) != 8 (dim 0)
Similarly, doing
for co in coords:
np.matrix(obj.matrix_world) @ co
fails with
ValueError: shapes (4,4) and (3,) not aligned: 4 (dim 1) != 3 (dim 0)
So I've hit a wall now. Numpy can't multiply a 4x4 matrix with a 3d vector, but Blender can. How do I solve this in a numpy way?
edit:
Based on @JoseConseco's excellent reply below, this is what I'm doing now
mx = active.matrix_world
verts = active.data.vertices
vert_count = len(verts)
coords = np.empty((vert_count, 3), 'f')
verts.foreach_get('co', np.reshape(coords, vert_count * 3))
coords_4d = np.ones((vert_count, 4), 'f')
coords_4d[:, :-1] = coords
coords = np.einsum('ij,aj->ai', mx, coords_4d)[:, :-1]
Note, that there's no need to convert the (mathutils) Matrix into an np array. It works fine just like that.
Based on my tests, doing this via numpy is ~3 times faster than the list comprehension.
matrix @ vector
list comprehensions with something more efficient" $\endgroup$