def get_collider_aligned_rots(self, context, coords, directions): ''' Takes the location coordinates and the corresponding direction vectors. Creates a left and a right rotation Matrix aligned to the surface of the collider Mesh. ''' mat_rots = [] for co, direction in zip(coords, directions): hit, normal, face, distance = self.bvh.find_nearest(co) vec_left = -direction.cross(normal).normalized() vec_right = direction.cross(normal).normalized() vec_left = direction.lerp(vec_left, self.rot_align_left_right).normalized() vec_right = direction.lerp(vec_right, self.rot_align_left_right).normalized() vec_left = vec_left.lerp(normal, self.rot_align_normal).normalized() vec_right = vec_right.lerp(normal, self.rot_align_normal).normalized() vec_left += noise.random_unit_vector() * self.rot_random vec_right += noise.random_unit_vector() * self.rot_random mat_left = align(vec_left, normal) mat_right = align(vec_right, normal) mat_rots.extend([mat_left, mat_right]) return mat_rots
def process(self): count_socket = self.inputs['Count'] seed_socket = self.inputs['Seed'] scale_socket = self.inputs['Scale'] random_socket = self.outputs['Random'] # inputs Coun = count_socket.sv_get(deepcopy=False)[0] Seed = seed_socket.sv_get(deepcopy=False)[0] Scale = scale_socket.sv_get(deepcopy=False, default=[])[0] # outputs if random_socket.is_linked: Random = [] param = match_long_repeat([Coun, Seed, Scale]) # set seed, protect against float input # seed = 0 is special value for blender which unsets the seed value # and starts to use system time making the random values unrepeatable. # So when seed = 0 we use a random value far from 0, generated used random.org for c, s, sc in zip(*param): int_seed = int(round(s)) if int_seed: seed_set(int_seed) else: seed_set(140230) Random.append([(random_unit_vector()*sc).to_tuple() for i in range(int(max(1, c)))]) random_socket.sv_set(Random)
def get_offset(seed): if seed == 0: offset = [0.0, 0.0, 0.0] else: noise.seed_set(seed) offset = noise.random_unit_vector() * 10.0 return offset
def process(self): # inputs if 'Count' in self.inputs and self.inputs['Count'].links and \ type(self.inputs['Count'].links[0].from_socket) == bpy.types.StringsSocket: Coun = SvGetSocketAnyType(self, self.inputs['Count'])[0] else: Coun = [self.count_inner] if 'Seed' in self.inputs and self.inputs['Seed'].links and \ type(self.inputs['Seed'].links[0].from_socket) == bpy.types.StringsSocket: Seed = SvGetSocketAnyType(self, self.inputs['Seed'])[0] else: Seed = [self.seed] # outputs if 'Random' in self.outputs and self.outputs['Random'].links: Random = [] param = match_long_repeat([Coun, Seed]) # set seed, protect against float input # seed = 0 is special value for blender which unsets the seed value # and starts to use system time making the random values unrepeatable. # So when seed = 0 we use a random value far from 0, generated used random.org for c, s in zip(*param): int_seed = int(round(s)) if int_seed: seed_set(int_seed) else: seed_set(140230) Random.append([random_unit_vector().to_tuple() for i in range(int(max(1, c)))]) SvSetSocketAnyType(self, 'Random', Random)
def process(self): # inputs if 'Count' in self.inputs and self.inputs['Count'].links and \ type(self.inputs['Count'].links[0].from_socket) == bpy.types.StringsSocket: Coun = SvGetSocketAnyType(self, self.inputs['Count'])[0] else: Coun = [self.count_inner] if 'Seed' in self.inputs and self.inputs['Seed'].links and \ type(self.inputs['Seed'].links[0].from_socket) == bpy.types.StringsSocket: Seed = SvGetSocketAnyType(self, self.inputs['Seed'])[0] else: Seed = [self.seed] # outputs if 'Random' in self.outputs and self.outputs['Random'].links: Random = [] param = match_long_repeat([Coun, Seed]) # set seed, protect against float input # seed = 0 is special value for blender which unsets the seed value # and starts to use system time making the random values unrepeatable. # So when seed = 0 we use a random value far from 0, generated used random.org for c, s in zip(*param): int_seed = int(round(s)) if int_seed: seed_set(int_seed) else: seed_set(140230) Random.append([ random_unit_vector().to_tuple() for i in range(int(max(1, c))) ]) SvSetSocketAnyType(self, 'Random', Random)
def process(self): count_socket = self.inputs['Count'] seed_socket = self.inputs['Seed'] scale_socket = self.inputs['Scale'] random_socket = self.outputs['Random'] # inputs Coun = count_socket.sv_get(deepcopy=False)[0] Seed = seed_socket.sv_get(deepcopy=False)[0] Scale = scale_socket.sv_get(deepcopy=False, default=[])[0] # outputs if random_socket.is_linked: Random = [] param = match_long_repeat([Coun, Seed, Scale]) # set seed, protect against float input # seed = 0 is special value for blender which unsets the seed value # and starts to use system time making the random values unrepeatable. # So when seed = 0 we use a random value far from 0, generated used random.org for c, s, sc in zip(*param): int_seed = int(round(s)) if int_seed: seed_set(int_seed) else: seed_set(140230) Random.append([(random_unit_vector() * sc).to_tuple() for i in range(int(max(1, c)))]) random_socket.sv_set(Random)
def grow_branch(context, branchidx, ivy, bvh=None): ''' Should have two branches maybe. Test if only the next coordinate is missing: if yes only calculate that one. Reduce computation per frame update if not recalc spline points from start as is done now ''' opt = ivy.ivy seed_val = opt.seed + branchidx + 1 seed(seed_val) noise.seed_set(seed_val) # GET BRANCH-NUMSTEPS FOR THIS FRAME if opt.animated: # this is fixed steps along animation range anim_frames_total = opt.end - opt.start anim_frame_current = context.scene.frame_current - opt.start numsteps = int( (anim_frame_current / anim_frames_total) * opt.fixed_steps) else: numsteps = opt.fixed_steps # CUTOFF NUMSTEPS cutoff = random() if opt.steps_random_cutoff <= cutoff: # cut this one off cutoffamount = (1 - cutoff) * opt.cutoffamount cutoff += cutoffamount numsteps = int(cutoff * numsteps) uvec = noise.random_unit_vector() start_co = Vector((uvec.x * opt.root_area.x, uvec.y * opt.root_area.y, uvec.z * opt.root_area.z)) coords = [start_co] #free = [True] def recalc_all(): freefloatinglength = 0 for step in range(numsteps): last_co = coords[-1] vec_grow = growvec(opt, coords, bvh, freefloatinglength) next_co = last_co + vec_grow if opt.has_collider: next_co, is_free = collision(opt, last_co, next_co, bvh) if is_free: freefloatinglength += (last_co - next_co).length else: freefloatinglength = 0 else: freefloatinglength += (last_co - next_co).length coords.append(next_co) recalc_all() return coords
def grow_branch(context, branchidx, ivy, bvh=None): ''' Should have two branches maybe. Test if only the next coordinate is missing: if yes only calculate that one. Reduce computation per frame update if not recalc spline points from start as is done now ''' opt = ivy.ivy seed_val = opt.seed + branchidx + 1 seed(seed_val) noise.seed_set(seed_val) # GET BRANCH-NUMSTEPS FOR THIS FRAME if opt.animated: # this is fixed steps along animation range anim_frames_total = opt.end - opt.start anim_frame_current = context.scene.frame_current - opt.start numsteps = int((anim_frame_current / anim_frames_total) * opt.fixed_steps) else: numsteps = opt.fixed_steps # CUTOFF NUMSTEPS cutoff = random() if opt.steps_random_cutoff <= cutoff: # cut this one off cutoffamount = (1 - cutoff) * opt.cutoffamount cutoff += cutoffamount numsteps = int(cutoff * numsteps) uvec = noise.random_unit_vector() start_co = Vector((uvec.x * opt.root_area.x, uvec.y * opt.root_area.y, uvec.z * opt.root_area.z)) coords = [start_co] #free = [True] def recalc_all(): freefloatinglength = 0 for step in range(numsteps): last_co = coords[-1] vec_grow = growvec(opt, coords, bvh, freefloatinglength) next_co = last_co + vec_grow if opt.has_collider: next_co, is_free = collision(opt, last_co, next_co, bvh) if is_free: freefloatinglength += (last_co - next_co).length else: freefloatinglength = 0 else: freefloatinglength += (last_co - next_co).length coords.append(next_co) recalc_all() return coords
def grow(self): self.itt += 1 self.to_mesh() nfaces = len(self.obj.data.polygons) face_ind = randint(0,nfaces-1) if self.hits[face_ind]>HITMAX: #print(self.itt,self.faces,'added nothing. hit count reached') return face = self.obj.data.polygons[face_ind] vertices = self.obj.data.vertices fv = face.vertices normal = face.normal.copy() scaled_normal = normal*self.height ru = random_unit_vector()*NOISE xyz_loc = Vector((0,0,0)) for v in fv: xyz_loc += vertices[v].co xyzn_loc = xyz_loc/3.+scaled_normal+ru pos_loc = self.closest_point(xyzn_loc) if (xyzn_loc-pos_loc).length<=scaled_normal.length*SEPARATION: self.hits[face_ind] += 1 #print(self.itt,self.faces,'added nothing.') return xyzn_glob = self.obj.matrix_world*xyzn_loc if not self.is_on_geom(xyzn_glob,GEOM_DISTANCE): self.hits[face_ind] += 1 #print(self.itt,self.faces,'added nothing. too far from geometry') return bm = self.get_bmesh() new_face = bmesh.ops.extrude_discrete_faces(bm, faces=[bm.faces[face_ind]])['faces'].pop() for v in new_face.verts: v.co = xyzn_loc bmesh.ops.remove_doubles(bm,verts=new_face.verts,dist=1000) self.hits[face_ind] = HITMAX+1 self.faces += 3 print(self.itt,self.faces,'new tetrahedron *')
def shake(cont): own = cont.owner t = bge.logic.getRealTime() n = noise.random_unit_vector() own.worldPosition = own.worldPosition + n*own["shake_amount"]
def random_orientation_matrix(size=4): if size == 2: V = random_unit_vector(2) N = Vector((V.y, -V.x)) return Matrix([V, N]) N, V = random_unit_vector(), random_unit_vector() E1 = N.cross(V).normalized() E2 = N.cross(E1).normalized() if (N.length == 0 or E1.length == 0 or E2.length == 0): return random_orientation_matrix() if size == 3: return Matrix([E1, E2, N]) elif size == 4: return Matrix([E1, E2, N]).to_4x4() else: raise ValueError('can only return 2x2, 3x3 or 4x4 matrix')
def grow_from(self, p): growvec = p.direction().normalized() growvec += random_unit_vector(size=3) * 0.5 growvec = growvec.normalized() * 0.1 child = Particle(id=self.particles[-1].id + 1, co=p.rest.translation + growvec, parent=p) p.children.append(child) self.particles.append(child) print('added particle {id}'.format(id=child.id))
def __init__(self, index, scale, location=Vector()): targ_vel = 0.005 * scale self.MAX_VEL = gauss(targ_vel, targ_vel / 10) self.location = location.copy() self.velocity = noise.random_unit_vector() * self.MAX_VEL self.guide_index = index self.noise_seed = noise.random_unit_vector() self.active = True self.direction = randint(0,1)*2-1 # if index > guide_len/2: # self.direction = -1 # else: # self.direction = 1 self.behaviour = 0.6 # 1 = guide ; 0 = turbulence
def process(self): # inputs if ( "Count" in self.inputs and self.inputs["Count"].links and type(self.inputs["Count"].links[0].from_socket) == bpy.types.StringsSocket ): Coun = SvGetSocketAnyType(self, self.inputs["Count"])[0] else: Coun = [self.count_inner] if ( "Seed" in self.inputs and self.inputs["Seed"].links and type(self.inputs["Seed"].links[0].from_socket) == bpy.types.StringsSocket ): Seed = SvGetSocketAnyType(self, self.inputs["Seed"])[0] else: Seed = [self.seed] if ( "Scale" in self.inputs and self.inputs["Scale"].links and type(self.inputs["Scale"].links[0].from_socket) == bpy.types.StringsSocket ): Scale = self.inputs["Scale"].sv_get(deepcopy=False, default=[])[0] else: Scale = [self.scale] # outputs if "Random" in self.outputs and self.outputs["Random"].links: Random = [] param = match_long_repeat([Coun, Seed, Scale]) # set seed, protect against float input # seed = 0 is special value for blender which unsets the seed value # and starts to use system time making the random values unrepeatable. # So when seed = 0 we use a random value far from 0, generated used random.org for c, s, sc in zip(*param): int_seed = int(round(s)) if int_seed: seed_set(int_seed) else: seed_set(140230) Random.append([(random_unit_vector() * sc).to_tuple() for i in range(int(max(1, c)))]) SvSetSocketAnyType(self, "Random", Random)
def update(self): # inputs if 'Count' in self.inputs and len(self.inputs['Count'].links)>0 and \ type(self.inputs['Count'].links[0].from_socket) == bpy.types.StringsSocket: if not self.inputs['Count'].node.socket_value_update: self.inputs['Count'].node.update() Coun = eval(self.inputs['Count'].links[0].from_socket.StringsProperty) else: Coun = [[self.count_inner]] if 'Seed' in self.inputs and len(self.inputs['Seed'].links)>0 and \ type(self.inputs['Seed'].links[0].from_socket) == bpy.types.StringsSocket: if not self.inputs['Seed'].node.socket_value_update: self.inputs['Seed'].node.update() Seed = eval(self.inputs['Seed'].links[0].from_socket.StringsProperty)[0][0] else: Seed = self.seed # outputs if 'Random' in self.outputs and len(self.outputs['Random'].links)>0: Random = [] # set seed, protect against float input # seed = 0 is special value for blender which unsets the seed value # and starts to use system time making the random values unrepeatable. # So when seed = 0 we use a random value far from 0, generated used random.org int_seed = int(round(Seed)) if int_seed: seed_set(int_seed) else: seed_set(140230) # Coun[0], only takes first list for number in Coun[0]: if number > 0: Random.append( [random_unit_vector().to_tuple() \ for i in range(int(number))]) SvSetSocketAnyType(self,'Random',Random)
def make_random_sources_on_geom(self,sinit,init_dist,noise): from numpy import row_stack, all, zeros from numpy.random import randint from scipy.spatial import distance cdist = distance.cdist self.sinit = sinit geom = bpy.data.objects[self.trace_geom] verts = geom.data.vertices num_verts = len(verts) mat = geom.matrix_world source_vectors = [] for i in range(sinit): k = randint(0,num_verts) v_loc = verts[k] v_glob = mat*v_loc.co v_glob += random_unit_vector()*noise source_vectors.append(v_glob) sources = row_stack(source_vectors) dss = cdist(sources,sources,'euclidean') mask = zeros(sinit,'bool') for i in range(sinit-1): d = dss[i,i+1:]>init_dist ok = all(d) if ok: mask[i] = True self.sources = sources[mask] self.dead_sources = [] self.num_sources = sum(mask) return
def cell_fracture_objects( scene, obj, source={'PARTICLE_OWN'}, source_limit=0, source_noise=0.0, clean=True, # operator options use_smooth_faces=False, use_data_match=False, use_debug_points=False, margin=0.0, material_index=0, use_debug_redraw=False, cell_scale=(1.0, 1.0, 1.0), ): from . import fracture_cell_calc # ------------------------------------------------------------------------- # GET POINTS points = _points_from_object(obj, source) if not points: # print using fallback points = _points_from_object(obj, {'VERT_OWN'}) if not points: print("no points found") return [] # apply optional clamp if source_limit != 0 and source_limit < len(points): import random random.shuffle(points) points[source_limit:] = [] # saddly we cant be sure there are no doubles from mathutils import Vector to_tuple = Vector.to_tuple points = list({to_tuple(p, 4): p for p in points}.values()) del to_tuple del Vector # end remove doubles # ------------------ if source_noise > 0.0: from random import random # boundbox approx of overall scale from mathutils import Vector matrix = obj.matrix_world.copy() bb_world = [matrix * Vector(v) for v in obj.bound_box] scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0) from mathutils.noise import random_unit_vector points[:] = [ p + (random_unit_vector() * (scalar * random())) for p in points ] if use_debug_points: bm = bmesh.new() for p in points: bm.verts.new(p) mesh_tmp = bpy.data.meshes.new(name="DebugPoints") bm.to_mesh(mesh_tmp) bm.free() obj_tmp = bpy.data.objects.new(name=mesh_tmp.name, object_data=mesh_tmp) scene.objects.link(obj_tmp) del obj_tmp, mesh_tmp mesh = obj.data matrix = obj.matrix_world.copy() verts = [matrix * v.co for v in mesh.vertices] cells = fracture_cell_calc.points_as_bmesh_cells(verts, points, cell_scale, margin_cell=margin) # some hacks here :S cell_name = obj.name + "_cell" objects = [] for center_point, cell_points in cells: # --------------------------------------------------------------------- # BMESH # create the convex hulls bm = bmesh.new() # WORKAROUND FOR CONVEX HULL BUG/LIMIT # XXX small noise import random def R(): return (random.random() - 0.5) * 0.001 # XXX small noise for i, co in enumerate(cell_points): # XXX small noise co.x += R() co.y += R() co.z += R() # XXX small noise bm_vert = bm.verts.new(co) import mathutils bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005) try: bmesh.ops.convex_hull(bm, input=bm.verts) except RuntimeError: import traceback traceback.print_exc() if clean: bm.normal_update() try: bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001) except RuntimeError: import traceback traceback.print_exc() if use_smooth_faces: for bm_face in bm.faces: bm_face.smooth = True if material_index != 0: for bm_face in bm.faces: bm_face.material_index = material_index # --------------------------------------------------------------------- # MESH mesh_dst = bpy.data.meshes.new(name=cell_name) bm.to_mesh(mesh_dst) bm.free() del bm if use_data_match: # match materials and data layers so boolean displays them # currently only materials + data layers, could do others... mesh_src = obj.data for mat in mesh_src.materials: mesh_dst.materials.append(mat) for lay_attr in ("vertex_colors", "uv_textures"): lay_src = getattr(mesh_src, lay_attr) lay_dst = getattr(mesh_dst, lay_attr) for key in lay_src.keys(): lay_dst.new(name=key) # --------------------------------------------------------------------- # OBJECT obj_cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst) scene.objects.link(obj_cell) # scene.objects.active = obj_cell obj_cell.location = center_point objects.append(obj_cell) # support for object materials if use_data_match: for i in range(len(mesh_dst.materials)): slot_src = obj.material_slots[i] slot_dst = obj_cell.material_slots[i] slot_dst.link = slot_src.link slot_dst.material = slot_src.material if use_debug_redraw: scene.update() _redraw_yasiamevil() scene.update() # move this elsewhere... for obj_cell in objects: game = obj_cell.game game.physics_type = 'RIGID_BODY' game.use_collision_bounds = True game.collision_bounds_type = 'CONVEX_HULL' return objects
def __init__(self, location=Vector()): self.location = location.copy() self.velocity = noise.random_unit_vector() self.active = True
def noise_gen(coords, props): terrain_name = props[0] cursor = props[1] smooth = props[2] triface = props[3] sphere = props[4] land_mat = props[5] water_mat = props[6] texture_name = props[7] subd_x = props[8] subd_y = props[9] meshsize_x = props[10] meshsize_y = props[11] meshsize = props[12] rseed = props[13] x_offset = props[14] y_offset = props[15] z_offset = props[16] size_x = props[17] size_y = props[18] size_z = props[19] nsize = props[20] ntype = props[21] nbasis = props[22] vlbasis = props[23] distortion = props[24] hardnoise = int(props[25]) depth = props[26] amp = props[27] freq = props[28] dimension = props[29] lacunarity = props[30] offset = props[31] gain = props[32] marblebias = int(props[33]) marblesharpnes = int(props[34]) marbleshape = int(props[35]) height = props[36] height_invert = props[37] height_offset = props[38] maximum = props[39] minimum = props[40] falloff = int(props[41]) edge_level = props[42] falloffsize_x = props[43] falloffsize_y = props[44] stratatype = props[45] strata = props[46] addwater = props[47] waterlevel = props[48] vert_group = props[49] remove_double = props[50] fx_mixfactor = props[51] fx_mix_mode = props[52] fx_type = props[53] fx_bias = props[54] fx_turb = props[55] fx_depth = props[56] fx_frequency = props[57] fx_amplitude = props[58] fx_size = props[59] fx_loc_x = props[60] fx_loc_y = props[61] fx_height = props[62] fx_offset = props[63] fx_invert = props[64] x, y, z = coords # Origin if rseed == 0: origin = x_offset, y_offset, z_offset origin_x = x_offset origin_y = y_offset origin_z = z_offset o_range = 1.0 else: # Randomise origin o_range = 100 seed_set(rseed) origin = random_unit_vector() ox = (origin[0] * o_range) oy = (origin[1] * o_range) oz = 0 origin_x = (ox - (ox * 0.5)) + x_offset origin_y = (oy - (oy * 0.5)) + y_offset origin_z = oz + z_offset ncoords = (x / (nsize * size_x) + origin_x, y / (nsize * size_y) + origin_y, z / (nsize * size_z) + origin_z) # Noise type's if ntype in [0, 'multi_fractal']: value = multi_fractal( ncoords, dimension, lacunarity, depth, noise_basis=nbasis) * 0.5 elif ntype in [1, 'ridged_multi_fractal']: value = ridged_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, noise_basis=nbasis) * 0.5 elif ntype in [2, 'hybrid_multi_fractal']: value = hybrid_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, noise_basis=nbasis) * 0.5 elif ntype in [3, 'hetero_terrain']: value = hetero_terrain( ncoords, dimension, lacunarity, depth, offset, noise_basis=nbasis) * 0.25 elif ntype in [4, 'fractal']: value = fractal(ncoords, dimension, lacunarity, depth, noise_basis=nbasis) elif ntype in [5, 'turbulence_vector']: value = turbulence_vector(ncoords, depth, hardnoise, noise_basis=nbasis, amplitude_scale=amp, frequency_scale=freq)[0] elif ntype in [6, 'variable_lacunarity']: value = variable_lacunarity(ncoords, distortion, noise_type1=nbasis, noise_type2=vlbasis) elif ntype in [7, 'marble_noise']: value = marble_noise( (ncoords[0] - origin_x + x_offset), (ncoords[1] - origin_y + y_offset), (ncoords[2] - origin_z + z_offset), (origin[0] + x_offset, origin[1] + y_offset, origin[2] + z_offset), nsize, marbleshape, marblebias, marblesharpnes, distortion, depth, hardnoise, nbasis, amp, freq) elif ntype in [8, 'shattered_hterrain']: value = shattered_hterrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype in [9, 'strata_hterrain']: value = strata_hterrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype in [10, 'ant_turbulence']: value = ant_turbulence(ncoords, depth, hardnoise, nbasis, amp, freq, distortion) elif ntype in [11, 'vl_noise_turbulence']: value = vl_noise_turbulence(ncoords, distortion, depth, nbasis, vlbasis, hardnoise, amp, freq) elif ntype in [12, 'vl_hTerrain']: value = vl_hTerrain(ncoords, dimension, lacunarity, depth, offset, nbasis, vlbasis, distortion) elif ntype in [13, 'distorted_heteroTerrain']: value = distorted_heteroTerrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis, vlbasis) elif ntype in [14, 'double_multiFractal']: value = double_multiFractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis, vlbasis) elif ntype in [15, 'rocks_noise']: value = rocks_noise(ncoords, depth, hardnoise, nbasis, distortion) elif ntype in [16, 'slick_rock']: value = slick_rock(ncoords, dimension, lacunarity, depth, offset, gain, distortion, nbasis, vlbasis) elif ntype in [17, 'planet_noise']: value = planet_noise(ncoords, depth, hardnoise, nbasis)[2] * 0.5 + 0.5 elif ntype in [18, 'blender_texture']: if texture_name != "" and texture_name in bpy.data.textures: value = bpy.data.textures[texture_name].evaluate(ncoords)[3] else: value = 0.0 else: value = 0.5 # Effect mix val = value if fx_type in [0, "0"]: fx_mixfactor = -1.0 fxval = val else: fxcoords = Trans_Effect((x, y, z), fx_size, (fx_loc_x, fx_loc_y)) effect = Effect_Function(fxcoords, fx_type, fx_bias, fx_turb, fx_depth, fx_frequency, fx_amplitude) effect = Height_Scale(effect, fx_height, fx_offset, fx_invert) fxval = Mix_Modes(val, effect, fx_mixfactor, fx_mix_mode) value = fxval # Adjust height value = Height_Scale(value, height, height_offset, height_invert) # Edge falloff: if not sphere: if falloff: ratio_x, ratio_y = abs(x) * 2 / meshsize_x, abs(y) * 2 / meshsize_y fallofftypes = [ 0, sqrt(ratio_y**falloffsize_y), sqrt(ratio_x**falloffsize_x), sqrt(ratio_x**falloffsize_x + ratio_y**falloffsize_y) ] dist = fallofftypes[falloff] value -= edge_level if (dist < 1.0): dist = (dist * dist * (3 - 2 * dist)) value = (value - value * dist) + edge_level else: value = edge_level # Strata / terrace / layers if stratatype not in [0, "0"]: if stratatype in [1, "1"]: strata = strata / height strata *= 2 steps = (sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [2, "2"]: strata = strata / height steps = -abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [3, "3"]: strata = strata / height steps = abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [4, "4"]: strata = strata / height value = int(value * strata) * 1.0 / strata elif stratatype in [5, "5"]: strata = strata / height steps = (int(value * strata) * 1.0 / strata) value = (value * (1.0 - 0.5) + steps * 0.5) # Clamp height min max if (value < minimum): value = minimum if (value > maximum): value = maximum return value
def generate_random_unitvectors(): # may need many more directions to increase accuracy # generate up to 6 directions, filter later seed_set(140230) return [random_unit_vector() for i in range(6)]
def points_to_cells(context, original, original_xyz_minmax, points, source_limit=0, source_noise=0.0, use_smooth_faces=False, use_data_match=False, use_debug_points=False, margin=0.0, material_index=0, use_debug_redraw=False, cell_scale=(1.0, 1.0, 1.0), clean=True): from . import cell_calc collection = context.collection view_layer = context.view_layer # apply optional clamp if source_limit != 0 and source_limit < len(points): points = _limit_source(points, source_limit) # saddly we cant be sure there are no doubles from mathutils import Vector to_tuple = Vector.to_tuple # To remove doubles, round the values. points = [(Vector(to_tuple(p[0], 4)), p[1]) for p in points] del to_tuple del Vector if source_noise > 0.0: from random import random # boundbox approx of overall scale from mathutils import Vector matrix = original.matrix_world.copy() bb_world = [matrix @ Vector(v) for v in original.bound_box] scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0) from mathutils.noise import random_unit_vector points[:] = [(p[0] + (random_unit_vector() * (scalar * random())), p[1]) for p in points] if use_debug_points: bm = bmesh.new() for p in points: bm.verts.new(p[0]) mesh_tmp = bpy.data.meshes.new(name="DebugPoints") bm.to_mesh(mesh_tmp) bm.free() obj_tmp = bpy.data.objects.new(name=mesh_tmp.name, object_data=mesh_tmp) collection.objects.link(obj_tmp) del obj_tmp, mesh_tmp cells_verts = cell_calc.points_to_verts(original_xyz_minmax, points, cell_scale, margin_cell=margin) # some hacks here :S cell_name = original.name + "_cell" cells = [] for center_point, cell_verts in cells_verts: # --------------------------------------------------------------------- # BMESH # create the convex hulls bm = bmesh.new() # WORKAROUND FOR CONVEX HULL BUG/LIMIT # XXX small noise import random def R(): return (random.random() - 0.5) * 0.001 for i, co in enumerate(cell_verts): co.x += R() co.y += R() co.z += R() bm_vert = bm.verts.new(co) import mathutils bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005) try: # Making cell meshes as convex full here! bmesh.ops.convex_hull(bm, input=bm.verts) except RuntimeError: import traceback traceback.print_exc() if clean: bm.normal_update() try: bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001) except RuntimeError: import traceback traceback.print_exc() # smooth faces will remain only inner faces, after appling boolean modifier. if use_smooth_faces: for bm_face in bm.faces: bm_face.smooth = True if material_index != 0: for bm_face in bm.faces: bm_face.material_index = material_index # --------------------------------------------------------------------- # MESH mesh_dst = bpy.data.meshes.new(name=cell_name) bm.to_mesh(mesh_dst) bm.free() del bm if use_data_match: # match materials and data layers so boolean displays them # currently only materials + data layers, could do others... mesh_src = original.data for mat in mesh_src.materials: mesh_dst.materials.append(mat) for lay_attr in ("vertex_colors", "uv_layers"): lay_src = getattr(mesh_src, lay_attr) lay_dst = getattr(mesh_dst, lay_attr) for key in lay_src.keys(): lay_dst.new(name=key) # --------------------------------------------------------------------- # OBJECT cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst) collection.objects.link(cell) cell.location = center_point cells.append(cell) # support for object materials if use_data_match: for i in range(len(mesh_dst.materials)): slot_src = original.material_slots[i] slot_dst = cell.material_slots[i] slot_dst.link = slot_src.link slot_dst.material = slot_src.material if use_debug_redraw: view_layer.update() _redraw_yasiamevil() view_layer.update() # move this elsewhere... # Blender 2.8: BGE integration was disabled, -- # -- because BGE was deleted in Blender 2.8. ''' for cell in cells: game = cell.game game.physics_type = 'RIGID_BODY' game.use_collision_bounds = True game.collision_bounds_type = 'CONVEX_HULL' ''' return cells
def get_mats_for_segment(self, context, segment, splinetype): ''' Creates the Matrizies for a spline segment. ''' #printd('Creating transforms for segment', splinetype) mats = [] p1 = segment[0] p2 = segment[1] count = self.leafs_per_segment if self.bvh: count *= 2 ### TRANSLATION ################# if splinetype == 'BEZIER': coordsb = interpolate_bezier(p1.co, p1.handle_right, p2.handle_left, p2.co, count+1) coords = [coordsb[i].lerp(coordsb[i+1], random()*self.loc_random) for i in range(len(coordsb)-1)] elif splinetype == 'POLY': if count > 1: positions = [i / count for i in range(count)] else: positions = [0.5] #printd('POLY-segment: Lerp-positions', positions) coords = [p1.co.lerp(p2.co, positions[i]+(random() * self.loc_random)).to_3d() for i in range(count)] mat_locs = [Matrix.Translation(co) for co in coords] ### SCALE ################# mat_scales = [Matrix.Scale(self.scale+(random()*self.scale_random), 4) for i in range(len(mat_locs))] ### ROTATION ################# if splinetype == 'BEZIER': directions = [(coordsb[i+1] - coordsb[i]).normalized() for i in range(len(coordsb)-1)] elif splinetype == 'POLY': directions = [(p2.co - p1.co).to_3d().normalized()]*len(coords) #COLLISION -> align leaves to surface if self.bvh: #printd('COLLISION') mat_rots = get_collider_aligned_rots(self, context, coords[:int(count/2)], directions) #NO COLLISION else: vecs_target = directions.copy() #direction + random for y alignment vecs_target = [vt.lerp(vt+noise.random_unit_vector(), self.rot_random).normalized() for vt in vecs_target] #up versus random for z alignment vecs_alignz = [Vector((0,0,1)).lerp(noise.random_unit_vector(), self.rot_align_normal_random).normalized() for i in range(len(directions))] #return alignz towards the direction vector vecs_alignz = [va.lerp(d, self.rot_align_normal).normalized() for va, d in zip(vecs_alignz, directions)] mat_rots = [align(vt, va) for vt, va in zip(vecs_target, vecs_alignz)] #printd('FREE ROTATION Mats:', len(mat_rots)) #COMBINED mats = [l*s*r for l,s,r in zip(mat_locs, mat_scales, mat_rots)] mats = [m for m in mats if not random() > self.leafs_per_segment_random] #printd('MATS: ', len(mats), len(mat_locs), len(mat_scales), len(mat_rots)) return mats
def noise_gen(coords, props): terrain_name = props[0] cursor = props[1] smooth = props[2] triface = props[3] sphere = props[4] land_mat = props[5] water_mat = props[6] texture_name = props[7] subd_x = props[8] subd_y = props[9] meshsize_x = props[10] meshsize_y = props[11] meshsize = props[12] rseed = props[13] x_offset = props[14] y_offset = props[15] z_offset = props[16] size_x = props[17] size_y = props[18] size_z = props[19] nsize = props[20] ntype = props[21] nbasis = int(props[22]) vlbasis = int(props[23]) distortion = props[24] hardnoise = int(props[25]) depth = props[26] amp = props[27] freq = props[28] dimension = props[29] lacunarity = props[30] offset = props[31] gain = props[32] marblebias = int(props[33]) marblesharpnes = int(props[34]) marbleshape = int(props[35]) height = props[36] height_invert = props[37] height_offset = props[38] maximum = props[39] minimum = props[40] falloff = int(props[41]) edge_level = props[42] falloffsize_x = props[43] falloffsize_y = props[44] stratatype = props[45] strata = props[46] addwater = props[47] waterlevel = props[48] vert_group = props[49] remove_double = props[50] fx_mixfactor = props[51] fx_mix_mode = props[52] fx_type = props[53] fx_bias = props[54] fx_turb = props[55] fx_depth = props[56] fx_frequency = props[57] fx_amplitude = props[58] fx_size = props[59] fx_loc_x = props[60] fx_loc_y = props[61] fx_height = props[62] fx_offset = props[63] fx_invert = props[64] x, y, z = coords # Origin if rseed is 0: origin = x_offset, y_offset, z_offset origin_x = x_offset origin_y = y_offset origin_z = z_offset o_range = 1.0 else: # Randomise origin o_range = 10000.0 seed_set(rseed) origin = random_unit_vector() ox = (origin[0] * o_range) oy = (origin[1] * o_range) oz = (origin[2] * o_range) origin_x = (ox - (ox / 2)) + x_offset origin_y = (oy - (oy / 2)) + y_offset origin_z = (oz - (oz / 2)) + z_offset ncoords = (x / (nsize * size_x) + origin_x, y / (nsize * size_y) + origin_y, z / (nsize * size_z) + origin_z) # Noise basis type's if nbasis == 9: nbasis = 14 # Cellnoise if vlbasis == 9: vlbasis = 14 # Noise type's if ntype in [0, 'multi_fractal']: value = multi_fractal(ncoords, dimension, lacunarity, depth, nbasis) * 0.5 elif ntype in [1, 'ridged_multi_fractal']: value = ridged_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis) * 0.5 elif ntype in [2, 'hybrid_multi_fractal']: value = hybrid_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis) * 0.5 elif ntype in [3, 'hetero_terrain']: value = hetero_terrain(ncoords, dimension, lacunarity, depth, offset, nbasis) * 0.25 elif ntype in [4, 'fractal']: value = fractal(ncoords, dimension, lacunarity, depth, nbasis) elif ntype in [5, 'turbulence_vector']: value = turbulence_vector(ncoords, depth, hardnoise, nbasis, amp, freq)[0] elif ntype in [6, 'variable_lacunarity']: value = variable_lacunarity(ncoords, distortion, nbasis, vlbasis) elif ntype in [7, 'marble_noise']: value = marble_noise( (ncoords[0] - origin_x + x_offset), (ncoords[1] - origin_y + y_offset), (ncoords[2] - origin_z + z_offset), (origin[0] + x_offset, origin[1] + y_offset, origin[2] + z_offset), nsize, marbleshape, marblebias, marblesharpnes, distortion, depth, hardnoise, nbasis, amp, freq ) elif ntype in [8, 'shattered_hterrain']: value = shattered_hterrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype in [9, 'strata_hterrain']: value = strata_hterrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype in [10, 'ant_turbulence']: value = ant_turbulence(ncoords, depth, hardnoise, nbasis, amp, freq, distortion) elif ntype in [11, 'vl_noise_turbulence']: value = vl_noise_turbulence(ncoords, distortion, depth, nbasis, vlbasis, hardnoise, amp, freq) elif ntype in [12, 'vl_hTerrain']: value = vl_hTerrain(ncoords, dimension, lacunarity, depth, offset, nbasis, vlbasis, distortion) elif ntype in [13, 'distorted_heteroTerrain']: value = distorted_heteroTerrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis, vlbasis) elif ntype in [14, 'double_multiFractal']: value = double_multiFractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis, vlbasis) elif ntype in [15, 'rocks_noise']: value = rocks_noise(ncoords, depth, hardnoise, nbasis, distortion) elif ntype in [16, 'slick_rock']: value = slick_rock(ncoords,dimension, lacunarity, depth, offset, gain, distortion, nbasis, vlbasis) elif ntype in [17, 'planet_noise']: value = planet_noise(ncoords, depth, hardnoise, nbasis)[2] * 0.5 + 0.5 elif ntype in [18, 'blender_texture']: if texture_name != "" and texture_name in bpy.data.textures: value = bpy.data.textures[texture_name].evaluate(ncoords)[3] else: value = 0.0 else: value = 0.5 # Effect mix val = value if fx_type in [0,"0"]: fx_mixfactor = -1.0 fxval = val else: fxcoords = Trans_Effect((x, y, z), fx_size, (fx_loc_x, fx_loc_y)) effect = Effect_Function(fxcoords, fx_type, fx_bias, fx_turb, fx_depth, fx_frequency, fx_amplitude) effect = Height_Scale(effect, fx_height, fx_offset, fx_invert) fxval = Mix_Modes(val, effect, fx_mixfactor, fx_mix_mode) value = fxval # Adjust height value = Height_Scale(value, height, height_offset, height_invert) # Edge falloff: if not sphere: if falloff: ratio_x, ratio_y = abs(x) * 2 / meshsize_x, abs(y) * 2 / meshsize_y fallofftypes = [0, sqrt(ratio_y**falloffsize_y), sqrt(ratio_x**falloffsize_x), sqrt(ratio_x**falloffsize_x + ratio_y**falloffsize_y) ] dist = fallofftypes[falloff] value -= edge_level if(dist < 1.0): dist = (dist * dist * (3 - 2 * dist)) value = (value - value * dist) + edge_level else: value = edge_level # Strata / terrace / layers if stratatype not in [0, "0"]: if stratatype in [1, "1"]: strata = strata / height strata *= 2 steps = (sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [2, "2"]: strata = strata / height steps = -abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [3, "3"]: strata = strata / height steps = abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [4, "4"]: strata = strata / height value = int( value * strata ) * 1.0 / strata elif stratatype in [5, "5"]: strata = strata / height steps = (int( value * strata ) * 1.0 / strata) value = (value * (1.0 - 0.5) + steps * 0.5) # Clamp height min max if (value < minimum): value = minimum if (value > maximum): value = maximum return value
def get_mats_for_segment(self, context, segment, splinetype): ''' Creates the Matrizies for a spline segment. ''' #printd('Creating transforms for segment', splinetype) mats = [] p1 = segment[0] p2 = segment[1] count = self.leafs_per_segment if self.bvh: count *= 2 ### TRANSLATION ################# if splinetype == 'BEZIER': coordsb = interpolate_bezier(p1.co, p1.handle_right, p2.handle_left, p2.co, count + 1) coords = [ coordsb[i].lerp(coordsb[i + 1], random() * self.loc_random) for i in range(len(coordsb) - 1) ] elif splinetype == 'POLY': if count > 1: positions = [i / count for i in range(count)] else: positions = [0.5] #printd('POLY-segment: Lerp-positions', positions) coords = [ p1.co.lerp(p2.co, positions[i] + (random() * self.loc_random)).to_3d() for i in range(count) ] mat_locs = [Matrix.Translation(co) for co in coords] ### SCALE ################# mat_scales = [ Matrix.Scale(self.scale + (random() * self.scale_random), 4) for i in range(len(mat_locs)) ] ### ROTATION ################# if splinetype == 'BEZIER': directions = [(coordsb[i + 1] - coordsb[i]).normalized() for i in range(len(coordsb) - 1)] elif splinetype == 'POLY': directions = [(p2.co - p1.co).to_3d().normalized()] * len(coords) #COLLISION -> align leaves to surface if self.bvh: #printd('COLLISION') mat_rots = get_collider_aligned_rots(self, context, coords[:int(count / 2)], directions) #NO COLLISION else: vecs_target = directions.copy() #direction + random for y alignment vecs_target = [ vt.lerp(vt + noise.random_unit_vector(), self.rot_random).normalized() for vt in vecs_target ] #up versus random for z alignment vecs_alignz = [ Vector((0, 0, 1)).lerp(noise.random_unit_vector(), self.rot_align_normal_random).normalized() for i in range(len(directions)) ] #return alignz towards the direction vector vecs_alignz = [ va.lerp(d, self.rot_align_normal).normalized() for va, d in zip(vecs_alignz, directions) ] mat_rots = [align(vt, va) for vt, va in zip(vecs_target, vecs_alignz)] #printd('FREE ROTATION Mats:', len(mat_rots)) #COMBINED mats = [l * s * r for l, s, r in zip(mat_locs, mat_scales, mat_rots)] mats = [m for m in mats if not random() > self.leafs_per_segment_random] #printd('MATS: ', len(mats), len(mat_locs), len(mat_scales), len(mat_rots)) return mats
def __init__(self): self.bodies = [] for i in range(self.N): self.bodies.append(Packer(10 * noise.random_unit_vector()))
def landscape_gen(x, y, z, falloffsize, options): # options = [0, 1.0, 'multi_fractal', 0, 0, 1.0, 0, 6, 1.0, 2.0, 1.0, 2.0, # 0, 0, 0, 1.0, 0.0, 1, 0.0, 1.0, 0, 0, 0, 0.0, 0.0] rseed = options[0] nsize = options[1] ntype = options[2] nbasis = int(options[3][0]) vlbasis = int(options[4][0]) distortion = options[5] hardnoise = options[6] depth = options[7] dimension = options[8] lacunarity = options[9] offset = options[10] gain = options[11] marblebias = int(options[12][0]) marblesharpnes = int(options[13][0]) marbleshape = int(options[14][0]) invert = options[15] height = options[16] heightoffset = options[17] falloff = int(options[18][0]) sealevel = options[19] platlevel = options[20] strata = options[21] stratatype = options[22] sphere = options[23] x_offset = options[24] y_offset = options[25] # origin if rseed == 0: origin = 0.0 + x_offset, 0.0 + y_offset, 0.0 origin_x = x_offset origin_y = y_offset origin_z = 0.0 else: # randomise origin seed_set(rseed) origin = random_unit_vector() origin[0] += x_offset origin[1] += y_offset origin_x = ((0.5 - origin[0]) * 1000.0) + x_offset origin_y = ((0.5 - origin[1]) * 1000.0) + y_offset origin_z = (0.5 - origin[2]) * 1000.0 # adjust noise size and origin ncoords = (x / nsize + origin_x, y / nsize + origin_y, z / nsize + origin_z) # noise basis type's if nbasis == 9: nbasis = 14 # to get cellnoise basis you must set 14 instead of 9 if vlbasis == 9: vlbasis = 14 # noise type's if ntype == 'multi_fractal': value = multi_fractal(ncoords, dimension, lacunarity, depth, nbasis) * 0.5 elif ntype == 'ridged_multi_fractal': value = ridged_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis) * 0.5 elif ntype == 'hybrid_multi_fractal': value = hybrid_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis) * 0.5 elif ntype == 'hetero_terrain': value = hetero_terrain(ncoords, dimension, lacunarity, depth, offset, nbasis) * 0.25 elif ntype == 'fractal': value = fractal(ncoords, dimension, lacunarity, depth, nbasis) elif ntype == 'turbulence_vector': value = turbulence_vector(ncoords, depth, hardnoise, nbasis)[0] elif ntype == 'variable_lacunarity': value = variable_lacunarity(ncoords, distortion, nbasis, vlbasis) + 0.5 elif ntype == 'marble_noise': value = marble_noise(x * 2.0 / falloffsize, y * 2.0 / falloffsize, z * 2 / falloffsize, origin, nsize, marbleshape, marblebias, marblesharpnes, distortion, depth, hardnoise, nbasis) elif ntype == 'shattered_hterrain': value = shattered_hterrain(ncoords[0], ncoords[1], ncoords[2], dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype == 'strata_hterrain': value = strata_hterrain(ncoords[0], ncoords[1], ncoords[2], dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype == 'planet_noise': value = planet_noise(ncoords, depth, hardnoise, nbasis)[2] * 0.5 + 0.5 else: value = 0.0 # adjust height if invert != 0: value = (1 - value) * height + heightoffset else: value = value * height + heightoffset # edge falloff if sphere == 0: # no edge falloff if spherical if falloff != 0: fallofftypes = [ 0, hypot(x * x, y * y), hypot(x, y), abs(y), abs(x) ] dist = fallofftypes[falloff] if falloff == 1: radius = (falloffsize / 2)**2 else: radius = falloffsize / 2 value = value - sealevel if (dist < radius): dist = dist / radius dist = (dist * dist * (3 - 2 * dist)) value = (value - value * dist) + sealevel else: value = sealevel # strata / terrace / layered if stratatype != '0': strata = strata / height if stratatype == '1': strata *= 2 steps = (sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * (1.0 - 0.5) + steps * 0.5) * 2.0 elif stratatype == '2': steps = -abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * (1.0 - 0.5) + steps * 0.5) * 2.0 elif stratatype == '3': steps = abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * (1.0 - 0.5) + steps * 0.5) * 2.0 else: value = value # clamp height if (value < sealevel): value = sealevel if (value > platlevel): value = platlevel return value
def cell_fracture_objects(scene, obj, material_index): from . import fracture_cell_calc ctx = obj.destruction.cell_fracture source = ctx.source source_limit = ctx.source_limit source_noise = ctx.source_noise clean = True # operator options use_smooth_faces = ctx.use_smooth_faces use_data_match = ctx.use_data_match use_island_split = True margin = ctx.margin use_debug_points = ctx.use_debug_points cell_scale = ctx.cell_scale re_unwrap = obj.destruction.re_unwrap smart_angle = obj.destruction.smart_angle # ------------------------------------------------------------------------- # GET POINTS points = _points_from_object(obj, source) if not points: # print using fallback points = _points_from_object(obj, {'VERT_OWN'}) if not points: print("no points found") return [] # apply optional clamp if source_limit != 0 and source_limit < len(points): import random random.shuffle(points) points[source_limit:] = [] # saddly we cant be sure there are no doubles from mathutils import Vector to_tuple = Vector.to_tuple points = list({to_tuple(p, 4): p for p in points}.values()) del to_tuple del Vector # end remove doubles # ------------------ if source_noise > 0.0: from random import random # boundbox approx of overall scale from mathutils import Vector matrix = obj.matrix_world.copy() bb_world = [matrix * Vector(v) for v in obj.bound_box] scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0) from mathutils.noise import random_unit_vector points[:] = [p + (random_unit_vector() * (scalar * random())) for p in points] if use_debug_points: bm = bmesh.new() for p in points: bm.verts.new(p) mesh_tmp = bpy.data.meshes.new(name="DebugPoints") bm.to_mesh(mesh_tmp) bm.free() obj_tmp = bpy.data.objects.new(name=mesh_tmp.name, object_data=mesh_tmp) scene.objects.link(obj_tmp) del obj_tmp, mesh_tmp mesh = obj.data matrix = obj.matrix_world.copy() verts = [matrix * v.co for v in mesh.vertices] cells = fracture_cell_calc.points_as_bmesh_cells(verts, points, cell_scale, margin_cell=margin) # some hacks here :S cell_name = obj.name #+ "_cell" objects = [] for center_point, cell_points in cells: # --------------------------------------------------------------------- # BMESH # create the convex hulls bm = bmesh.new() # WORKAROUND FOR CONVEX HULL BUG/LIMIT # XXX small noise import random def R(): return (random.random() - 0.5) * 0.001 # XXX small noise for i, co in enumerate(cell_points): # XXX small noise co.x += R() co.y += R() co.z += R() # XXX small noise bm_vert = bm.verts.new(co) import mathutils bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005) try: bmesh.ops.convex_hull(bm, input=bm.verts) except RuntimeError: import traceback traceback.print_exc() if clean: bm.normal_update() try: bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001) except RuntimeError: import traceback traceback.print_exc() if use_smooth_faces: for bm_face in bm.faces: bm_face.smooth = True if material_index != 0: for bm_face in bm.faces: bm_face.material_index = material_index # --------------------------------------------------------------------- # MESH mesh_dst = bpy.data.meshes.new(name=cell_name) bm.to_mesh(mesh_dst) bm.free() del bm if use_data_match: # match materials and data layers so boolean displays them # currently only materials + data layers, could do others... mesh_src = obj.data for mat in mesh_src.materials: mesh_dst.materials.append(mat) for lay_attr in ("vertex_colors", "uv_textures"): lay_src = getattr(mesh_src, lay_attr) lay_dst = getattr(mesh_dst, lay_attr) for key in lay_src.keys(): lay_dst.new(name=key) # --------------------------------------------------------------------- # OBJECT obj_cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst) scene.objects.link(obj_cell) # scene.objects.active = obj_cell obj_cell.location = center_point #needed for parenting system obj_cell.parent = bpy.context.scene.objects[cell_name].parent objects.append(obj_cell) if re_unwrap: scene.objects.active = obj_cell bpy.ops.object.mode_set(mode = 'EDIT') bpy.ops.mesh.select_all(action = 'SELECT') bpy.ops.mesh.dissolve_limited(angle_limit = 0.001) bpy.ops.mesh.mark_seam() bpy.ops.uv.smart_project(angle_limit = smart_angle) bpy.ops.object.mode_set(mode = 'OBJECT') if obj.destruction.use_debug_redraw: scene.update() obj.destruction._redraw_yasiamevil() scene.update() # move this elsewhere... # for obj_cell in objects: # game = obj_cell.game # game.physics_type = 'RIGID_BODY' # game.use_collision_bounds = True # game.collision_bounds_type = 'CONVEX_HULL' return objects
def grow(self): from numpy import sum, all, ones self.itt += 1 stp = self.stp killzone = self.killzone noise = self.noise v_xyz,s_xyz = self.get_positions() dvv,dvs = self.get_distances(v_xyz,s_xyz) vs_map,sv_map = self.make_maps(dvv,dvs,killzone) nv,ns = dvs.shape self.select_seed() bm = self.get_bmesh() nodes = [v for v in bm.verts] for i,jj in vs_map.items(): v = Vector(sum(s_xyz[jj,:]-v_xyz[i,:],axis=0)) v.normalize() # this is flawed. particularly for "flat" geometries p,pn = self.closest_point_on_geom(nodes[i].co) projected = pn.cross(v.cross(pn)) projected += random_unit_vector()*noise projected.normalize() new = nodes[i].co + projected*stp verts = [nodes[i]] new_vert = bmesh.ops.extrude_vert_indiv( bm, verts=verts)['verts'].pop() new_vert.co = new ## mask out dead sources mask = ones(ns,'bool') for j,ii in sv_map.items(): if all(dvs[ii,j]<=killzone): mask[j] = False self.num_sources -= 1 print('merging:',len(ii),'deleted source:',j) new_verts = [] for i in ii: new = bmesh.ops.extrude_vert_indiv( bm, verts=[nodes[i]])['verts'].pop() new.co = self.sources[j] new_verts.append(new) bmesh.ops.remove_doubles(bm,verts=new_verts,dist=0.01) self.dead_sources.append(self.sources[j]) self.to_mesh() self.sources = self.sources[mask,:] return
def grow(self): from numpy import sum, all, ones self.itt += 1 v_xyz,s_xyz = self.get_positions() dvv,dvs = self.get_distances(v_xyz,s_xyz) vs_map,sv_map = self.make_maps(dvv,dvs) nv,ns = dvs.shape nodes = self.nodes stp = self.stp killzone = self.killzone noise = self.noise spawn_count = self.spawn_count new_node_pos = [] for i,jj in vs_map.items(): if spawn_count[i]>2: continue mask = dvs[i,jj]>=killzone if all(mask): spawn_count[i] += 1 v = Vector(sum(s_xyz[jj,:]-v_xyz[i,:],axis=0)) v.normalize() p,pn = self.closest_point_on_geom(nodes[i]) projected = pn.cross(v.cross(pn)) projected.normalize() if v.dot(projected)<0.85: new = projected else: new = v new += random_unit_vector()*noise new.normalize() new = nodes[i] + new*stp new_node_pos.append(new) bpy.ops.mesh.primitive_ico_sphere_add( size=0.3, subdivisions=1, location=new) self.rotate(v) self.boolean_union(bpy.context.object) ## mask out dead source nodes mask = ones(ns,'bool') for j,ii in sv_map.items(): if all(dvs[ii,j]<=killzone): mask[j] = False self.num_sources -= 1 bpy.ops.mesh.primitive_ico_sphere_add( size=0.3, subdivisions=1, location=self.sources[j]) self.boolean_union(bpy.context.object) print('deleted source:',j) self.dead_sources.append(self.sources[j]) self.nodes.extend(new_node_pos) self.sources = self.sources[mask,:] return