def scatter_object(leaf_candidates, ob, dupli_object, leaf_size): if dupli_object == None: # return when leaf object is not specified return leafs = [] # container for all created leafs collection = bpy.context.scene.collection # get scene collection ob_transform = ob.matrix_world for position, direction, length, radius, is_end in leaf_candidates: new_leaf = dupli_object.copy() # copy leaf object new_leaf.data = new_leaf.data.copy() dir_rot = Vector((1,0,0)).rotation_difference(direction) # rotation of new leaf loc, rot, scale = new_leaf.matrix_world.decompose() mat_scale = Matrix() # scale of new leaf random_scale = 1 + ((random()-.5) * .4) for i in range(3): mat_scale[i][i] = scale[i] * random_scale new_leaf.matrix_world = ob_transform @ ((Matrix.Translation(position) @ dir_rot.to_matrix().to_4x4() @ mat_scale)) c =random() color_vertices(new_leaf, (c,c,c,c)) leafs.append(new_leaf) collection.objects.link(new_leaf) bpy.ops.object.select_all(action='DESELECT') # deselecting everything so no unwanted object will be joined as a leaf for leaf in leafs: leaf.select_set(state=True) # selecting all leafs ob.select_set(state=True) # selecting twig bpy.context.view_layer.objects.active = ob # make twig the active object so that leafs are joined to it bpy.ops.object.join() # join leafs to twig
def OBB(vecs, r_indices=None, eps=1e-6): """Convex hull を用いたOBBを返す。 Z->Y->Xの順で長さが最少となる軸を求める。 :param vecs: list of Vector :type vecs: list | tuple :param r_indices: listを渡すとconvexhullの結果を格納する :type r_indices: None | list :param eps: 種々の計算の閾値 :return: (matrix, obb_size) matrix: type: Matrx OBBの回転と中心を表す。vecsが二次元ベクトルの場合は3x3, 三次元なら4x4。 obb_size: type: Vector OBBの各軸の長さ。vecsと同じ次元。 :rtype: (Matrix, Vector) """ if not vecs: return None, None # 2D ---------------------------------------------------------------------- if len(vecs[0]) == 2: mat = Matrix.Identity(3) bb_size = Vector((0, 0)) indices = convex_hull_2d(vecs, eps) if r_indices: r_indices[:] = indices if len(indices) == 1: mat.col[2][:2] = vecs[0] elif len(indices) == 2: v1 = vecs[indices[0]] v2 = vecs[indices[1]] xaxis = (v2 - v1).normalized() angle = math.atan2(xaxis[1], xaxis[0]) mat2 = Matrix.Rotation(angle, 2) mat.col[0][:2] = mat2.col[0] mat.col[1][:2] = mat2.col[1] mat.col[2][:2] = (v1 + v2) / 2 bb_size[0] = (v2 - v1).length else: yaxis = _closest_axis_on_plane(vecs, indices) angle = math.atan2(yaxis[1], yaxis[0]) - math.pi / 2 # X軸 mat2 = Matrix.Rotation(angle, 2) imat2 = Matrix.Rotation(-angle, 2) rotvecs = [imat2 * v for v in vecs] loc = Vector((0, 0)) for i in range(2): rotvecs.sort(key=lambda v: v[i]) bb_size[i] = rotvecs[-1][i] - rotvecs[0][i] loc[i] = (rotvecs[0][i] + rotvecs[-1][i]) / 2 mat.col[0][:2] = mat2.col[0] mat.col[1][:2] = mat2.col[1] mat.col[2][:2] = mat2 * loc return mat, bb_size # 3D ---------------------------------------------------------------------- mat = Matrix.Identity(4) bb_size = Vector((0, 0, 0)) indices = convex_hull(vecs, eps) if r_indices: r_indices[:] = indices if isinstance(indices[0], int): # 2d if len(indices) == 1: mat.col[3][:3] = vecs[0] return mat, bb_size elif len(indices) == 2: # 同一線上 v1 = vecs[indices[0]] v2 = vecs[indices[1]] xaxis = (v2 - v1).normalized() quat = Vector((1, 0, 0)).rotation_difference(xaxis) mat = quat.to_matrix().to_4x4() mat.col[3][:3] = (v1 + v2) / 2 bb_size[0] = (v2 - v1).length return mat, bb_size else: # 同一平面上 medium = reduce(lambda a, b: a + b, vecs) / len(vecs) v1 = max(vecs, key=lambda v: (v - medium).length) v2 = max(vecs, key=lambda v: (v - v1).length) line = v2 - v1 v3 = max(vecs, key=lambda v: line.cross(v - v1).length) zaxis = geom.normal(v1, v2, v3) if zaxis[2] < 0.0: zaxis.negate() quat = zaxis.rotation_difference(Vector((0, 0, 1))) rotvecs = [quat * v for v in vecs] indices_2d = indices else: # 3d indices_set = set(chain(*indices)) zaxis = None dist = 0.0 # 最も距離の近い面(平面)と頂点を求める for tri in indices: v1, v2, v3 = [vecs[i] for i in tri] normal = geom.normal(v1, v2, v3) d = 0.0 for v4 in (vecs[i] for i in indices_set if i not in tri): f = abs(geom.distance_point_to_plane(v4, v1, normal)) d = max(f, d) if zaxis is None or d < dist: zaxis = -normal dist = d quat = zaxis.rotation_difference(Vector((0, 0, 1))) rotvecs = [(quat * v).to_2d() for v in vecs] indices_2d = convex_hull_2d(rotvecs, eps) yaxis = _closest_axis_on_plane(rotvecs, indices_2d) yaxis = quat.inverted() * yaxis.to_3d() xaxis = yaxis.cross(zaxis) xaxis.normalize() # 不要? mat.col[0][:3] = xaxis mat.col[1][:3] = yaxis mat.col[2][:3] = zaxis # OBBの大きさと中心を求める imat = mat.inverted() rotvecs = [imat * v for v in vecs] loc = Vector() for i in range(3): rotvecs.sort(key=lambda v: v[i]) bb_size[i] = rotvecs[-1][i] - rotvecs[0][i] loc[i] = (rotvecs[0][i] + rotvecs[-1][i]) / 2 mat.col[3][:3] = mat * loc return mat, bb_size
def execute(self, context): active = context.active_object bm = bmesh.from_edit_mesh(active.data) bm.normal_update() selverts = [v for v in bm.verts if v.select] selfaces = [f for f in bm.faces if f.select] if selfaces: boundary = get_boundary_edges(selfaces) sequences = get_edges_vert_sequences(selverts, boundary, debug=False) # if there are 2 sequences if len(sequences) == 2: seq1, seq2 = sequences verts1, cyclic1 = seq1 verts2, cyclic2 = seq2 if self.flip: verts1, verts2 = verts2, verts1 cyclic1, cyclic2 = cyclic2, cyclic1 # if they are both cyclic and have the same amount of verts,and at least 5 if cyclic1 == cyclic2 and cyclic1 is True and len( verts1) == len(verts2) and len(verts1) >= 5: smooth = selfaces[0].smooth if smooth: active.data.use_auto_smooth = True # deselect verts for v in verts1 + verts2: v.select_set(False) bm.select_flush(False) # set amount of segments self.segments = len(verts1) # get selection mid points center1 = average_locations([v.co for v in verts1]) center2 = average_locations([v.co for v in verts2]) # get the radii, and set the radius as an average radius1 = (center1 - verts1[0].co).length radius2 = (center2 - verts2[0].co).length self.radius = (radius1 + radius2) / 2 # create point coordinates and face indices thread, bottom, top, height = calculate_thread( segments=self.segments, loops=self.loops, radius=self.radius, depth=self.depth / 100, h1=self.h1, h2=self.h2, h3=self.h3, h4=self.h4, fade=self.fade / 100) if height != 0: # build the faces from those coords and indices verts, faces = self.build_faces(bm, thread, bottom, top, smooth=smooth) # scale the thread geometry to fit the selection height selheight = (center1 - center2).length bmesh.ops.scale(bm, vec=Vector((1, 1, selheight / height)), space=Matrix(), verts=verts) # move the thread geometry into alignment with the first selection center bmesh.ops.translate(bm, vec=center1, space=Matrix(), verts=verts) # then rotate it into alignment too, this is done in two steps, first the up vectors are aligned selup = (center2 - center1).normalized() selrot = Vector((0, 0, 1)).rotation_difference(selup) bmesh.ops.rotate(bm, cent=center1, matrix=selrot.to_matrix(), verts=verts, space=Matrix()) # then the first verts are aligned too, get the first vert from the active face if its part of the selection if bm.faces.active and bm.faces.active in selfaces: active_loops = [ loop for v in bm.faces.active.verts if v in verts1 for loop in v.link_loops if loop.face == bm.faces.active ] if active_loops[ 0].link_loop_next.vert == active_loops[ 1].vert: v1 = active_loops[1].vert else: v1 = active_loops[0].vert else: v1 = verts1[0] threadvec = verts[0].co - center1 selvec = v1.co - center1 matchrot = threadvec.rotation_difference( selvec).normalized() bmesh.ops.rotate(bm, cent=center1, matrix=matchrot.to_matrix(), verts=verts, space=Matrix()) # remove doubles bmesh.ops.remove_doubles(bm, verts=verts + verts1 + verts2, dist=0.00001) # remove the initially selected faces bmesh.ops.delete(bm, geom=selfaces, context='FACES') # recalculate the normals, usefull when doing inverted thread bmesh.ops.recalc_face_normals( bm, faces=[f for f in faces if f.is_valid]) bmesh.update_edit_mesh(active.data) return {'FINISHED'} return {'CANCELLED'}
def checkFire(self, tembak): now = datetime.datetime.now() jarak = now - self.lastTimeOfFire if tembak == 2: #print("trying to fire weapon {0} with time a : {1} and time b : {2}".format(self.name, str(jarak.seconds), str(self.reloadTime))) if self.mag > -1: if self.ammo > 0: interval = rTimeLeft(jarak, self.interval) if interval <= 0: projectile = None if self.shootOneByOne == False: for barrel in self.barrelsDeviation: if self.hideBarrelAfterShot == True: barrel.parent.visible = False #print("dp scene ialah " + self.scene.name + " dengan objek " + self.self.name) #ator dp deviation nx = random.random() * self.deviation nx = nx - self.deviation / 2 nz = random.random() * self.deviation nz = nz - self.deviation / 2 deviation = Euler((nx, 0.0, nz)) #print([nx, ny, nz, self.deviation]) na = barrel.parent.worldOrientation #na.rotate(deviation) eul = Vector(na.to_euler()) + Vector(deviation) eul = Euler(eul) barrel.worldOrientation = eul.to_matrix() #cek = deviation, na.to_euler(), barrel.worldOrientation.to_euler() #print(cek) projectile = self.scene.addObject( self.shell, barrel, self.timeToLive) else: barrel = self.barrelsDeviation[ self.currentBarrelIndex] if self.hideBarrelAfterShot == True: barrel.parent.visible = False nx = random.random() * self.deviation nx = nx - self.deviation / 2 nz = random.random() * self.deviation nz = nz - self.deviation / 2 deviation = Euler((nx, 0.0, nz)) na = barrel.parent.worldOrientation eul = Vector(na.to_euler()) + Vector(deviation) eul = Euler(eul) barrel.worldOrientation = eul.to_matrix() #print("dp scene ialah " + self.scene.name + " dengan objek " + self.self.name) projectile = self.scene.addObject( self.shell, barrel, self.timeToLive) ''' if 'type' in projectile: if projectile['type'] == "heatSeekingMissile": projectile = KX_SeekingMissile(projectile) else: projectile = KX_Projectile(projectile) else: projectile = KX_Projectile(projectile) self.ammo -= 1 #print('dp putput = ' + str(self.output)) #print("dp velocity = " + str(self.velocity)) projectile.localLinearVelocity = Vector((self.output.x * self.velocity + self.heldBy.localLinearVelocity.x, self.output.y * self.velocity + self.heldBy.localLinearVelocity.y, self.output.z * self.velocity + self.heldBy.localLinearVelocity.z)) #print('projectile has been shot with speed = {0}'.format(projectile.localLinearVelocity)) self.lastTimeOfFire = datetime.datetime.now() projectile.shotWith = self.name projectile.shotBy = self.heldBy projectile.scaling = Vector(self.scale) projectile.target = self.target ''' pb = len(self.barrelsDeviation) if pb > 1: self.currentBarrelIndex += 1 if self.currentBarrelIndex > pb - 1: self.currentBarrelIndex = 0 #rint(self.currentBarrelIndex) if projectile != None: if 'type' in projectile: if projectile['type'] == "heatSeekingMissile": projectile = gameobjects.KX_SeekingMissile( projectile) projectile.target = self.lockedTo projectile.lockOnStatus = self.lockOnStatus else: projectile = gameobjects.KX_Projectile( projectile) else: projectile = gameobjects.KX_Projectile( projectile) self.ammo -= 1 projectile.localLinearVelocity += Vector( (self.output.x * self.velocity + self.heldBy.localLinearVelocity.x, self.output.y * self.velocity + self.heldBy.localLinearVelocity.y, self.output.z * self.velocity + self.heldBy.localLinearVelocity.z)) #print('projectile has been shot with speed = {0}'.format(projectile.localLinearVelocity)) projectile.lastVelocity = projectile.worldLinearVelocity self.lastTimeOfFire = datetime.datetime.now() projectile.shotWith = self.name projectile.shotBy = self.heldBy projectile.scaling = Vector(self.scale) self.shootCount += 1 if self.ammo == 0: if self.reloadStatus == "standBy": self.reloadStatus = "gonnaReload" if self.reloadStatus == "awal": self.mag -= 1 self.reloadStatus = "standBy" if self.reloadStatus == "gonnaReload": self.lastTimeOfFire = datetime.datetime.now() jarak = now - self.lastTimeOfFire self.reloadTimeLeft = rTimeLeft(jarak, self.reloadTime) self.reloadStatus = "isReloading" if self.reloadStatus == "isReloading": jarak = now - self.lastTimeOfFire self.reloadTimeLeft = rTimeLeft(jarak, self.reloadTime) if self.reloadTimeLeft <= 0.0: self.reloadStatus = "reloaded" if self.reloadStatus == "reloaded": if self.mag > 0: self.mag -= 1 self.ammo = self.ammoSize if self.mag == 0 and self.ammo == 0: self.reloadStatus = "abis" else: self.reloadStatus = "standBy" if self.hideBarrelAfterShot == True: for barrel in self.barrels: barrel.visible = True