What is the fastest way of creating a large mesh/object built from smaller mesh “building blocks”

I realize similar questions have been asked before and I followed the advice given there but I hope to gain more insight on the matter here.

I've added a lot of details, I hope it's not too much.

I have information about voxel-based terrain, which I want to put together in a 3D model, basically using different voxel building blocks. The currently fastest version of my script will create 980000 vertices (after removing doubles) in 5 minutes.

The relevant parts of my script look something like this (simplified to focus on relevant parts):

generate_relevant_map_data_from_file()

bm = bmesh.new()
stepsize = 500
col_num = 0

#this part builds a dictionary for the different voxel types with the corresponding
#bmesh and translocation vector
obj_meshes = ["WALL", "FLOOR", "TREE", ...]
mesh_dict = {s: type('bm_ext', (object,), dict(v=Vector((0, 0, 0)), bm=bmesh.new())) for s in obj_meshes}
for k in mesh_dict:
mesh_dict[k].bm.from_object(bpy.data.objects[k], bpy.context.scene)

#this is where all the stuff is generated
for c in columns:
col_num += 1
for t in c:
identificator = t.generate_id()
loc = Vector((t.x * 2, t.y * - 2, t.z * 3))

#this is where I tried to optimize things
#the different attempts are shown and explained below
"""
INSERT CODE HERE
"""

if numBlocks >= stepsize:
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
me = bpy.data.meshes.new("landscape")
bm.to_mesh(me)
ob = bpy.data.objects.new("Land", me)
bm = bmesh.new()
numBlocks = 0
bpy.ops.wm.save_mainfile(filepath=filename)
bpy.ops.wm.open_mainfile(filepath=filename)

#do the same as above to finalize object creation


The fastest version for INSERT CODE HERE I have found so far looks like this:

add_bm = mesh_dict[identificator].bm
mesh_dict[identificator].v = loc
me = bpy.data.meshes.new("temp")
bm.from_mesh(me)


First of all, I noticed that the speed is very dependent on how much memory Blender is using. Even when I just interrupt the script, delete anything it created and restart it, the speed will be similar to when I interrupted it. This is why I reload the .blend file every 500 columns. Is there a better way to do this?

Second: Is there a function to directly copy bmesh data from one to another? Right now I first export to Mesh, and then load from there, which seems really clunky.

If nothing else, it would at least be nice to these 2 things explained/resolved.

Some of my other attempts are described below.

At first, I didn't have the dictionary with the bmeshes and created them new every time:

add_bm = bmesh.new()
me = bpy.data.meshes.new("temp")
bm.from_mesh(me)


It is slightly slower than what I have now, but not by much (286s vs 292s, so maybe it was just chance).

I think this was one of my earliest attempts:

start_vert = len(bm.verts)
bm.from_object(bpy.data.objects[identificator], bpy.context.scene)
bmesh.ops.translate(bm, vec=loc, verts=bm.verts[start_vert:len(bm.verts)])


It already took 58 sec for the first batch of 500 columns, when there is a total of 9000.

I thought, maybe always creating the new meshes was taking a lot of time and I couldn't find a function to copy data directly from one bmesh to another so I tried this:

add_bm = bmesh.new()
vertindex_offset = len(bm.verts)
bm.verts.new(v.co)
bm.edges.new([bm.verts[v.index + vertindex_offset] for v in e.verts])
bm.faces.new([bm.verts[v.index + vertindex_offset] for v in f.verts])


I thought this would be a more low-level approach, but I was obviously very mistaken, because this one also already took 60 seconds for the first batch of 500 columns.

UPDATE: I also tried creating a bunch of linked object copies like this:

copy = bpy.data.objects[identificator].copy()
copy.location = loc


But it was also a lot slower. Additionally, opening the file takes several seconds.

• Is there a specific reason why you need to join those meshes to a single mesh? Using instances should be cheaper. – pink vertex Jul 28 '14 at 11:45
• I was mainly thinking it would be good not to have all the overlapping vertices because a) it's a lot of redundant information and b) I thought it would lead to artifacts at the edges during rendering etc. I just tested point b) though and it doesn't seem to be an issue. By instances, do you mean creating linked copies of the "building block" objects? – ZeitPolizei Jul 28 '14 at 14:32
• Have encountered similar exponential performance drop with large bmesh, it seems the issue do not come from the new() method but from bmesh.ops. – domlysz Jul 7 '16 at 7:49

You might try to use Dupli Verts:

mesh = bpy.data.meshes.new("WorldLocations")
#flat_vertex_coordinates x0, y0, z0, x1, y1, z1, ...
mesh.vertices.foreach_set("co", flat_vertex_coordinates)

duplicator = bpy.data.objects.new("Duplicator", mesh)

• Parent your object to be duplicated:

original = bpy.data.objects[original]
original.parent = duplicator

• Set the duplication type

duplicator.dupli_type = 'VERTS'


Instead of bmesh you might also try Mesh.from_pydata. The source code of this function is located at scripts/modules/bpy_types.py

• the from_pydata works fine, I've posted an answer with more details. – ZeitPolizei Jul 29 '14 at 6:36

pink vertex' idea using from_pydata works, I just wanted to add a few more details.

my code:

add_bm = mesh_dict[identificator].bm
mesh_dict[identificator].v = loc
#until here identical, then I copy the raw data into python lists instead of directly
#into the bmesh
vertindex_offset = len(all_v)

Then outside the main loop I do the mesh.from_pydata(all_v, [], all_f) and create the object etc.
It is essentially the "lowlevel" approach I tried, but apparently the bmesh.verts.new() is pretty slow (I suspect the entire array is copied every time) and there doesn't seem to be a method to add an entire list of verts to a bmesh (yet).