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
    Aug 10, 2020 at 14:29
  • $\begingroup$ I added an minimal working example. $\endgroup$ 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
    Aug 10, 2020 at 19:15
  • $\begingroup$ Ah, okay. Do you mean? developer.blender.org/T31340 $\endgroup$ 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$ Aug 11, 2020 at 6:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.