Test Results.
Big thanks to @lemon. The original thought behind this question was toward making a grid via numpy as fast as possible.
Test Script to add a grid using numpy, bmesh operator and operator.
For trivial sizes 10 x 10 numpy is well ahead, by 100 x 100 it is well, last. Cursory investigation shows mesh.from_pydata
in script below, is the rate determining step.
Points toward using a hybrid method to create the grid with bmesh
then manipulate later with numpy
using foreach_get
and foreach_set
import bpy
import numpy as np
import bmesh
from time import time
from bpy import context
def to_object(name, me):
ob = bpy.data.objects.new(name, me)
context.collection.objects.link(ob)
return ob
def bmesh_grid(rows, cols):
me = bpy.data.meshes.new("BMGrid")
bm = bmesh.new()
bmesh.ops.create_grid(
bm,
x_segments=cols,
y_segments=rows,
)
bm.to_mesh(me)
def np_grid(rows, cols):
m = np.dstack(
np.meshgrid(
np.linspace(-1, 1, cols),
np.linspace(-1, 1, rows),
)
).reshape(-1, 2)
verts = np.dstack(
[m[:,0],
m[:, 1],
np.zeros(rows * cols)]
).reshape(-1, 3)
# skinning code courtesy of @lemon
first_face = [0, 1, cols + 1, cols]
last_face_index = cols * (rows - 1)
last_face = [i + last_face_index - 1 for i in first_face]
faces = np.linspace(first_face, last_face, last_face_index)
#faces = faces[np.mod(np.arange(last_face_index), cols) > 0]
faces = np.reshape(faces, (rows - 1, cols, 4))
faces = np.delete(faces, cols - 1, 1)
faces = np.reshape(faces, (-1, 4))
me = bpy.data.meshes.new("NPGrid")
#https://developer.blender.org/T90268
me.from_pydata(verts, [], faces)
# pre fix
#me.from_pydata(verts, [], list(faces))
to_object("NPGrid", me)
# test call
rows, cols = 500, 100
t = time()
bmesh_grid(rows, cols)
bm_time = time() - t
print("BM", bm_time)
t = time()
np_grid(rows, cols)
np_time = time() - t
print("NP", np_time)
t = time()
bpy.ops.mesh.primitive_grid_add(
x_subdivisions=cols,
y_subdivisions=rows,
)
op_time = time() - t
print("OP", op_time)
# ugly one liner to remove all add grids
#bpy.data.batch_remove([o for o in bpy.data.objects if any(o.name.startswith(k) for k in ("Grid", "NPGrid", "BMGrid"))])
print(f"{np_time / op_time :.3f}")