I have an array that is called ccValids, which contains "good" center coordinates for the cylinders I want to create. These cylinders are created as follows:

for c in ccValids:
    leafs = bpy.ops.mesh.primitive_cylinder_add( location = c, enter_editmode = True )

bm = bmesh.new()

It appears that the cylinders are created as one object, which is very good since there is a great number of them and they are all supposed to be manipulated by the exact same operations. However the bmesh.new() command does not work.

The error I get is "Expected 'Mesh' found 'set' instead". Is there a way to use bmesh methods on my nicely gathered cylinders though?


Firstly the issue and error with your code.

Operators only return a python set containing the status of the operation, for example {'FINISHED'} if finished normally, or {'CANCELLED'} if there was a problem.

On looping a primitive add operator, the object will be context.object the mesh context.object.data on each iteration. If run in edit mode, (enter_editmode takes you into edit mode on first iteration) then all will be added to the edit objects mesh. This is why you have one object.

Secondly, I'd probably use the bmesh create cone operator as pointed out in answer by @TLousky, for completeness here is a way to put the created cylinders into a "live" bmesh, that is a bmesh from the edit objects edit mesh. To demonstrate, I've put in code to select the ngon caps of the cylinders.

import bpy
import bmesh
context = bpy.context
ccValids = [(1, 1, 1), (2, 2, 2)]
for c in ccValids:
    leafs = bpy.ops.mesh.primitive_cylinder_add( location = c, enter_editmode = True )
# we will now be in edit mode
bm = bmesh.from_edit_mesh(context.edit_object.data)
# deselect all but ngon faces
for f in bm.faces:
    f.select = len(f.verts) > 4

enter image description here Result. Still in edit mode, cylinder ngon caps selected.

When you've finished operations, a bmesh.update_edit_mesh(context.object.data) will update the edit mesh.


You need to create cylinders with bmesh's create cone operator, then create a mesh, an object and link the object to the scene:

import bpy, bmesh

# Imports used to demo code since I don't really have ccValids
from random import randint
from mathutils import Vector, Matrix

# Generate 5 random centers for our cylinders
ccValids = [ Vector([ randint(-5,5) for axis in 'xyz' ]) for i in range(5) ]

bm = bmesh.new()
for c in ccValids:
    # Create a cylinder using the create_cone operator with an identical top and bottom diameter
    m = Matrix()
        diameter1 = 1, 
        diameter2 = 1, 
        depth     = 3, 
        segments  = 12,
        matrix    = m.Translation( c )

# Create a mesh and object to represent our bmesh data in the scene
m = bpy.data.meshes.new('cyl')
bm.to_mesh( m )
o = bpy.data.objects.new('cyl', m )
bpy.context.scene.objects.link( o )

The Create cone operator takes various parameters and can control whether the cone / cylinder has caps, uses triangles or quads and other stuff in addition to the obvious parameters of diameter and depth.

BMeshOpFunc bmesh.ops.create_cone(bmesh, cap_ends=False, cap_tris=False, segments=0, diameter1=0.0, diameter2=0.0, depth=0.0, matrix=Matrix(), calc_uvs=False)
-> dict(verts=[])
  • $\begingroup$ I looked up what create_cone does, but I don't get the matrix-parameter. It says "matrix to multiply the new geometry with", what does this mean? Why is it not just a vector that denotes the origin? $\endgroup$ – Gnub Oct 6 '17 at 9:50
  • 1
    $\begingroup$ @Gnub, this is the entire Transformation matrix of the new object, which controls translation, rotation and scale all at once. I only set the translation as shown above, but you can also use m.Rotation( r ) and provide an Euler or Quaternion, or set an m.Scale( s ) with a scale vector. $\endgroup$ – TLousky Oct 6 '17 at 10:56

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.