0

I've been modeling neurons in Blender using python code. This is the best way I've found to import cylinders (each representing a slice of a neuron) of a certain radius, depth, and position. Then I name the cylinder and assign it a material.

import bpy 
import csv 
with open ('C:/Users/scrill2015/Desktop/Modeling/Neuron 57-2 EM Post Analysis wo Labels.csv') as f:    
    readout=list(csv.reader(f))
    #print(readout) 
for a in readout: 
    bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius=float(a[3]), depth=float(a[5]), enter_editmode=False, align='WORLD', location=(0, 0, 1000), scale=(1, 1, 1)) 
    bpy.ops.transform.rotate(value=1.5708, orient_axis='X', orient_type='VIEW', orient_matrix=((0.999984, -0.00558533, 2.27243e-07), (0.00311015, 0.556867, 0.830596), (-0.00463928, -0.830583, 0.556876)), orient_matrix_type='VIEW', mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
    bpy.context.object.location[1] = float(a[6])
    bpy.context.active_object.name = (a[0])
    mat = bpy.data.materials.get("Silhouette")
    bpy.context.active_object.data.materials.append(mat)

The cylinders are being produced at a rate of 1-2 seconds per cylinder, meaning a neuron made up of 1900 cylinders takes over an hour. My boss says that it should occur on a magnitude of microseconds. Is there anything I can do my code to optimize the time it takes to run?

Sarah
  • 3
  • 1

1 Answers1

1

Calls to bpy.ops are slow, and get slower the more objects there are in the scene. See Python performance with Blender operators. It's faster to use the lower level APIs than the operators.

In this case for example, you can create one cylinder as a "template", then copy and scale it to produce a cylinder with a different radius/depth. This should be a lot faster.

import time
import math
import bpy
from mathutils import Matrix

Create a cylinder to use as a "template"

bpy.ops.mesh.primitive_cylinder_add( vertices=32, radius=1, depth=1, enter_editmode=False, ) cyl = bpy.context.object.data cyl.name = 'tmp' bpy.data.objects.remove(bpy.context.object, do_unlink=True)

Fetch material to use

mat = bpy.data.materials.get("Silhouette")

for ai, a in enumerate(readout): start_t = time.time()

# Copy the template cylinder and scale it to the right radius/depth.
mesh = cyl.copy()
mesh.name = a[0]
radius = float(a[3])
depth = float(a[5])
mesh.transform(Matrix.Diagonal([radius, radius, depth, 1]))

mesh.materials.append(mat)

ob = bpy.data.objects.new(a[0], mesh)
ob.location = (0, float(a[6]), 1000)
ob.rotation_euler[0] = -math.pi / 2

bpy.context.collection.objects.link(ob)

print("%d : took %.4f" % (ai, time.time() - start_t))

Done with the template cylinder so remove it

bpy.data.meshes.remove(cyl)

Not sure this exactly matches your code since its hard to test without your file, but it should be close enough for you to get the idea.

scurest
  • 10,349
  • 13
  • 31