Multiple meshes not welded with pydata For an addon, I want to transform the mesh of an object into multiple meshes to create an array using from_pydata. My problem is that the vertices of the meshes are not welded in the final object :


Could you tell me what i do wrong ? Why the vertices are not welded, is this a normal behaviour ?

You can try the script on a startup file with a 'Cube' :

import bpy
import bmesh

vertices = []
face = []
verts = []
edges = []
faces = []
numface = 0
nbcol = 2
nbrow = 2
scale_x = 1
scale_y = 1

#--Gap between each row / column
gapx = 1.2
gapy = 1.2

#--Width of each row / column   
widthx = 1 * scale_x
widthy = 1 * scale_y

#--Compute the corners so the new object will be always at the center
left = -((widthx * (nbcol-1)) + (gapx * (nbcol-1)) ) / 2
right = left + widthx
start = -((widthy * (nbrow-1)) + (gapy * (nbrow-1))) / 2
end = start + widthy

#---Get the data from the object
brush = bpy.data.objects["Cube"]
obj = bpy.context.selected_objects[0]
obverts = brush.data.vertices
obfaces = brush.data.polygons

for vertex in obverts:
    vertices.append(tuple(vertex.co))
for f in obfaces:
    face.append(tuple(f.vertices))

for x in range(nbcol):
#---Create Verts, Faces on X axis
    for f in face:
        for i in range (0, len(f)):
            verts.extend([(vertices[f[i]][0]-left, vertices[f[i]][1]-start, vertices[f[i]][2])])    
        faces.append([r for r in range(numface,numface+len(f))])    
        numface += len(f)
    start2 = end + gapy
    end2 = start2 + widthy

    for y in range(nbrow-1):
    #---Create Verts, Faces on Y axis
        for f in face:
            for i in range (0, len(f)):
                verts.extend([(vertices[f[i]][0]-left, vertices[f[i]][1]-start2, vertices[f[i]][2])])   
            faces.append([r for r in range(numface,numface+len(f))])
            numface += len(f)
        start2 = end2 + gapy
        end2 = start2 + widthy

    left = right + gapx
    right = left + widthx

#---Update the mesh
# Create mesh data      
mymesh = bpy.data.meshes.new("Cube")
# Generate mesh data
mymesh.from_pydata(verts, edges, faces)
# Calculate the edges
mymesh.update(calc_edges=True)
# Update data
obj.data = mymesh
# Make the the object the active one to remove double
bpy.context.scene.objects.active = obj


Thanks a lot for your help.
C.
You end up with a lot of doubles (ie verts in same location) from your logic of running thru faces.  Remember on the cube each vert is shared by 3 faces.  Hence you end up with 4 x 3 x 8 (96) verts for four cubes, instead of 4 x 8 (32) vertices.

If you ran the the remove doubles operator on your mesh it would "weld" it.

Here is another take on this, using the list comprehension methods here https://blender.stackexchange.com/a/54130/15543 and then extending and offsetting for each row, col with gap for the vertices coordinates list, and incrementing the face vert index by the number of verts in the "brush" object for each copy.

import bpy
from mathutils import Vector
context = bpy.context
cube = context.object
mesh = cube.data
rows, cols = 5, 7
scale_x, scale_y = 1, 1
#--Gap between each row / column
gapx, gapy = 0.2, 0.2
#--Width of each row / column   
widthx, widthy = cube.dimensions.x * scale_x, cube.dimensions.y * scale_y
verts = []
faces = []
lenverts = len(mesh.vertices)
# make the 
for i in range(rows * cols):
    row = i % rows
    col = i // rows 
    # vector math
    verts.extend([v.co + Vector((col * (widthx + gapx), row * (widthy + gapy), 0.0))
             for v in mesh.vertices])
    faces.extend([[v + i * lenverts for v in p.vertices] for p in mesh.polygons])

# new mesh
mymesh = bpy.data.meshes.new("mymesh")        
mymesh.from_pydata(vertices=verts, edges=[], faces=faces)
obj = bpy.data.objects.new("foobar", mymesh)
context.scene.objects.link(obj)


You may want to adjust the vector math depending on where you want the origin to be.