def are_objects_intersecting(self, obj1, obj2): BMESH_1 = bmesh.new() BMESH_1.from_mesh(obj1.data) BMESH_1.transform(obj1.matrix_world) BVHtree_1 = BVHTree.FromBMesh(BMESH_1) BMESH_2 = bmesh.new() BMESH_2.from_mesh(obj2.data) BMESH_2.transform(obj2.matrix_world) BVHtree_2 = BVHTree.FromBMesh(BMESH_2) inter = BVHtree_1.overlap(BVHtree_2) #if list is empty, no objects are touching if inter != []: return True else: return False
def __init__(self, obj): self.matrix_local = obj.matrix_local # mesh_settings = (bpy.context.scene, True, 'RENDER') data = obj.to_mesh() #*mesh_settings) vertices = [vert.co[:] for vert in data.vertices] polygons = [poly.vertices[:] for poly in data.polygons] self.BVH = BVHTree.FromPolygons(vertices, polygons) obj.to_mesh_clear()
def BVHTreeAndVerticesInWorldFromObj(obj): mWorld = obj.matrix_world vertsInWorld = [mWorld @ v.co for v in obj.data.vertices] bvh = BVHTree.FromPolygons(vertsInWorld, [p.vertices for p in obj.data.polygons]) return bvh, vertsInWorld
def invoke(self, context, event): wm = context.window_manager self._timer = wm.event_timer_add(0.01, context.window) wm.modal_handler_add(self) settings = get_settings() self.align_meth = settings.align_meth self.start = time.time() self.align_obj = context.object self.base_obj = [ obj for obj in context.selected_objects if obj != self.align_obj ][0] self.base_bvh = BVHTree.FromObject(self.base_obj, context.scene) self.align_obj.rotation_mode = 'QUATERNION' self.vlist = [] #figure out if we need to do any inclusion/exclusion group_lookup = {g.name: g.index for g in self.align_obj.vertex_groups} if 'icp_include' in self.align_obj.vertex_groups: group = group_lookup['icp_include'] for v in self.align_obj.data.vertices: for g in v.groups: if g.group == group and g.weight > 0.9: self.vlist.append(v.index) elif 'icp_exclude' in self.align_obj.vertex_groups: group = group_lookup['icp_exclude'] for v in self.align_obj.data.vertices: v_groups = [g.group for g in v.groups] if group not in v_groups: self.vlist.append(v.index) else: for g in v.groups: if g.group == group and g.weight < 0.1: self.vlist.append(v.index) #unfortunate way to do this.. else: self.vlist = [v.index for v in self.align_obj.data.vertices] #vlist = [range(0,len(align_obj.data.vertices] #perhaps much smarter settings = get_settings() self.thresh = settings.min_start self.sample_fraction = settings.sample_fraction self.iters = settings.icp_iterations self.target_d = settings.target_d self.use_target = settings.use_target self.sample_factor = round(1 / self.sample_fraction) self.redraw_frequency = settings.redraw_frequency self.total_iters = 0 self.converged = False self.conv_t_list = [self.target_d * 2] * 5 #store last 5 translations self.conv_r_list = [None] * 5 return {'RUNNING_MODAL'}
def execute_Mesh(self, vectorList, polygonsIndices, epsilon): if len(polygonsIndices) == 0: return self.getFallbackBVHTree() if 0 <= polygonsIndices.getMinIndex() <= polygonsIndices.getMaxIndex( ) < len(vectorList): return BVHTree.FromPolygons(vectorList, polygonsIndices, epsilon=max(epsilon, 0))
def scanmap(mapname): print("Initializing " + mapname + " " + str(datetime.datetime.now().time())) scale = 1 matrix = np.zeros((SCAN_WIDTH, SCAN_WIDTH, SCAN_HEIGHT), dtype=int) ########################################################################### join_map() # <--- Problematic area ########################################################################### scene = bpy.context.scene print("Creating grid") source_dsts = grid_init(scale, SCAN_WIDTH, SCAN_WIDTH) print("Initializing tree") for obj in bpy.context.scene.objects: if obj.type == 'MESH': objt = obj tree = BVHTree.FromObject(obj, scene) print("Starting scan of " + mapname + ": " + str(datetime.datetime.now().time())) for z in range(SCAN_HEIGHT): # Posun na Z for idxx, line in enumerate(source_dsts): for idxy, sccube in enumerate(line): H_1 = [sccube[0], sccube[2] + z * scale, sccube[1]] v = Vector(list(H_1)) matc = 1 loc, norm, polid, dist = tree.find_nearest(v) pog = objt.data.polygons[polid] slot = objt.material_slots[pog.material_index] mat = slot.material if mat is not None: matc = mat.diffuse_color if dist <= 0.9: matrix[idxy][idxx][z] = matc #print("Pt " + str(idxx) + " " + str(idxy) + " completed at " + str(datetime.datetime.now().time())) #print("Line " + str(idxx) + " completed at " + str(datetime.datetime.now().time())) print("Map " + mapname + " layer completed: " + str(z) + " at " + str(datetime.datetime.now().time())) filename = 'export_mat_' + mapname print("Writing to file" + filename) with open(filename, 'a') as f: for z in range(SCAN_HEIGHT): f.write('\n') f.write('Layer: ' + str(z)) for x in range(SCAN_WIDTH): f.write('\n') for y in range(SCAN_WIDTH): f.write(str(matrix[y][x][z])) print(mapname + " DONE")
def raycast_object(obj, ray_origin, ray_direction, ray_dist=1000.0, world_normal=False, work_layer_mask=0, pass_dist=0.001): matrix = obj.matrix_world.copy() # get the ray relative to the object matrix_inv = matrix.inverted() ray_origin_obj = matrix_inv @ ray_origin ray_target_obj = matrix_inv @ (ray_origin + ray_direction) ray_direction_obj = ray_target_obj - ray_origin_obj mesh = bmesh.from_edit_mesh(obj.data) tree = BVHTree.FromBMesh(mesh) location, normal, face_index, distance = tree.ray_cast( ray_origin_obj, ray_direction_obj, ray_dist) if face_index is None: return None, None, None, None face = mesh.faces[face_index] work_layer_id = mesh.faces.layers.int.get(UvDataLayers.WORK_LAYER) if work_layer_id is None: return None, None, None, None work_layer_value = face[work_layer_id] # Pass through faces under certain conditions do_pass_through = False # Layer mask not matching if work_layer_value != work_layer_mask: do_pass_through = True # Hit face is backface if face.normal.dot(ray_direction) > 0: do_pass_through = not bpy.context.scene.sprytile_data.allow_backface # Hit face is hidden if face.hide: do_pass_through = True # Translate location back to world space location = matrix @ location if do_pass_through: # add shift offset if passing through shift_vec = ray_direction.normalized() * pass_dist new_ray_origin = location + shift_vec return VIEW3D_OP_SprytileModalTool.raycast_object( obj, new_ray_origin, ray_direction, work_layer_mask=work_layer_mask) if world_normal: normal = matrix @ normal return location, normal, face_index, distance
def bvhtree_from_object(self, context, object): bm = bmesh.new() mesh = object.to_mesh(context.depsgraph, True) bm.from_mesh(mesh) bm.transform(object.matrix_world) bvhtree = BVHTree.FromBMesh(bm) bpy.data.meshes.remove(mesh) return bvhtree
def RayCast(obj, start, end): """ Ray cast wraper """ deps = bpy.context.view_layer.depsgraph bvh = tree.FromObject(obj, deps) localStart = obj.matrix_world.inverted() @ start localEnd = obj.matrix_world.inverted() @ end direction = localEnd - localStart ray = bvh.ray_cast(localStart, direction, get_distance(localEnd, localStart)) return (ray[2])
def BVHTreeAndVerticesInWorldFromObj(obj): """ Input: Object of Blender type Object Output: BVH Tree necessary for ray tracing and vertsInWorld = verts in global coordinate system. """ mWorld = obj.matrix_world vertsInWorld = [mWorld @ v.co for v in obj.data.vertices] bvh = BVHTree.FromPolygons(vertsInWorld, [p.vertices for p in obj.data.polygons]) return bvh, vertsInWorld
def is_overlapping(bm1, bm2): """ Input: - bm1 : bmesh 1st object - bm2 : bmesh 2nd object returns: - True if bm1 overlap bm2 """ # Check overlap bool_res = True bvh1 = BVHTree.FromBMesh(bm1) bvh2 = BVHTree.FromBMesh(bm2) res = bvh1.overlap(bvh2) del bvh1 del bvh2 return len(res) != 0
def RayCast(obj, start, end): """ Ray cast wraper """ scn = bpy.context.scene bvh = tree.FromObject(obj, scn) localStart = obj.matrix_world.inverted() * start localEnd = obj.matrix_world.inverted() * end direction = localEnd - localStart ray = bvh.ray_cast(localStart, direction, get_distance(localEnd, localStart)) return (ray[2])
def __init__(self, obj): self.obj = obj mode = obj.mode self.edit_mode = mode == 'EDIT' # hack to update the mesh data bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode=mode) self.bm = bmesh.new() self.bm.from_mesh(obj.data) self.bm1 = None if self.edit_mode: self.bm1 = self.bm.copy() remove, remove1 = [], [] for vert in self.bm.verts: if all(not f.select for f in vert.link_faces): remove.append(vert) for vert in remove: self.bm.verts.remove(vert) for vert in self.bm1.verts: if all(v.select for v in vert.link_faces): remove1.append(vert) for vert in remove1: self.bm1.verts.remove(vert) remove1 = [f for f in self.bm1.faces if f.select] for face in remove1: self.bm1.faces.remove(face) self.bvh = BVHTree.FromBMesh(self.bm) # Boundary_data is a list of directions and locations of boundaries. # This data will serve as guidance for the alignment self.boundary_data = [] # Fill the data using boundary edges as source of directional data. for edge in self.bm.edges: if edge.is_boundary: vec = (edge.verts[0].co - edge.verts[1].co).normalized() center = (edge.verts[0].co + edge.verts[1].co) / 2 self.boundary_data.append((center, vec)) # Create a Kd Tree to easily locate the nearest boundary point self.boundary_kd_tree = KDTree(len(self.boundary_data)) for index, (center, vec) in enumerate(self.boundary_data): self.boundary_kd_tree.insert(center, index) self.boundary_kd_tree.balance()
def start_ui(self, context): self.settings = common_utilities.get_settings() self.keymap = key_maps.rtflow_default_keymap_generate() self.mode_pos = (0, 0) self.cur_pos = (0, 0) self.mode_radius = 0 self.action_center = (0, 0) self.action_radius = 0 self.is_navigating = False self.tweak_data = None self.post_update = True self.obj_orig = get_source_object() self.src_bmc = BMeshCache(self.obj_orig) is_valid = is_object_valid(self.obj_orig) if is_valid: pass #self.bme = mesh_cache['bme'] #self.bvh = mesh_cache['bvh'] else: clear_mesh_cache() me = self.obj_orig.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW') me.update() bme = bmesh.new() bme.from_mesh(me) bvh = BVHTree.FromBMesh(bme) write_mesh_cache(self.obj_orig, bme, bvh) self.dest_obj = context.object self.dest_bme = bmesh.from_edit_mesh(context.object.data) self.mx = self.dest_obj.matrix_world self.imx = invert_matrix(self.mx) # World stroke radius self.stroke_radius = 0.01 * get_object_length_scale(self.obj_orig) # Screen_stroke_radius self.screen_stroke_radius = 20 # TODO, hood to settings self.sketch_brush = SketchBrush(context, self.settings, 0, 0, #event.mouse_region_x, event.mouse_region_y, 15, # settings.quad_prev_radius, mesh_cache['bvh'], self.mx, self.obj_orig.dimensions.length) tweak_undo_cache.clear() # Clear the cache in case any is left over context.area.header_text_set('Tweak')
def bvhtree_from_object(ob): import bmesh bm = bmesh.new() mesh = ob.to_mesh(bpy.context.depsgraph, True) bm.from_mesh(mesh) bm.transform(ob.matrix_world) bvhtree = BVHTree.FromBMesh(bm) bpy.data.meshes.remove(mesh) return bvhtree
def __init__(self, scn, ground, method='OBJ'): self.method = method # 'BVH' or 'OBJ' self.scn = scn self.ground = ground self.bbox = getBBOX.fromObj(ground, applyTransform=True) self.mw = self.ground.matrix_world self.mwi = self.mw.inverted() if self.method == 'BVH': self.bvh = BVHTree.FromObject(self.ground, bpy.context.depsgraph, deform=True)
def __init__(self, OB): self.matrix_local = OB.matrix_local mesh_settings = (bpy.context.scene, True, 'RENDER') data = OB.to_mesh(*mesh_settings) vertices = [vert.co[:] for vert in data.vertices] polygons = [poly.vertices[:] for poly in data.polygons] self.BVH = BVHTree.FromPolygons(vertices, polygons) bpy.data.meshes.remove(data)
def _update_snap_object(self, snap_object): if snap_object.name in self.snap_objects: snap_object_data = self.snap_objects[snap_object.name] snap_object_data.object_matrix = snap_object.matrix_world if snap_object.mode == 'EDIT': bm = bmesh.from_edit_mesh(snap_object.data) snap_object_data.bm = bm snap_object_data.bvh_tree = BVHTree.FromBMesh(bm, epsilon=0.001)
def intersection_check(v1, v2): bm1 = bmesh.new() bm2 = bmesh.new() #fill bmesh data from objects bm1.from_mesh(v1.data) bm2.from_mesh(v2.data) #fixed it here: bm1.transform(v1.matrix_world) bm2.transform(v2.matrix_world) #make BVH tree from BMesh of objects v1_BVHtree = BVHTree.FromBMesh(bm1) v2_BVHtree = BVHTree.FromBMesh(bm2) #get intersecting pairs inter = v1_BVHtree.overlap(v2_BVHtree) return inter
def __init__(self, data, mx=None): if type(data) is str: data = bpy.data.objects[data] if type(data) is bpy.types.Object: assert data.type == 'MESH', 'Unhandled object type: %s' % data.type if not is_object_valid(data): dprint('Creating BMesh from Mesh Object') bme = bmesh.new() bme.from_object(data, bpy.context.scene) # triangulate all faces to ensure planarity and other nice properties dprint('Triangulating BMesh') bmesh.ops.triangulate(bme, faces=bme.faces[:]) # create bvh tree for raycasting and snapping dprint('Creating BVH Tree') bvh = BVHTree.FromBMesh(bme) dprint('Writing to mesh cache') clear_mesh_cache() write_mesh_cache(data, bme, bvh) self.bme = mesh_cache['bme'] self.bvh = mesh_cache['bvh'] self.mx = data.matrix_world elif type(data) is bmesh.types.BMesh: assert mx, 'Must specify matrix when data is BMesh!' bmesh.ops.triangulate(data, faces=data.faces[:]) self.bme = data self.bvh = BVHTree.FromBMesh(self.bme) self.mx = mx else: assert False, 'Unknown data type: %s' % str(type(data)) self.bvh_raycast = self.bvh.ray_cast self.bvh_nearest = self.bvh.find_nearest if bversion( ) > '002.076.000' else self.bvh.find self.imx = invert_matrix(self.mx) self.nmx = matrix_normal(self.mx) self.imx3x3 = self.imx.to_3x3()
def lloyd_in_mesh(verts, faces, sites, n_iterations, thickness=None, weight_field=None): bvh = BVHTree.FromPolygons(verts, faces) if thickness is None: x_min, x_max, y_min, y_max, z_min, z_max = calc_bounds(verts) thickness = max(x_max - x_min, y_max - y_min, z_max - z_min) / 4.0 epsilon = 1e-8 def iteration(points): n = len(points) all_points = points[:] k = 0.5 * thickness for p in points: p = Vector(p) loc, normal, index, distance = bvh.find_nearest(p) if distance <= epsilon: p1 = p + k * normal all_points.append(tuple(p1)) diagram = Voronoi(all_points) centers = [] for site_idx in range(n): region_idx = diagram.point_region[site_idx] region = diagram.regions[region_idx] region_verts = np.array([diagram.vertices[i] for i in region]) center = weighted_center(region_verts, weight_field) centers.append(tuple(center)) return centers def restrict(points): result = [] for p in points: if point_inside_mesh(bvh, p): result.append(p) else: loc, normal, index, distance = bvh.find_nearest(p) if loc is not None: result.append(tuple(loc)) return result points = restrict(sites) for i in range(n_iterations): points = iteration(points) points = restrict(points) return points
def voronoi_on_mesh(verts, faces, sites, thickness, spacing=0.0, clip_inner=True, clip_outer=True, do_clip=True, clipping=1.0, mode='REGIONS', precision=1e-8): bvh = BVHTree.FromPolygons(verts, faces) npoints = len(sites) if clipping is None: x_min, x_max, y_min, y_max, z_min, z_max = calc_bounds(verts) clipping = max(x_max - x_min, y_max - y_min, z_max - z_min) / 2.0 if mode in {'REGIONS', 'RIDGES'}: if clip_inner or clip_outer: normals = calc_bvh_normals(bvh, sites) k = 0.5 * thickness sites = np.array(sites) all_points = sites.tolist() if clip_outer: plus_points = sites + k * normals all_points.extend(plus_points.tolist()) if clip_inner: minus_points = sites - k * normals all_points.extend(minus_points.tolist()) return voronoi3d_layer(npoints, all_points, make_regions=(mode == 'REGIONS'), do_clip=do_clip, clipping=clipping) else: # VOLUME, SURFACE all_points = sites[:] if do_clip: for site in sites: loc, normal, index, distance = bvh.find_nearest(site) if loc is not None: p1 = loc + clipping * normal all_points.append(p1) verts, edges, faces = voronoi_on_mesh_bmesh(verts, faces, len(sites), all_points, spacing=spacing, fill=(mode == 'VOLUME'), precision=precision) return verts, edges, faces, all_points
def add_object(self, snap_object: Object): if snap_object.name not in self.snap_objects: object_data = SnapObjectEditMeshData(snap_object.bound_box[0], snap_object.bound_box[6]) object_data.object_matrix = snap_object.matrix_world self.snap_objects[snap_object.name] = object_data if snap_object.mode == 'EDIT': bm = bmesh.from_edit_mesh(snap_object.data) object_data.bm = bm object_data.bvh_tree = BVHTree.FromBMesh(bm, epsilon=0.001)
def __init__(self, obj): self.matrix_local = obj.matrix_local # mesh_settings = (..., True, 'RENDER') # data = OB.to_mesh(*mesh_settings) data = obj.to_mesh() # bpy.context.depsgraph, apply_modifiers=True, calc_undeformed=False) vertices = [vert.co[:] for vert in data.vertices] polygons = [poly.vertices[:] for poly in data.polygons] self.BVH = BVHTree.FromPolygons(vertices, polygons) obj.to_mesh_clear()
def bvhtree_from_object(context, obj): bm = bmesh.new() depsgraph = context.evaluated_depsgraph_get() ob_eval = obj.evaluated_get(depsgraph) mesh = ob_eval.to_mesh() bm.from_mesh(mesh) bm.transform(obj.matrix_world) bvhtree = BVHTree.FromBMesh(bm) ob_eval.to_mesh_clear() return bvhtree
def lloyd_relax(vertices, faces, iterations, mask=None, method=NORMAL, skip_boundary=True, use_axes={0,1,2}): """ supported shape preservation methods: NONE, NORMAL, LINEAR, BVH """ def do_iteration(bvh, bm): verts_out = [] face_centers = np.array([face.calc_center_median() for face in bm.faces]) for bm_vert in bm.verts: co = bm_vert.co if (skip_boundary and bm_vert.is_boundary) or (mask is not None and not mask[bm_vert.index]): new_vert = tuple(co) else: normal = bm_vert.normal cs = np.array([face_centers[face.index] for face in bm_vert.link_faces]) if method == NONE: new_vert = cs.mean(axis=0) elif method == NORMAL: median = mathutils.Vector(cs.mean(axis=0)) dv = median - co dv = dv - dv.project(normal) new_vert = co + dv elif method == LINEAR: approx = linear_approximation(cs) median = mathutils.Vector(approx.center) plane = approx.most_similar_plane() dist = plane.distance_to_point(bm_vert.co) new_vert = median + plane.normal.normalized() * dist elif method == BVH: median = mathutils.Vector(cs.mean(axis=0)) new_vert, normal, idx, dist = bvh.find_nearest(median) else: raise Exception("Unsupported volume preservation method") new_vert = tuple(new_vert) new_vert = mask_axes(tuple(co), new_vert, use_axes) verts_out.append(new_vert) return verts_out if mask is not None: mask = repeat_last_for_length(mask, len(vertices)) bvh = BVHTree.FromPolygons(vertices, faces) for i in range(iterations): bm = bmesh_from_pydata(vertices, [], faces, normal_update=True) vertices = do_iteration(bvh, bm) bm.free() return vertices
def check_object_intersects(a, b): ''' Checks if 2 objects meshes intersects https://blender.stackexchange.com/questions/71289/using-overlap-to-check-if-two-meshes-are-intersecting ''' bmA = bmesh.new() bmB = bmesh.new() #fill bmesh data from objects bmA.from_mesh(a.data) bmB.from_mesh(b.data) #fixed it here: bmA.transform(a.matrix_world) bmB.transform(b.matrix_world) #make BVH tree from BMesh of objects bvhA = BVHTree.FromBMesh(bmA) bvhB = BVHTree.FromBMesh(bmB) #get intersecting pairs inter = bvhA.overlap(bvhB) #if list is empty, no objects are touching return inter
def obj_ray_cast(obj, matrix): """Wrapper for ray casting that moves the ray into object space""" # get the ray relative to the object matrix_inv = matrix.inverted() ray_origin_obj = matrix_inv * ray_origin ray_target_obj = matrix_inv * ray_target ray_direction_obj = ray_target_obj - ray_origin_obj d = ray_direction_obj.length ray_direction_obj.normalize() # cast the ray if context.mode == 'OBJECT': #print("object") if obj.modifiers == 0: bvh = BVHTree.FromObject(obj, context.scene) location, normal, face_index, d = bvh.ray_cast( ray_origin_obj, ray_direction_obj) else: scene = bpy.context.scene #obj = obj.to_mesh(scene, apply_modifiers=True, settings='PREVIEW') bvh = BVHTree.FromObject(obj, context.scene) location, normal, face_index, d = bvh.ray_cast( ray_origin_obj, ray_direction_obj) #success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj) #bpy.data.meshes.remove(obj) elif context.mode == 'EDIT_MESH': obj.update_from_editmode() bvh = BVHTree.FromBMesh(bmesh.from_edit_mesh(obj.data)) location, normal, face_index, d = bvh.ray_cast( ray_origin_obj, ray_direction_obj) if face_index != -1: return location, normal, face_index else: return None, None, None
def process(self): bvh = [] if self.Mod == "FromObject": for i in self.inputs[0].sv_get(): bvh.append( BVHTree.FromObject(i, bpy.context.scene, deform=True, render=False, cage=False, epsilon=0.0)) elif self.Mod == "FromBMesh": for i in self.inputs[0].sv_get(): bvh.append(BVHTree.FromBMesh(i)) else: for i, i2 in zip(self.inputs[1].sv_get(), self.inputs[2].sv_get()): bvh.append( BVHTree.FromPolygons(i, i2, all_triangles=False, epsilon=0.0)) self.outputs[0].sv_set(bvh)
def construct_pattern_BVHTree(self, obj): # give world space points ( multiplied by obj.mat_world) resampled_curve_segments = self.patter_segments_cache[obj.name] segments_points_flat = [] for segment in resampled_curve_segments: # add cloth sillayette segments_points_flat.extend(segment[:-1]) # cast the ray sourceTri_BVHT = BVHTree.FromPolygons( segments_points_flat, [tuple(i for i in range(len(segments_points_flat)))], all_triangles=False) # [0,1,2] - polygon == vert indices list return sourceTri_BVHT