Different ways to create mesh objects

Hello there,
I am a bit lost with the ways to create mesh objects with the new API (2.5x).
I know well the old API for Blender 2.4x, with Mesh or NMesh (Mesh better, NMesh faster).
The new API is seem to be easy to understand, but it is not well documented (with short example like the old API).
But no worry, the new API rock’s.

I found many way to create a simple mesh in 2.5x (2.56a), but I don’t know that they are differences between them (like performance or better initialisation).
I found at least four way to create a mesh :

  • by appending a face:
    me.faces.append(face)
  • by direct method
    me.from_pydata(vertexCoords,edgesList,faceList)
  • by loops technique (two ways):
    me.faces.foreach_set(“vertices_raw”,unpack_face_list([f[0] for f in faces]))
    or
    me.faces[i].vertices = vertsIndex

I think to create mesh from scratch, loopings techniques are the right way ?
Perso I use the second loop technique, but it does not appear to work.

Any idea about what is wrong ?

 
import bpy
 
nbVerts=8
vertsData=[1,-1,-1, 1,-1,1, -1,-1,1 ,-1,-1,-1 ,1,1,-1 ,1,1,1 ,-1,1,1 ,-1,1,-1]
nbEdges=13
edgesData=[0,1,0 ,1,2,0 ,2,3,0 ,3,7,0 ,4,7,0 ,5,6,0 ,6,7,0 ,0,3,0 ,4,5,0 ,1,5,0 ,2,6,0 ,0,4,0 ,1,4,0]
nbFaces=5
facesData=[(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7,3),(4,0,3,7)]
 
scn = bpy.data.scenes[0]
mesh = bpy.data.meshes.new('test')
 
mesh.vertices.add(nbVerts)
for i in range(nbVerts):
    mesh.vertices[i].co = (vertsData[i*3],vertsData[i*3+1],vertsData[i*3+2])
 
mesh.edges.add(nbEdges)
for i in range(nbEdges):
    mesh.edges[i].vertices = [edgesData[i*3],edgesData[i*3+1]]
 
mesh.faces.add(nbFaces)
for i in range(len(facesData)):
    mesh.faces[i].vertices = facesData[i]
 
obj = bpy.data.objects.new("test",mesh)
scn.objects.link(obj)

This way crash Blender.

import bpy
 
vertsData=[(1,-1,-1),(1,-1,1),(-1,-1,1),(-1,-1,-1),(1,1,-1),(1,1,1),(-1,1,1),(-1,1,-1)]
edgesData=[(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(0,7),(0,8)] # for example
facesData=[(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7,3),(4,0,3,7)]
 
# create new mesh structure
mesh = bpy.data.meshes.new("myMesh_mesh")
mesh.from_pydata(vertsData, edgesData, facesData)
mesh.update()

new_object = bpy.data.objects.new("myMesh_object", mesh)
new_object.data = mesh

scene = bpy.context.scene
scene.objects.link(new_object)
scene.objects.active = new_object
new_object.select = True

or


import bpy

vertsData=[(1,-1,-1),(1,-1,1),(-1,-1,1),(-1,-1,-1),(1,1,-1),(1,1,1),(-1,1,1),(-1,1,-1)]
facesData=[(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7,3),(4,0,3,7)]
 
# create new mesh structure
mesh = bpy.data.meshes.new("myMesh_mesh")
mesh.from_pydata(vertsData, [], facesData)  
mesh.update()

new_object = bpy.data.objects.new("myMesh_object", mesh)
new_object.data = mesh

scene = bpy.context.scene
scene.objects.link(new_object)
scene.objects.active = new_object
new_object.select = True

i guess you mentioned from_pydata, i hadn’t seen it when i wrote the reply.

there is another way to modify an existing mesh which is not done with theses commands

you can also add primitives like cube sphere circle ect
which are not shown here!

looks like there is a face missing on the cube!

and there might be another way of making mesh later on when they have time to work on it !

happy 2.5

Thx for reply,

to zeffii:
right I have mentionned this technique (the direct method). USefull and fast, but we have to known all of the geometry before use it (and store all of it in memory).

to RickyBlender:
right, I forgot the way with primitive and all bpy.ops

For now I work on a script to load object at the startup of blender (I use the option ‘register’), but we cannot acces to the context, it return always None…

So my script in the first post dont work only for face appending but I dont know why ?
(I have voluntarily remove some face on this cube :slight_smile:

Your original script crashes Blender because those vertices, edges and faces arrays need to start with a count of the number of items—you cannot simply append new items to them incrementally. The from_pydata call seems to be the preferred way of building a mesh, even though it’s still not properly documented. It knows how to handle the peculiarities of building the vertices, edges and faces arrays.

Note the right way to call from_pydata: either specify edges or faces, but not both (pass an empty list for the other one). Also, you can only use this call once on a mesh. Using it wrongly can crash Blender.

I dont understand what you have wrote ?

Two examples:
the first with me.faces.vertices

import bpy
 
vertsData=[(1,-1,-1), (1,-1,1),(-1,-1,1),(-1,-1,-1),(1,1,-1),(1,1,1),(-1,1,1),(-1,1,-1)]
nbVerts=len(vertsData)
edgesData=[(0,1),(1,2),(2,3),(3,7),(4,7),(5,6),(6,7),(0,3),(4,5),(1,5),(2,6),(0,4),(1,4)]
nbEdges=len(edgesData)
facesData=[(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7,3),(4,0,3,7)]
nbFaces=len(facesData)
 
scn = bpy.data.scenes[0]
mesh = bpy.data.meshes.new('test')
 
mesh.vertices.add(nbVerts)
for i in range(nbVerts):
    mesh.vertices<i>.co = vertsData[i]
 
mesh.edges.add(nbEdges)
for i in range(nbEdges):
    mesh.edges[i].vertices = edgesData[i]
 
mesh.faces.add(nbFaces)
for i in range(len(facesData)):
    mesh.faces[i].vertices = facesData[i]
 
obj = bpy.data.objects.new("test",mesh)
scn.objects.link(obj)

The second with [I]mesh.from_pydata()


import bpy
vertsData=[(1,-1,-1), (1,-1,1),(-1,-1,1),(-1,-1,-1),(1,1,-1),(1,1,1),(-1,1,1),(-1,1,-1)]
nbVerts=len(vertsData)
edgesData=[(0,1),(1,2),(2,3),(3,7),(4,7),(5,6),(6,7),(0,3),(4,5),(1,5),(2,6),(0,4),(1,4)]
nbEdges=len(edgesData)
facesData=[(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7,3),(4,0,3,7)]
nbFaces=len(facesData)
scn = bpy.data.scenes[0]
mesh = bpy.data.meshes.new('test')
mesh.from_pydata(vertsData,edgesData,facesData)
obj = bpy.data.objects.new("test",mesh)
scn.objects.link(obj)

In this case
mesh.from_pydata(vertsData,edgesData,facesData) work fine.
Same for the first script except faces

hi stun,

with quads you should use vertices_raw instead of vertices. so assigning verts to faces becomes:


mesh.faces.add(nbFaces)
for i in range(len(facesData)):
    mesh.faces[i].vertices_raw = facesData[i]

hope that helps

Thanks you very much dreampainter, it helps me a lot.
But for to create a mesh with quadrangles and triangles, the both (‘vertices_raw’ and ‘vertices’) dont work ?!
Any idea ?

 
import bpy
 
vertsData=[(1,-1,-1), (1,-1,1),(-1,-1,1),(-1,-1,-1),(1,1,-1),(1,1,1),(-1,1,1),(-1,1,-1)]
nbVerts=len(vertsData)
edgesData=[(0,1),(1,2),(2,3),(3,7),(4,7),(5,6),(6,7),(0,3),(4,5),(1,5),(2,6),(0,4),(1,4)]
nbEdges=len(edgesData)
facesData=[(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7),(4,0,3),]
nbFaces=len(facesData)
 
scn = bpy.data.scenes[0]
mesh = bpy.data.meshes.new('test')
 
mesh.vertices.add(nbVerts)
for i in range(nbVerts):
mesh.vertices[i].co = vertsData[i]
 
mesh.edges.add(nbEdges)
for i in range(nbEdges):
mesh.edges[i].vertices = edgesData[i]
 
mesh.faces.add(nbFaces)
for i in range(len(facesData)):
mesh.faces[i].vertices_raw = facesData[i]
#mesh.faces[i].vertices = facesData[i]
 
obj = bpy.data.objects.new("test",mesh)
scn.objects.link(obj)

use the vertices_raw and you’ll have to rework the list of tri’s

the for_each function expects 4 verts for every face, so just add the first vert for every tri to the end:


yours = [(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7),(4,0,3),]
new = [(0,1,2,3),(4,7,6,5),(1,5,6,2),(2,6,7,2),(4,0,3,4),]

from pydata does this automatically. i usually write a function to do this:


def prepFaceDataFast(faces):
    return [i*(len(i)==4) + (i+(i[0],))*(len(i)==3) for i in a]

def prepFaceDataSimple(faces):
    result = []
    for i in faces:
        if len(i)==3:result.append(i+(i[0],))
        else: result.append(i)
    return result

both functions do the same, simply adding the first vertice to each 3-long face, but the first function is just very fast.

if you also want to have n-gons in your mesh, youll have to process them to clip each to a number of faces. its done in my regular solids script (add mesh:regular solids, available in blender) so have a look there

hope that helped

hope that helped

Definitively yes :yes:

Thank you very much.

I’m using from_pydata(verts, edges, faces) to build a mesh in a script I’m writing. For some reason, it doesn’t handle the faces very well and it creates extra edges which criss cross some of the quads. The mesh data is going to include quads and tri’s since the geometry is the result of a cut but the behavior happens when it’s just quads as well. Does the face data have to list the verts in order?

Hello patmo141,

Does the face data have to list the verts in order?

Yes the faces need to be build in a certain order with vertex data.
You need to use a counterwise order to point the normal is the right direction.
Example:

 
1---&gt;2
|    |
|    |
4&lt;---3

Blender create edges automatically with faces, so you can just use from_pydata(vertex,[],faces)

do you have the final examples scripts!

would be nice to see theses work nicely !

another problem you may encounter is that if the vertex order is not right
you may end up with criss crossing edges in middle of quad face which is not nice!

Thanks happy 2.5

great! It’s good to know what the problem is

greeeeeeeat…now I have to figure out how to intuitively define my faces correctly. Sigh