def select_vertices(obj, group, filters): mesh = bmesh.from_edit_mesh(obj.data) vertices = [] axisMap = {'x': 0, 'y': 1, 'z': 2} for v in mesh.verts: satisfied = True for axis in filters: for relation in filters[axis]: mesh_val = v.co[axisMap[axis]] val = filters[axis][relation] if relation == 'lt': if mesh_val >= val: satisfied = False elif relation == 'lte': if mesh_val > val: satisfied = False elif relation == 'gt': if mesh_val <= val: satisfied = False elif relation == 'gte': if mesh_val < val: satisfied = False if satisfied: vertices.append(v.index) vertex_group = obj.vertex_groups.new(group) # === MODE TOGGLE === setMode('OBJECT') vertex_group.add(vertices, 1.0, 'REPLACE')
def make_cristae(name='Cristae', loc=(0,0,0), scale=(0.1, 1, 1), side='right', loop_cut_scale_val=2.4, subsurf_level=2): # Initial box cristae = geom.box(loc=loc, scale=scale, name=name) # Loop cut on front face 2x horizontally and vertically face = getPolygonByNormal(cristae, Vector((1, 0, 0))) edit.loop_cut(getEdgeForFaceAtIndex(cristae, face, 0).index, 2) bpy.ops.transform.resize(value=(1, loop_cut_scale_val, 1)) edit.loop_cut(getEdgeForFaceAtIndex(cristae, face, 1).index, 2) bpy.ops.transform.resize(value=(1, 1, loop_cut_scale_val)) # Subdivision surface modifiers.subsurf(subsurf_level) # Set base material setMaterial(cristae, makeMaterial('Membrane.Inner.Base', (1,1,1), (1,1,1), 1)) # TODO figure out what these numbers should be procedurally # was 0.89, 0.91 with 4x subdiv. pinchThreshold = 0.90 wallThreshold = 0.95 if side == 'right': selectVerticesAndAssignMaterial(cristae, 'Membrane.Inner.Pinch', {'y': {'lt': -pinchThreshold}}, makeMaterial('Membrane.Inner.Pinch', (1,0,0), (1,1,1), 1)) selectVerticesAndAssignMaterial(cristae, 'Membrane.Inner.Wall', {'y': {'gte': -wallThreshold}}, makeMaterial('Membrane.Inner.Wall', (0,0,1), (1,1,1), 1)) elif side == 'left': selectVerticesAndAssignMaterial(cristae, 'Membrane.Inner.Pinch', {'y': {'gte': pinchThreshold}}, makeMaterial('Membrane.Inner.Pinch', (1,0,0), (1,1,1), 1)) selectVerticesAndAssignMaterial(cristae, 'Membrane.Inner.Wall', {'y': {'lt': wallThreshold}}, makeMaterial('Membrane.Inner.Wall', (0,0,1), (1,1,1), 1)) setMode('OBJECT')
def assignMaterialToGroup(obj, group, material): setMaterial(obj, material) obj.active_material_index = getMaterialIndexByName(obj, material.name) bpy.ops.object.vertex_group_set_active(group=group) # === MODE TOGGLE === setMode('EDIT') bpy.ops.object.vertex_group_select() bpy.ops.object.material_slot_assign() bpy.ops.object.vertex_group_deselect()
def make_cristae(name='Cristae', loc=(0, 0, 0), scale=(0.1, 1, 1), side='right', loop_cut_scale_val=2.4, subsurf_level=2): # Initial box cristae = geom.box(loc=loc, scale=scale, name=name) # Loop cut on front face 2x horizontally and vertically face = getPolygonByNormal(cristae, Vector((1, 0, 0))) edit.loop_cut(getEdgeForFaceAtIndex(cristae, face, 0).index, 2) bpy.ops.transform.resize(value=(1, loop_cut_scale_val, 1)) edit.loop_cut(getEdgeForFaceAtIndex(cristae, face, 1).index, 2) bpy.ops.transform.resize(value=(1, 1, loop_cut_scale_val)) # Subdivision surface modifiers.subsurf(subsurf_level) # Set base material setMaterial(cristae, makeMaterial('Membrane.Inner.Base', (1, 1, 1), (1, 1, 1), 1)) # TODO figure out what these numbers should be procedurally # was 0.89, 0.91 with 4x subdiv. pinchThreshold = 0.90 wallThreshold = 0.95 if side == 'right': selectVerticesAndAssignMaterial( cristae, 'Membrane.Inner.Pinch', {'y': { 'lt': -pinchThreshold }}, makeMaterial('Membrane.Inner.Pinch', (1, 0, 0), (1, 1, 1), 1)) selectVerticesAndAssignMaterial( cristae, 'Membrane.Inner.Wall', {'y': { 'gte': -wallThreshold }}, makeMaterial('Membrane.Inner.Wall', (0, 0, 1), (1, 1, 1), 1)) elif side == 'left': selectVerticesAndAssignMaterial( cristae, 'Membrane.Inner.Pinch', {'y': { 'gte': pinchThreshold }}, makeMaterial('Membrane.Inner.Pinch', (1, 0, 0), (1, 1, 1), 1)) selectVerticesAndAssignMaterial( cristae, 'Membrane.Inner.Wall', {'y': { 'lt': wallThreshold }}, makeMaterial('Membrane.Inner.Wall', (0, 0, 1), (1, 1, 1), 1)) setMode('OBJECT')
def select_some(obj, center, threshold): setMode('EDIT') mesh = bmesh.from_edit_mesh(obj.data) vertices = [] for v in mesh.verts: v = obj.matrix_world * v.co x = v.x y = v.y z = v.z if y >= 0 and z >= center-threshold and z <= center+threshold: vertices.append({'x': x, 'y':y, 'z':z}) bpy.ops.object.mode_set(mode='OBJECT') return vertices
def select_some(obj, center, threshold): setMode('EDIT') mesh = bmesh.from_edit_mesh(obj.data) vertices = [] for v in mesh.verts: v = obj.matrix_world * v.co x = v.x y = v.y z = v.z if y >= 0 and z >= center - threshold and z <= center + threshold: vertices.append({'x': x, 'y': y, 'z': z}) bpy.ops.object.mode_set(mode='OBJECT') return vertices
def inner(*args, **kwargs): blenderutils.setMode('EDIT') ret = func(*args, **kwargs)
def make_mitochondria(length=3, width=1, num_rows=30, padding_factor=0.2, do_laplace=False, skip_material_cleaning=True, export=False): # Settings # TODO paramaterize mito_length = 0.8*length row_width = mito_length / num_rows # cristae_width = row_width*(1 - 2*padding_factor) cristae_width = 12.67 * 0.002 cristae_disc_subsurf_level = 2 # cristae_disc_loop_cut_scale_val = 2.4 inner_membrane_subsurf_level = 2 laplace_smooth_factor = 15 make_membranes(scale=(length, width, 1)) unselect_all() innerMembane = bpy.data.objects['Inner-Membrane'] vertices = sorted(select_some(innerMembane, center=0.0, threshold=0.01), key=itemgetter('x')) j_spaces = [] start = 0 - mito_length # for i in range(0, 2): for i in range(0, num_rows+1): x = start + 2*row_width*i y = -2 for v in vertices: if v['x'] >= x: j_spaces.append(2*v['y']) y = v['y'] + width break dist = random.random() * 0.5 j_1 = j_spaces[i] * (random.random()*dist + 0.25) y -= j_1 j_2 = (j_spaces[i]-j_1) * (random.random()*(dist) + 0.25) y2 = y - j_2 - width*2 spacage = j_2 / j_spaces[i] if x >= start + (start+2*mito_length)*0.05 and x <= (start+2*mito_length)*0.95: make_cristae(name='Cristae.' + numToStr(i*2), loc=(x, y, 0), scale=(cristae_width, 1, 1), subsurf_level=cristae_disc_subsurf_level) make_cristae(name='Cristae.' + numToStr(i*2 + 1), loc=(x, y2, 0), scale=(cristae_width, 1, 1), side='left', subsurf_level=cristae_disc_subsurf_level) # Select all cristaes # for i in range(0, num_rows+1): # bpy.data.objects['Cristae.' + numToStr(i*2)].select = True # bpy.data.objects['Cristae.' + numToStr(i*2 + 1)].select = True for obj in bpy.data.objects: if 'Cristae' in obj.name: obj.select = True # Join Cristaes bpy.ops.object.join() # bpy.data.objects['Cristae.' + numToStr(num_rows*2 + 1)].name = 'Cristae.All' # bpy.data.objects['Cristae.All'].select = True modifiers.boolean(bpy.data.objects['Inner-Membrane'], 'UNION') # TODO fix cristae's ending up outside # bpy.ops.mesh.separate(type='LOOSE') # unselect_all() # # for obj in bpy.data.objects: # if 'Cristae' in obj.name and obj.name != 'Cristae.All.001': # obj.select = True # # bpy.data.objects['Cristae.All'].select = True # # bpy.data.objects['Cristae.All.002'].select = True # bpy.ops.object.delete() # Remove top half of outer membrane unselect_all() bpy.context.scene.objects.active = bpy.data.objects['Outer-Membrane'] bpy.data.objects['Outer-Membrane'].select = True remove_top_outer() # Remove old inner membrane setMode('OBJECT') unselect_all() bpy.data.objects['Inner-Membrane'].select = True bpy.ops.object.delete() # Rename # bpy.data.objects['Cristae.All.001'].name = 'Inner-Membrane' # bpy.data.objects['Cristae.All'].name = 'Inner-Membrane' # Should be only one Cristae\.d+ for obj in bpy.data.objects: if 'Cristae' in obj.name: obj.name = 'Inner-Membrane' bpy.data.objects['Inner-Membrane'].select = True bpy.context.scene.objects.active = bpy.data.objects['Inner-Membrane'] modifiers.subsurf(inner_membrane_subsurf_level) modifiers.corrective_smooth(1, 5, True) if (do_laplace): modifiers.laplacian_smooth(laplace_smooth_factor) # === bisect === setMode('EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.bisect(plane_co=(0,0,0), plane_no=(0,0,1), xstart=10, xend=545, ystart=572, yend=572) mesh = bmesh.from_edit_mesh(bpy.context.object.data) zs = [] for v in mesh.verts: v2 = bpy.context.object.matrix_world * v.co if v.select == True: v.select = False zs.append(v2.z) mz = max(zs) for v in mesh.verts: v2 = bpy.context.object.matrix_world * v.co if v2.z > mz: v.select = True bpy.ops.mesh.delete(type='VERT') setMode('OBJECT') unselect_all() reset_box = geom.box(loc=(5,5,5), name='Reset-Box') # === Solidifiy outer membrane === bpy.data.objects['Outer-Membrane'].select = True #bpy.ops.object.duplicate_move() unselect_all() bpy.data.objects['Outer-Membrane'].select = True bpy.context.scene.objects.active = bpy.data.objects['Outer-Membrane'] modifiers.solidify(0, 4 * 0.002, True) #unselect_all() #bpy.data.objects['Outer-Membrane.001'].select = True #bpy.context.scene.objects.active = bpy.data.objects['Outer-Membrane.001'] #modifiers.solidify(0, 4 * 0.002, False, True) # Make and join to reset box then fix up unselect_all() bpy.data.objects['Inner-Membrane'].select = True bpy.data.objects['Reset-Box'].select = True bpy.context.scene.objects.active = bpy.data.objects['Reset-Box'] bpy.ops.object.join() setMode('EDIT') bpy.ops.mesh.separate(type='LOOSE') setMode('OBJECT') unselect_all() bpy.data.objects['Reset-Box.001'].select = True bpy.ops.object.delete() bpy.data.objects['Reset-Box'].name = 'Inner-Membrane' # Solidify Inner-Membrane unselect_all() bpy.data.objects['Inner-Membrane'].select = True modifiers.solidify(0, 4 * 0.002) # Clean up materials if not skip_material_cleaning: remove_unused_materials(bpy.data.objects['Inner-Membrane']) unselect_all() bpy.data.objects['Inner-Membrane'].select = True bpy.data.objects['Outer-Membrane'].select = True bpy.ops.object.join() bpy.data.objects['Inner-Membrane'].name = 'Mitochondria' unselect_all() bpy.data.objects['Mitochondria'].select = True bpy.ops.object.shade_smooth() unselect_all() bpy.data.objects['Mitochondria'].select = True if export: bpy.ops.export_scene.obj( filepath='/Users/jmazz/Desktop/mitochondria.obj', check_existing=False, axis_forward='-Z', axis_up='Y', use_selection=True, use_uvs=False, use_materials=False, group_by_material=True )
def make_mitochondria(length=3, width=1, num_rows=30, padding_factor=0.2, do_laplace=False, skip_material_cleaning=True, export=False): # Settings # TODO paramaterize mito_length = 0.8 * length row_width = mito_length / num_rows # cristae_width = row_width*(1 - 2*padding_factor) cristae_width = 12.67 * 0.002 cristae_disc_subsurf_level = 2 # cristae_disc_loop_cut_scale_val = 2.4 inner_membrane_subsurf_level = 2 laplace_smooth_factor = 15 make_membranes(scale=(length, width, 1)) unselect_all() innerMembane = bpy.data.objects['Inner-Membrane'] vertices = sorted(select_some(innerMembane, center=0.0, threshold=0.01), key=itemgetter('x')) j_spaces = [] start = 0 - mito_length # for i in range(0, 2): for i in range(0, num_rows + 1): x = start + 2 * row_width * i y = -2 for v in vertices: if v['x'] >= x: j_spaces.append(2 * v['y']) y = v['y'] + width break dist = random.random() * 0.5 j_1 = j_spaces[i] * (random.random() * dist + 0.25) y -= j_1 j_2 = (j_spaces[i] - j_1) * (random.random() * (dist) + 0.25) y2 = y - j_2 - width * 2 spacage = j_2 / j_spaces[i] if x >= start + (start + 2 * mito_length) * 0.05 and x <= ( start + 2 * mito_length) * 0.95: make_cristae(name='Cristae.' + numToStr(i * 2), loc=(x, y, 0), scale=(cristae_width, 1, 1), subsurf_level=cristae_disc_subsurf_level) make_cristae(name='Cristae.' + numToStr(i * 2 + 1), loc=(x, y2, 0), scale=(cristae_width, 1, 1), side='left', subsurf_level=cristae_disc_subsurf_level) # Select all cristaes # for i in range(0, num_rows+1): # bpy.data.objects['Cristae.' + numToStr(i*2)].select = True # bpy.data.objects['Cristae.' + numToStr(i*2 + 1)].select = True for obj in bpy.data.objects: if 'Cristae' in obj.name: obj.select = True # Join Cristaes bpy.ops.object.join() # bpy.data.objects['Cristae.' + numToStr(num_rows*2 + 1)].name = 'Cristae.All' # bpy.data.objects['Cristae.All'].select = True modifiers.boolean(bpy.data.objects['Inner-Membrane'], 'UNION') # TODO fix cristae's ending up outside # bpy.ops.mesh.separate(type='LOOSE') # unselect_all() # # for obj in bpy.data.objects: # if 'Cristae' in obj.name and obj.name != 'Cristae.All.001': # obj.select = True # # bpy.data.objects['Cristae.All'].select = True # # bpy.data.objects['Cristae.All.002'].select = True # bpy.ops.object.delete() # Remove top half of outer membrane unselect_all() bpy.context.scene.objects.active = bpy.data.objects['Outer-Membrane'] bpy.data.objects['Outer-Membrane'].select = True remove_top_outer() # Remove old inner membrane setMode('OBJECT') unselect_all() bpy.data.objects['Inner-Membrane'].select = True bpy.ops.object.delete() # Rename # bpy.data.objects['Cristae.All.001'].name = 'Inner-Membrane' # bpy.data.objects['Cristae.All'].name = 'Inner-Membrane' # Should be only one Cristae\.d+ for obj in bpy.data.objects: if 'Cristae' in obj.name: obj.name = 'Inner-Membrane' bpy.data.objects['Inner-Membrane'].select = True bpy.context.scene.objects.active = bpy.data.objects['Inner-Membrane'] modifiers.subsurf(inner_membrane_subsurf_level) modifiers.corrective_smooth(1, 5, True) if (do_laplace): modifiers.laplacian_smooth(laplace_smooth_factor) # === bisect === setMode('EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.bisect(plane_co=(0, 0, 0), plane_no=(0, 0, 1), xstart=10, xend=545, ystart=572, yend=572) mesh = bmesh.from_edit_mesh(bpy.context.object.data) zs = [] for v in mesh.verts: v2 = bpy.context.object.matrix_world * v.co if v.select == True: v.select = False zs.append(v2.z) mz = max(zs) for v in mesh.verts: v2 = bpy.context.object.matrix_world * v.co if v2.z > mz: v.select = True bpy.ops.mesh.delete(type='VERT') setMode('OBJECT') unselect_all() reset_box = geom.box(loc=(5, 5, 5), name='Reset-Box') # === Solidifiy outer membrane === bpy.data.objects['Outer-Membrane'].select = True #bpy.ops.object.duplicate_move() unselect_all() bpy.data.objects['Outer-Membrane'].select = True bpy.context.scene.objects.active = bpy.data.objects['Outer-Membrane'] modifiers.solidify(0, 4 * 0.002, True) #unselect_all() #bpy.data.objects['Outer-Membrane.001'].select = True #bpy.context.scene.objects.active = bpy.data.objects['Outer-Membrane.001'] #modifiers.solidify(0, 4 * 0.002, False, True) # Make and join to reset box then fix up unselect_all() bpy.data.objects['Inner-Membrane'].select = True bpy.data.objects['Reset-Box'].select = True bpy.context.scene.objects.active = bpy.data.objects['Reset-Box'] bpy.ops.object.join() setMode('EDIT') bpy.ops.mesh.separate(type='LOOSE') setMode('OBJECT') unselect_all() bpy.data.objects['Reset-Box.001'].select = True bpy.ops.object.delete() bpy.data.objects['Reset-Box'].name = 'Inner-Membrane' # Solidify Inner-Membrane unselect_all() bpy.data.objects['Inner-Membrane'].select = True modifiers.solidify(0, 4 * 0.002) # Clean up materials if not skip_material_cleaning: remove_unused_materials(bpy.data.objects['Inner-Membrane']) unselect_all() bpy.data.objects['Inner-Membrane'].select = True bpy.data.objects['Outer-Membrane'].select = True bpy.ops.object.join() bpy.data.objects['Inner-Membrane'].name = 'Mitochondria' unselect_all() bpy.data.objects['Mitochondria'].select = True bpy.ops.object.shade_smooth() unselect_all() bpy.data.objects['Mitochondria'].select = True if export: bpy.ops.export_scene.obj( filepath='/Users/jmazz/Desktop/mitochondria.obj', check_existing=False, axis_forward='-Z', axis_up='Y', use_selection=True, use_uvs=False, use_materials=False, group_by_material=True)