Function to create a mesh from a numpy array.
Object gets created, but edges and verts are only shown when I toggle to edit mode and back to object mode.

Small example, run in object mode with Plane selected.

 def write_obj(verts, edges):
    me = bpy.data.meshes.new("new_mesh")
    me.vertices.foreach_set("co", verts.ravel())
    me.edges.foreach_set("vertices", edges.ravel())

    obj = bpy.data.objects.new('new_obj', me)
def read_verts(mesh): #return np.array
    mverts_co = np.zeros((len(mesh.vertices) * 3), dtype=np.float)
    mesh.vertices.foreach_get("co", mverts_co)
    return np.reshape(mverts_co, (len(mesh.vertices), 3))

def read_edges(mesh): #return np.array
    fastedges = np.zeros((len(mesh.edges)*2), dtype=np.int) # [0.0, 0.0] * len(mesh.edges)
    mesh.edges.foreach_get("vertices", fastedges)
    return np.reshape(fastedges, (len(mesh.edges), 2))
active_obj = bpy.context.active_object    
verts = read_verts(active_obj.data)
edges = read_edges(active_obj.data)

write_obj(verts, edges)

What kind of update() am I missing in my function?
mesh.update() doesn't work.

// Okay, foreach_set doesn't seem to have a way to update.
Except toggling between object and edit mode, but that made the script really slow. Originally I wanted to run a time comparison against from_pydata

def write_obj_from_pydata(verts, edges=None):
    if edges is None:
        # join vertices into one uninterrupted chain of edges.
        edges = [[i, i+1] for i in range(len(verts)-1)]
    me = bpy.data.meshes.new("new_mesh")
    me.from_pydata(verts, edges, [])   
    obj = bpy.data.objects.new('new_obj', me)
  • 1
    $\begingroup$ To clarify is the issue running above in edit mode vs object mode? suggest adding a minimal working example eg add a test call to the above for a plane or something simple. $\endgroup$
    – batFINGER
    Commented Aug 10, 2020 at 14:29
  • $\begingroup$ I added an minimal working example. $\endgroup$ Commented Aug 10, 2020 at 18:38
  • 1
    $\begingroup$ Cheers. IIRC this has come up before and something about not being the intended use rings a bell.. The me.from_pydata method is the intended way to go ... with the bonus of being able to also add faces. $\endgroup$
    – batFINGER
    Commented Aug 10, 2020 at 19:15
  • $\begingroup$ Ah, okay. Do you mean? developer.blender.org/T31340 $\endgroup$ Commented Aug 10, 2020 at 20:12

1 Answer 1


Use me.update(calc_edges_loose=True). Make sure you do it after you set the edges though, not before where you currently have me.update().

  • $\begingroup$ That worked! Thank you. The foreach method takes 0.5sec for 1milion random vertices, pydata takes 2secs. $\endgroup$ Commented Aug 11, 2020 at 6:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .