Efficiently creating 50,000 cylinders in a scene?

I don’t know if this is possible, but I have some scenes where I’d like to draw tens of thousands, perhaps hundreds of thousands of cylinders in a scene. Each cylinder is oriented, sized, and textured individually, although the texturing falls into 11 categories. Anyhow, what I’m finding is that my code seems to be n^2 performance wise and would like to know if someone can speed it up.

Here is my code, can anyone tell me how to move the creation and materials part to a lower level? From reading around a bit, it looks like the slow part would be the calls to primitive_cylinder_add and primitive_sphere_add, although perhaps the creation of links in the materials section is also slow, causing scene updates. I just don’t know. I do know that eliminating the entire “if burgers” block still results in n^2 slowdown. Any help? Thanks :smiley:

def MakeCylinder(name, ep1, ep2, radius, orientation, burgers=None, endcaps=True):    # print ("Make cylinder %s from ep1 %s to ep2 %s, in orientation %s"%(name, ep1,ep2,orientation))
    cylvector = ep2 - ep1
    center = ep1 + 0.5 * cylvector
    depth = numpy.linalg.norm(cylvector)
    # print ("cylvector is %s, center is %s, and depth is %s"% (cylvector, center, depth))
    bpy.ops.mesh.primitive_cylinder_add(radius = radius, depth = depth, location = center)
    cyl = bpy.data.objects['Cylinder']
    cyl.name = name
    if orientation == 'X':
        cyl.rotation_euler = [0, pi/2.0, 0]
    elif orientation == 'Y':
        cyl.rotation_euler = [pi/2.0, 0, 0]
    elif orientation == 'Z':
        cyl.rotation_euler = [0, 0, 0]
    else:
        # cyl.rotation_euler = FindRotation(ep1, ep2)
        cyl.rotation_euler = orientation
        # compare = FindRotation(ep1, ep2)
        # print ("computed rotation %s"%str(cyl.rotation_euler ))
        # print ("compare rotation %s"%str(compare ))
    if burgers:
        objs = [cyl]
        if endcaps:
            bpy.ops.mesh.primitive_uv_sphere_add(location=ep1, size = radius )
            ep1s = bpy.data.objects['Sphere']
            ep1s.name = "%s ep1"%name
            bpy.ops.mesh.primitive_uv_sphere_add(location=ep2, size = radius )
            ep2s = bpy.data.objects['Sphere']
            ep2s.name = "%s ep2"%name
            objs = objs + [ep1s, ep2s]
        for obj in objs:
            name = obj.name
            color = ColorFromBurgers(burgers)
            bpy.ops.object.shade_smooth()
            bpy.data.materials.new('%s_material'%name)
            mat = bpy.data.materials['%s_material'%name]
            obj.data.materials.append(mat)
            mat.use_nodes = True
            # node = mat.node_tree.nodes.new("ShaderNodeBsdfDiffuse")
            # node.name = "diffuse_%s"%name
            colornode = mat.node_tree.nodes.new("ShaderNodeBsdfGlossy")
            colornode.name = "%s color"%name
            colornode.inputs['Roughness'].default_value = 0.6
            color = ColorFromBurgers(burgers)
            colornode.inputs['Color'].default_value = color
            emission = mat.node_tree.nodes.new("ShaderNodeEmission")
            emission.name = "%s emission"%name
            emission.inputs['Color'].default_value = color        
            mixnode = mat.node_tree.nodes.new("ShaderNodeMixShader")
            mixnode.name = "%s mixnode"%name
            mat.node_tree.links.new(colornode.outputs['BSDF'], mixnode.inputs[1])
            mat.node_tree.links.new(emission.outputs['Emission'], mixnode.inputs[2]) 
            outnode = mat.node_tree.nodes['Material Output']
            mat.node_tree.links.new(mixnode.outputs['Shader'], outnode.inputs['Surface'])
    return 



There is just one loop. So it looks more like O(n).

You get O(n²) when you call the function in a loop. But i do not know what the inner loop is supposed to do. So it is hard to suggest a better method.

You are right that on the face of it, this algorithm appears O(n). The O(n[SUP]2[/SUP]) behavior is implicit, due to the way blender responds – each additional object updates all objects in the scene, thus each call to create a cylinder slows down as more cylinders appear in the scene. My understanding is that using low-level functions will be better. I have discovered some sample code in the PDB import module that I’m going to use I think. I don’t fully understand it yet.

ask in python forum there was an example for this using plane I think

happy bl

*** Moderation ***
Moved from CG Discussions

See here:
Python performance with Blender operators

I have found another method. Instead of drawing each little cylinder, I draw NURBS curves and extrude a circle along the result. This is a massive speedup. Not quite satisfied yet, but I can now do drawings of moderate datasets.