def makeAffectedGroups(self, string, baseGroups): selection = string['selection'] newGroups = [] formmatrix = mathutils.Matrix() growmatrices = [] # Deselect all faces to start clean! select_faces.none() # Select everything in the base groups for g in baseGroups: select_faces.in_group(g,True) #print('in_group',len(mesh_extras.get_selected_faces())) # If nothing is selected there's nothing to do if mesh_extras.contains_selected_item(self.me.faces): # Select the faces at the tip in a certain direction if selection['type'] == 'joint' or selection['type'] == 'tip': select_faces.innermost() if mesh_extras.contains_selected_item(self.me.faces): if selection['type'] == 'joint': select_faces.connected(True) selCnt = len(mesh_extras.get_selected_faces()) nuCnt = selCnt div = selection['divergence'] # If the nr of faces selected isn't diminished... we select less! while selCnt and selCnt == nuCnt and div > 0.1: select_faces.by_direction(selection['vector'],div) div = div * 0.75 selFaces = mesh_extras.get_selected_faces() nuCnt = len(selFaces) # Check for opposing normals.. .cause they should not be there! for f1 in selFaces: if f1.select: f1No = f1.normal for f2 in selFaces: if f2.select and not f1 is f2: f2No = f2.normal ang = f2No.angle(f1No) if ang > math.radians(120): f1.select = False break selFaces = mesh_extras.get_selected_faces() nuCnt = len(selFaces) if nuCnt == selCnt: select_faces.none() # If we have selected faces... we can add em to a new group newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # Select by pi (fake random) elif selection['type'] == 'liberal': select_faces.liberal(self.dnaString) # If we have selected faces... we can add em to a new group newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # Select all loops in the group elif selection['type'] == 'loops': select_faces.connected() self.deselectUnGrouped() step = 0 # As long as something is selected, we can continue while mesh_extras.contains_selected_item(self.ob.data.faces): select_faces.connected() self.deselectGrouped(baseGroups) # Skip selection just in case if not step % selection['frequency']: # If we have selected faces... we can add em to a new group newGroups, formmatrix, grw = self.addToNewGroups(string, newGroups, growmatrices) growmatrices.extend(grw) step += 1 print(step) # Select by direction elif selection['type'] == 'direction': select_faces.by_direction(selection['vector'],selection['divergence']) newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # All! else: newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) return newGroups, formmatrix, growmatrices
def executeDNA(self, string, baseGroups, baseWeight): ''' if string['number'] >= 1: #if string['number'] in [0,1,3]: return elif string['number'] == 5 or string['number'] == 6: return ''' # Redraw hack to see what is happening # bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) newGroups, formmatrix, growmatrices = self.makeAffectedGroups(string, baseGroups) groupLen = len(newGroups)\ pad = str(' ').rjust(string['level'], ' ') idText = 'limb '+misc.nr4(string['number'])+' '+string['name'].ljust(10, ' ') print(pad,idText) # only if we made a group with something in it do we continue if not groupLen: print(' - No group!') else: # Loop through all the groups for i, group in enumerate(newGroups): # The step number to print out stepText = misc.nr4(i+1)+' of '+misc.nr4(groupLen) # We need a check matrix only if we're not on the head or body if string['name'] == 'head' or string['name'] == 'body' or True: try: del(self.ob['formmatrix']) except: pass # If not... then just try to get rid of it else: self.ob['formmatrix'] = formmatrix # Body gets a set matrix (so it grows nice and straight) if string['name'] == 'head': growmatrix = mathutils.Matrix(((1.0,0.0,0.0),(0.0,0.0,1.0),(0.0,-1.0,0.0))).transposed() # Head gets a set matrix (so it grows nice and straight) elif string['name'] == 'body': growmatrix = mathutils.Matrix(((-1.0,0.0,0.0),(0.0,0.0,1.0),(0.0,1.0,0.0))).transposed() # In all other cases the matrix can be dealt with by the grow addon else: growmatrix = growmatrices[i] self.ob['growmatrix'] = growmatrix # Select a group select_faces.none() select_faces.in_group(group) # No need to continue if we have no selected faces if not mesh_extras.contains_selected_item(self.me.faces): print(pad,'skip ',stepText,'no selection',string['action']['name']) else: a = string['action'] if a['type'] == 'grow': # Check for mirroring right = mathutils.Vector((1.0,0.0,0.0)) check = mathutils.Vector(growmatrix[2]) # If we're aiming left we "invert" the rotation if right.dot(check) < 0.0: rot = mathutils.Vector((-a['rotation'][0],a['rotation'][1],-a['rotation'][2])) else: rot = a['rotation'] # Add relative intensity here (half the original + half the weight) weight = baseWeight * self.getWeight(groupLen, a['scalin']) trans = a['translation'] #trans = self.applyIntensity(a['translation'], weight, 'float') #rot = self.applyIntensity(rot, weight, 'inc') if a['type'] == 'grow' and trans == 0.0: print(pad,'skip ',stepText,'too short',trans,'from',a['translation']) else: print(pad,'step ',stepText,a['name']) #print(self.applyIntensity(a['push'], weight, 'float')) bpy.ops.object.mode_set(mode='EDIT') if a['type'] == 'bump': bpy.ops.mesh.bump( type=a['bumptype'], scale=a['bumpscale'], steps=True, ) else: bpy.ops.mesh.grow( translation=trans, rotation=rot, rotation_falloff=a['rotation_falloff'], scale=a['scale'], scale_falloff=a['scale_falloff'], retain=True, steps=True, debug=False, ) bpy.ops.object.mode_set(mode='OBJECT') select_faces.none() select_faces.in_group(group) self.applyGrowthColor(a) if a['type'] == 'grow': self.applyGrowthCrease(a) # Remove new stuff from all but the current group self.cleanGroup(group) # Keep track of how much steps we've taken self.dnaStep += 1 # If there's a sub if len(string['strings']): for s in string['strings']: #print('going sub', string['name'], s['name']) self.executeDNA(s, [group], weight)
def __init__(self, context, dnaString): self.startTime = time.time() self.markTime = self.startTime self.debug = True self.mark('start') self.offset = 0.999 self.xVec = mathutils.Vector((1.0,0.0,0.0)) self.yVec = mathutils.Vector((0.0,1.0,0.0)) self.zVec = mathutils.Vector((0.0,0.0,1.0)) # Make the liberty class random.seed(dnaString) #Figure out what hull to use hulls = bpy.data.groups['hulls'].objects hull = self.prepObject(random.choice(hulls)) select_faces.none() select_faces.in_group(hull.vertex_groups['mounts']) # Make sure there's some selected faces at least if not mesh_extras.has_selected('faces'): print('No faces found in hull'); else: attachMents = mesh_extras.get_selected_faces() if len(attachMents): group = hull.vertex_groups['mounts'] step = 0 attachCount = 1 vertLen = len(bpy.context.active_object.data.vertices) while step < attachCount and step <= 13 and vertLen < 500000: print('') self.mark('- - - - - finished step '+str(step)+' with '+str(vertLen)+' verts') print('') step += 1 #print('\n - step',step,'\n') # Deselect all faces #select_faces.none() #select_faces.in_group(group) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') #bpy.ops.object.vertex_group_select() bpy.ops.object.vertex_group_select() bpy.ops.object.mode_set(mode='OBJECT') self.mark('deselected everything') #select_faces.in_group(group) #self.mark('selected mounts') hullMounts = mesh_extras.get_selected_faces() hullLen = len(hullMounts) self.mark('got mounts '+str(hullLen)) attachCount = random.randint(int(round(hullLen*0.4)), hullLen) self.mark('made attachcount '+str(attachCount)) if len(hullMounts): hullMount = random.choice(hullMounts) # PREP hullNormal = (hullMount.normal * hull.matrix_world).normalized() hullPos = hullMount.center * hull.matrix_world self.mark('prepped for attaching') self.attachPart(hull, hullMount, hullNormal, hullPos) self.mark('part attached') bpy.ops.object.modifier_add(type='EDGE_SPLIT') bpy.ops.object.modifier_apply(apply_as='DATA', modifier="EdgeSplit") self.mark('edges split') vertLen = len(bpy.context.active_object.data.vertices) self.mark('done attaching at '+str(vertLen)+' verts') ''' select_faces.none() ob = bpy.context.active_object bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.wm.context_set_value(data_path='tool_settings.mesh_select_mode', value="(False, True, False)") bpy.ops.mesh.edges_select_sharp(sharpness=140.0) #bpy.ops.transform.edge_crease(value=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False) bpy.ops.mesh.mark_sharp(clear=False) bpy.ops.object.mode_set(mode='OBJECT') for e in bpy.context.active_object.data.edges: if e.select: e.crease = 1.0 bpy.ops.object.mode_set(mode='EDIT') bpy.ops.wm.context_set_value(data_path='tool_settings.mesh_select_mode', value="(False, False, True)") bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_add(type='SUBSURF') m = ob.modifiers[0] m.show_viewport = False bpy.ops.object.modifier_add(type='EDGE_SPLIT') m = ob.modifiers[0] m.use_edge_angle = False m.use_edge_sharp = True m.show_viewport = False ''' bpy.ops.object.modifier_add(type='EDGE_SPLIT') bpy.ops.object.modifier_apply(apply_as='DATA', modifier="EdgeSplit") #m = bpy.context.active_object.modifiers[0] #m.show_viewport = False bpy.ops.object.shade_smooth() self.mark('set edgesplit and shading') # Lets scale the object ob = bpy.context.active_object dimensions = ob.dimensions max = 0.0 for i, d in enumerate(dimensions): if (not i) or d > max: max = d if max != 0.0: ratio = 15 / max ob.scale *= ratio self.mark('found relative dimension') bpy.ops.object.scale_apply() bpy.ops.object.location_clear() bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS') self.mark('set scale and location') max = mathutils.Vector() min = mathutils.Vector() for i, v in enumerate(ob.data.vertices): co = v.co * ob.matrix_world for j, c in enumerate(co): if c > max[j] or not i: max[j] = c if c < min[j] or not i: min[j] = c #print('vmax',max) #print('vmin',min) loc = (max + min) * 0.5 ob.location = -loc self.mark('corrected location') #print('loc',loc) bpy.data.objects['name'].data.body = dnaString.upper() bpy.context.active_object.name = dnaString self.mark('finished') return
def attachPart(self, parent, parentMount, parentNormal, parentPos): print('') # NOW LETS FIND A PART #children = self.dna.makeDict(bpy.data.groups['parts'].objects) children = bpy.data.groups['parts'].objects if not len(children): return child = self.prepObject(random.choice(children)) #child = self.prepObject(self.dna.Choose('select', children, 'part')) self.mark('prepped object') # Select all the mounts in the child part select_faces.in_group(child.vertex_groups['mounts']) # Make sure there's some selected faces at least if not mesh_extras.has_selected('faces'): print('No faces found in part'); else: childMat = child.matrix_world childMounts = mesh_extras.get_selected_faces() # Deselect all faces select_faces.none() self.mark('finished selection') #childMounts = self.dna.makeDict(childMounts) childMount = random.choice(childMounts) #childMount = self.dna.Choose('select', childMounts, 'childMount') self.mark('chose mount') if childMount: childMount.select = True childNormal = (childMount.normal * child.matrix_world).normalized() # ROTATE THE CHILD AROUND THE GLOBAL Y AXIS TO MATCH THE PARENTMOUNT childY = mathutils.Vector((childNormal[0], 0.0, childNormal[2])).normalized() parentY = mathutils.Vector((parentNormal[0], 0.0, parentNormal[2])).normalized() if childY.length > 0.0 and parentY.length > 0.0: angY = childY.angle(parentY) print(' angY', math.degrees(angY)) if angY > 0.0 and angY < 180.0: rotY = mathutils.Matrix.Rotation((math.radians(180) - angY), 4, mathutils.Vector((0.0,1.0,0.0))).to_4x4() child.matrix_world = rotY * child.matrix_world childNormal = (childMount.normal * child.matrix_world).normalized() else: # ROTATE THE CHILD AROUND THE GLOBAL X AXIS TO MATCH THE PARENTMOUNT childX = mathutils.Vector((0.0, childNormal[1], childNormal[2])).normalized() parentX = mathutils.Vector((0.0, parentNormal[0], parentNormal[2])).normalized() if childX.length > 0.0 and parentX.length > 0.0: angX = childX.angle(parentX) print(' angX', math.degrees(angX)) if angX > 0.0 and angX < 180.0: rotX = mathutils.Matrix.Rotation((math.radians(180) - angX), 4, mathutils.Vector((-1.0,0.0,0.0))).to_4x4() child.matrix_world = rotX * child.matrix_world childNormal = (childMount.normal * child.matrix_world).normalized() # ROTATE THE CHILD AROUDN THE GLOBAL Z AXIS TO MATCH THE PARENTMOUNT childZ = mathutils.Vector((childNormal[0], childNormal[1], 0.0)).normalized() parentZ = mathutils.Vector((parentNormal[0], parentNormal[1], 0.0)).normalized() if childZ.length > 0.0 and parentZ.length > 0.0: angZ = childZ.angle(parentZ) print(' angZ', math.degrees(angZ)) if angZ > 0.0 and angZ < 180.0: rotZ = mathutils.Matrix.Rotation((math.radians(180) - angZ), 4, mathutils.Vector((0.0,0.0,-1.0))).to_4x4() child.matrix_world = rotZ * child.matrix_world elif angZ == 0.0: rotZ = mathutils.Matrix.Rotation(math.radians(180), 4, mathutils.Vector((0.0,0.0,-1.0))).to_4x4() child.matrix_world = rotZ * child.matrix_world #childNormal = (childMount.normal * child.matrix_world).normalized() self.mark('fixed rotation') # SET CHILD POSITION childPos = childMount.center * child.matrix_world child.location = parentPos - childPos bpy.ops.transform.resize(value=(self.offset,self.offset,self.offset), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=0.826446, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), texture_space=False, release_confirm=False) #child.scale *= self.offset self.offset -= 0.001 self.mark('fixed location') # MAKE THE PARENT THE PARENT! YEA parent.select = True bpy.context.scene.objects.active = parent #bpy.ops.object.parent_set(type='OBJECT') self.mirrorCheck(parent, parentMount, parentPos, child) self.mark('checked mirror') # Join the two meshes bpy.ops.object.join() #print(' post join selected',len(mesh_extras.get_selected_faces())) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.vertex_group_remove_from(all=True) bpy.ops.object.mode_set(mode='OBJECT') self.mark('joined and cleaned') return
def makeAffectedGroups(self, string, baseGroups, subCount): print('subcnt', subCount) selection = string['selection'] newGroups = [] formmatrix = mathutils.Matrix() growmatrices = [] # Deselect all faces to start clean! select_faces.none() # Select everything in the base groups for g in baseGroups: select_faces.in_group(g,True) #print('in_group',len(mesh_extras.get_selected_faces())) # If nothing is selected there's nothing to do if mesh_extras.contains_selected_item(self.me.faces): if selection['type'] == 'twig': # Lets find the middle... selFaces = mesh_extras.get_selected_faces() midPoint = mathutils.Vector(); for f1 in selFaces: midPoint += f1.center midPoint /= len(selFaces) midDist = 0.0 nearest = 0 for fc, f1 in enumerate(selFaces): dist = midPoint - f1.center dist = dist.length if not fc or dist < midDist: nearest = f1 midDist = dist select_faces.none() nearest.select = True print('found at distance',len(mesh_extras.get_selected_faces(self.me.faces))) # If we have selected faces... we can add em to a new group newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # Select the faces at the tip in a certain direction elif selection['type'] == 'joint' or selection['type'] == 'tip' : select_faces.innermost() if mesh_extras.contains_selected_item(self.me.faces): if selection['type'] == 'joint': select_faces.connected(True) selCnt = len(mesh_extras.get_selected_faces()) nuCnt = selCnt div = selection['divergence'] # If the nr of faces selected isn't diminished... we select less! while selCnt and selCnt == nuCnt and div > 0.1: select_faces.by_direction(selection['vector'],div) div = div * 0.75 selFaces = mesh_extras.get_selected_faces() nuCnt = len(selFaces) # Check for opposing normals.. .cause they should not be there! for f1 in selFaces: if f1.select: f1No = f1.normal for f2 in selFaces: if f2.select and not f1 is f2: f2No = f2.normal ang = f2No.angle(f1No) if ang > math.radians(120): f1.select = False break selFaces = mesh_extras.get_selected_faces() nuCnt = len(selFaces) if nuCnt == selCnt: select_faces.none() # If we have selected faces... we can add em to a new group newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # Select by pi (fake random) elif selection['type'] == 'liberal': select_faces.liberal(self.dnaString) # If we have selected faces... we can add em to a new group newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # Select all loops in the group elif selection['type'] == 'loops': select_faces.connected() self.deselectUnGrouped() step = 0 # As long as something is selected, we can continue while mesh_extras.contains_selected_item(self.ob.data.faces): select_faces.connected() self.deselectGrouped(baseGroups) # Skip selection just in case if not step % selection['frequency']: # If we have selected faces... we can add em to a new group newGroups, formmatrix, grw = self.addToNewGroups(string, newGroups, growmatrices) growmatrices.extend(grw) step += 1 print(step) # Select by direction elif selection['type'] == 'direction': select_faces.by_direction(selection['vector'],selection['divergence']) newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) # All! else: newGroups, formmatrix, growmatrices = self.addToNewGroups(string, newGroups, growmatrices) return newGroups, formmatrix, growmatrices
def executeDNA(self, string, baseGroups, baseWeight, subCount): '''' if string['number'] >= 1: #if string['number'] in [0,1,3]: return elif string['number'] == 5 or string['number'] == 6: return ''' # Redraw hack #bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) newGroups, formmatrix, growmatrices = self.makeAffectedGroups(string, baseGroups, subCount) groupLen = len(newGroups) pad = str(' ').rjust(string['level'], ' ') idText = 'limb '+misc.nr4(string['number'])+' '+string['name'].ljust(10, ' ') print(pad,idText) # only if we made a group with something in it do we continue if not groupLen: print(' - No group!') else: # Loop through all the groups for i, group in enumerate(newGroups): # The step number to print out stepText = misc.nr4(i+1)+' of '+misc.nr4(groupLen) # We need a check matrix only if we're not on the trunk or body if string['name'] == 'trunk' or string['name'] == 'body' or True: try: del(self.ob['formmatrix']) except: pass # If not... then just try to get rid of it else: self.ob['formmatrix'] = formmatrix # Body gets a set matrix (so it grows nice and straight) if string['name'] == 'trunk': growmatrix = mathutils.Matrix(((1.0,0.0,0.0),(0.0,-1.0,0.0),(0.0,0.0,1.0))).transposed() # In all other cases the matrix can be dealt with by the grow addon else: growmatrix = growmatrices[i] self.ob['growmatrix'] = growmatrix # Select a group select_faces.none() select_faces.in_group(group) # No need to continue if we have no selected faces if not mesh_extras.contains_selected_item(self.me.faces): print(pad,'skip ',stepText,'no selection',string['action']['name']) else: a = string['action'] if a['type'] == 'grow': # Check for mirroring right = mathutils.Vector((1.0,0.0,0.0)) check = mathutils.Vector(growmatrix[2]) # If we're aiming left we "invert" the rotation if right.dot(check) < 0.0: rot = mathutils.Vector((-a['rotation'][0],a['rotation'][1],-a['rotation'][2])) else: rot = a['rotation'] # Add relative intensity here (half the original + half the weight) weight = baseWeight * self.getWeight(groupLen, a['scalin']) trans = a['translation'] if a['type'] == 'grow' and trans == 0.0: print(pad,'skip ',stepText,'too short',trans,'from',a['translation']) else: print(pad,'step ',stepText,a['name']) bpy.ops.object.mode_set(mode='EDIT') if a['type'] == 'bump': bpy.ops.mesh.bump( type=a['bumptype'], scale=a['bumpscale'], steps=True, ) else: bpy.ops.mesh.grow( translation=trans, rotation=rot, rotation_falloff=a['rotation_falloff'], scale=a['scale'], scale_falloff=a['scale_falloff'], retain=True, steps=True, debug=False, ) bpy.ops.object.mode_set(mode='OBJECT') select_faces.none() select_faces.in_group(group) self.applyGrowthColor(a) if a['type'] == 'grow': self.applyGrowthCrease(a) # Remove new stuff from all but the current group self.cleanGroup(group) # Keep track of how much steps we've taken self.dnaStep += 1 # If there's a sub if len(string['strings']): for sc, s in enumerate(string['strings']): #print('going sub', string['name'], s['name']) self.executeDNA(s, [group], weight, sc)