def bvhtree_from_object(context, obj): bm = bmesh.new() mesh = obj.to_mesh(context.depsgraph, True) bm.from_mesh(mesh) bm.transform(obj.matrix_world) bvhtree = BVHTree.FromBMesh(bm) bpy.data.meshes.remove(mesh) return bvhtree
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 __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 _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 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 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 are_inside(points, bm): mask_inside = [] mask = mask_inside.append bvh = BVHTree.FromBMesh(bm, epsilon=0.0001) # return points on polygons for point in points: fco, normal, _, _ = bvh.find_nearest(point) p2 = fco - Vector(point) v = p2.dot(normal) mask(not v < 0.0) # addp(v >= 0.0) ? return mask_inside
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 shrinkwrap(bm, bmt, debug=False): bvh = BVH.FromBMesh(bmt) for v in bm.verts: location, normal, index, distance = bvh.find_nearest(v.co) if debug: print(location, normal, index, distance) if location: v.co = location bmt.free()
def get_collider_bvh(context, ivy): opt = ivy.ivy if opt.has_collider: # collider in ivy space returns theoretically the # correct mesh. But somehow rotations still mock # up the collsions. bm = collider_in_ivy_space(context, ivy) bvh = BVHTree() bvh = bvh.FromBMesh(bm) # from object does not take transforms into account #bvh = bvh.FromObject(context.scene.objects[opt.collider], context.scene) return bvh else: return None
def setup_self(self, context): ''' Setup: Set needed Values and prepare and store some data. ''' self.curve = context.active_object groups = bpy.data.groups names = [n.strip() for n in self.leafgroupname.split(',')] self.dupli_groups = [groups[n] for n in names if n in groups] #printd(self.dupli_groups) seed(self.seed) noise.seed_set(self.seed) #this is only if the scripts are not together in a moduke #if 'curve_ivy_animated' in context.user_preferences.addons.keys(): self.ivy_loaded = True #printd('Animated Ivy Addon loaded ok', self.ivy_loaded) self.ivyopt = self.curve.ivy #else: #self.ivy_loaded = False ### CHECK FOR COLLIDER selected = context.selected_objects if len(selected) == 2: collider = [ob for ob in selected if ob != self.curve][-1] collider.select = False if collider.type == 'MESH': bm = bmesh.new() bm.from_object(collider, context.scene) bm.transform(collider.matrix_world) bm.transform(self.curve.matrix_world.inverted()) bvh = BVHTree() bvh = bvh.FromBMesh(bm) self.bvh = bvh else: self.bvh = None ### TAKE ANIMATION FROM GROWING IVY IF AVAILABLE if self.ivy_loaded: if self.ivyopt.added_as_ivy: #was indeed intended as growing ivy if self.ivyopt.animated: print('taking animation from ivy') self.animated = self.ivyopt.animated self.start = self.ivyopt.start self.end = self.ivyopt.end #if no leafgroup found create simple leaf if not self.dupli_groups: pass
def start(self, context): ''' Called when tool is invoked ''' # Setup target for BmeshRender drawing of existing geometry self.tar_bmesh = bmesh.from_edit_mesh(context.object.data) bvh = BVHTree.FromBMesh(self.tar_bmesh) #target_bmesh, target_mx, source_bvh, source_mx self.tar_bmeshrender = BMeshRender(self.tar_bmesh, get_target_object().matrix_world, bvh, context.object.matrix_world) # Hide any existing geometry bpy.ops.mesh.hide(unselected=True) bpy.ops.mesh.hide(unselected=False) self.start_ui(context)
def are_inside(verts, faces, points, eps): bm = bmesh_from_pydata(verts, [], faces, normal_update=True) mask_inside = [] mask = mask_inside.append bvh = BVHTree.FromBMesh(bm, epsilon=eps) # return points on polygons for point in points: fco, normal, _, _ = bvh.find_nearest(point) p2 = fco - Vector(point) v = p2.dot(normal) mask(not v < 0.0) # addp(v >= 0.0) ? return mask_inside
def check_intersect(the_object,the_other_object): BMESH_1 = bmesh.new() BMESH_1.from_mesh(bpy.context.scene.objects[the_object.name].data) BMESH_1.transform(the_object.matrix_world) BVHtree_1 = BVHTree.FromBMesh(BMESH_1) BMESH_2 = bmesh.new() BMESH_2.from_mesh(bpy.context.scene.objects[the_other_object.name].data) BMESH_2.transform(the_other_object.matrix_world) BVHtree_2 = BVHTree.FromBMesh(BMESH_2) inter = BVHtree_1.overlap(BVHtree_2) touching=False if inter != []: #print(the_object.name + " and " + the_other_object.name + " are touching!") touching=True #else: #print(the_object.name + " and " + the_other_object.name + " NOT touching!") return touching
def objectsOverlap(objA, objB): objABmesh = bmesh.new() objABmesh.from_mesh(objA.data) objABmesh.transform(objA.matrix_world) objABvhTree = BVHTree.FromBMesh(objABmesh) objBBmesh = bmesh.new() objBBmesh.from_mesh(objB.data) objBBmesh.transform(objB.matrix_world) objBBvhTree = BVHTree.FromBMesh(objBBmesh) inter = objABvhTree.overlap(objBBvhTree) if inter: objBBmesh.faces.ensure_lookup_table() centerLocal = Vector((0, 0, 0)) for p in inter: centerLocal = centerLocal + objBBmesh.faces[ p[1]].calc_center_bounds() centerLocal /= len(inter) return centerLocal return None
def bmesh_check_intersect_objects(obj, obj2, selectface=False): assert (obj != obj2) # Triangulate in most cases, not if using CPK matching tris = True if selectface: tris = False bm = bmesh_copy_from_object(obj, transform=True, triangulate=tris) bm2 = bmesh_copy_from_object(obj2, transform=True, triangulate=tris) intersect = False BMT1 = BVHTree.FromBMesh(bm) BMT2 = BVHTree.FromBMesh(bm2) overlap_pairs = BMT1.overlap(BMT2) if len(overlap_pairs) > 0: intersect = True if selectface: # deselect everything for both objects bpy.context.scene.objects.active = obj bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.context.scene.objects.active = obj2 bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.mode_set(mode='OBJECT', toggle=False) for each in overlap_pairs: obj.data.polygons[each[0]].select = True obj.update_from_editmode() obj2.data.polygons[each[1]].select = True obj2.update_from_editmode() bm.free() bm2.free() return intersect
def get_global_intersections(): for obj_now in Objects: # Check every object in the scene for intersections with all the other objects for obj_next in Objects: #print(obj_now.name + " :: " + obj_next.name) if obj_now == obj_next: continue # Create bmesh objects bm_now = bmesh.new() bm_next = bmesh.new() # Fill bmesh data from scene objects bm_now.from_mesh(obj_now.data) bm_next.from_mesh(obj_next.data) # Apply world transform bm_now.transform(obj_now.matrix_world) bm_next.transform(obj_next.matrix_world) # Make BVH tree from BMesh objects obj_now_BVH = BVHTree.FromBMesh(bm_now) obj_next_BVH = BVHTree.FromBMesh(bm_next) # Get overlapping objects overlap = obj_now_BVH.overlap(obj_next_BVH) # If 'overlap' list is empty, no objects are touching if overlap != []: print(obj_now.name + " and " + obj_next.name + " are overlapping!") for item in overlap: Intersections.append(item) else: print(obj_now.name + " and " + obj_next.name + " are NOT overlapping!")
def execute( self, context ): active_object = context.scene.objects.active active_mesh = active_object.data if not bpy.context.space_data.region_3d.is_perspective: self.report({'ERROR'}, "Can`t work in ORTHO mode") return {'CANCELLED'} cameraOrigin_g = camera_pos(bpy.context.space_data.region_3d) selvertsAll = get_selected_vertsIdx(active_mesh) bpy.ops.object.mode_set( mode = 'EDIT' ) bpy.ops.mesh.region_to_loop() selvertsBnd = get_selected_vertsIdx(active_mesh) selvertsInner = list(filter(lambda plt: plt not in selvertsBnd, selvertsAll)) if len(selvertsInner) == 0: self.report({'ERROR'}, "No inner vertices found") #print("All: ",selvertsAll," outer:", selvertsBnd) return {'CANCELLED'} bm2 = bmesh.new() chull_verts = [ active_mesh.vertices[vIdx].co for vIdx in selvertsBnd ] for v in chull_verts: bm2.verts.new(v) bmesh.ops.convex_hull(bm2, input=bm2.verts) bm2_tree = BVHTree.FromBMesh(bm2, epsilon = kRaycastEpsilon) bm2.free() #obj_tmp = bpy.data.objects.new(name=me_tmp.name, object_data=me_tmp) #scene.objects.link(obj_tmp) #scene.update() # tracing to new geometry matrix_world_inv = active_object.matrix_world.inverted() cameraOrigin = matrix_world_inv * cameraOrigin_g inner_verts = [ (vIdx, active_mesh.vertices[vIdx].co, active_mesh.vertices[vIdx].normal) for vIdx in selvertsInner ] for w_v in inner_verts: hit = None if self.opt_flatnMeth == 'TO_CAMERA': direction = w_v[1] - cameraOrigin direction.normalize() hit, normal, index, distance = bm2_tree.ray_cast(cameraOrigin, direction) else: origin = w_v[1] direction = w_v[2] direction.normalize() hit, normal, index, distance = bm2_tree.ray_cast(origin+kRaycastDeadzone*direction, direction) if hit is not None: # lerping position vco_shift = hit - w_v[1] vco = w_v[1]+vco_shift*self.opt_flatnFac active_mesh.vertices[w_v[0]].co = vco bpy.ops.object.mode_set( mode = 'EDIT' ) return {'FINISHED'}
def medial_approx(points_loop, precision=0.001): kd = kd_from_points(points_loop) bm = bmesh.new() verts = [bm.verts.new(v) for v in points_loop] face = bm.faces.new(verts) bmesh.ops.recalc_face_normals(bm, faces=bm.faces) normal = face.normal bmesh.ops.triangulate(bm, faces=bm.faces) bvh = BVHTree.FromBMesh(bm) def radius(pt): result, _, _, _ = bvh.ray_cast(pt + normal, -normal) if result: return kd.find(pt)[2] else: return 0 for vert in bm.verts: if not vert.is_boundary: continue mid = vert.co evec = Vector() for edge in vert.link_edges: if edge.is_boundary: evec += (edge.verts[0].co - edge.verts[1].co).cross( edge.link_faces[0].normal) size = precision last_size = size incr = 2 scr = radius(mid + evec * size) cap = 1 + precision while incr > cap: pt = mid + evec * size * incr scr1 = radius(pt) if scr1 > scr: scr = scr1 last_size = size size *= incr continue else: incr = (incr + 1) / 2 size = last_size scr = radius(mid + evec * size) yield mid + evec * size, scr
def create_bvh(scene_object): """Creates the BVH of a given scene object. :param scene_object: A given scene object. :return: A reference to the BVH """ bm = bmesh.new() bm.from_mesh(scene_object.data) bm.transform(scene_object.matrix_world) object_bvh = BVHTree.FromBMesh(bm) bm.free() return object_bvh
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 = True # 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 update_bmesh_tree(self, context, update_index=False): self.bmesh = bmesh.from_edit_mesh(context.object.data) if update_index: # Verify layers are created for layer_name in UvDataLayers.LAYER_NAMES: layer_data = self.bmesh.faces.layers.int.get(layer_name) if layer_data is None: print('Creating face layer:', layer_name) self.bmesh.faces.layers.int.new(layer_name) for el in [self.bmesh.faces, self.bmesh.verts, self.bmesh.edges]: el.index_update() el.ensure_lookup_table() self.bmesh.loops.layers.uv.verify() self.bmesh = bmesh.from_edit_mesh(context.object.data) self.tree = BVHTree.FromBMesh(self.bmesh)
def find_nearest_normals(bm, target, debug=False): bmt = bmesh.new() bmt.from_mesh(target.data) bvh = BVH.FromBMesh(bmt) normals = {} for v in bm.verts: location, normal, index, distance = bvh.find_nearest(v.co) if debug: print(location, normal, index, distance) # if index: # target.data.polygons[index].select = True normals[v] = normal return normals, bmt
def update_bmesh_tree(self, context, update_index=False): self.bmesh = bmesh.from_edit_mesh(context.object.data) if update_index: # Verify layers are created layer_names = [ 'grid_index', 'grid_tile_id', 'grid_sel_width', 'grid_sel_height', 'paint_settings', 'grid_sel_origin' ] for layer_name in layer_names: layer_data = self.bmesh.faces.layers.int.get(layer_name) if layer_data is None: print('Creating face layer:', layer_name) self.bmesh.faces.layers.int.new(layer_name) for el in [self.bmesh.faces, self.bmesh.verts, self.bmesh.edges]: el.index_update() el.ensure_lookup_table() self.bmesh = bmesh.from_edit_mesh(context.object.data) self.tree = BVHTree.FromBMesh(self.bmesh)
def __init__(self, obj, max_adjacent=20): self.matrix = obj.matrix_world.copy() self.draw = DrawCallback() self.draw.matrix = self.matrix self.bm = bmesh.new() self.bm.from_mesh(obj.data) bmesh.ops.triangulate(self.bm, faces=self.bm.faces) self.bm.verts.ensure_lookup_table() self.bm.edges.ensure_lookup_table() self.bm.faces.ensure_lookup_table() self.hex_mode = False self.bvh = BVHTree.FromBMesh(self.bm) self.n = len(self.bm.verts) self.max_adjacent = max_adjacent self.singularities = [] self.locations = np.array([vert.co for vert in self.bm.verts], dtype=np.float32) self.normals = np.zeros((self.n, 3), dtype=np.float32) self.adjacent_counts = np.zeros((self.n,), dtype=np.float32) self.field = np.zeros((self.n, 3), dtype=np.float64) self.scale = np.zeros((self.n,), dtype=np.float64) self.curvature = np.zeros((self.n,), dtype=np.float64) self.weights = np.ones((self.n,), dtype=np.float64) self.connectivity = np.zeros((self.n, max_adjacent), dtype=np.int64) mask_layer = self.bm.verts.layers.paint_mask.verify() for vert in self.bm.verts: i = vert.index self.field[i] = curvature_direction(vert) self.normals[i] = vert_normal(vert) self.scale[i] = vert[mask_layer] self.curvature[i] = average_curvature(vert) self.adjacent_counts[i] = min(len(vert.link_edges), max_adjacent) if vert.is_boundary: self.weights[vert.index] = 0 for j, e in enumerate(vert.link_edges): if j >= max_adjacent: continue self.connectivity[i, j] = e.other_vert(vert).index
def intersection_from_bm(bm): bvh = BVHTree.FromBMesh(bm, epsilon=0.00001) bm_out = bmesh.new() faces = bm.faces for face1 in faces: for face2 in faces: if face1.index != face2.index: # edges of one against the others locs = get_intersections_faces(face1, face2) print(len(locs)) for loc in locs: bm_out.verts.new(loc) if len(locs) == 2: bm_out.edges.new(bm_out.verts[-2:]) return bm_out return bm_out
def __init__(self, context, bracket_data_manager): ''' Gets info from bracket manager and siplays orthogonal slices on the snap object ''' if not bracket_data_manager.bracket_obj: return None elif not bracket_data_manager.snap_ob: return None self.bracket_data = bracket_data_manager ob = self.bracket_data.snap_ob bme = bmesh.new() bme.from_object(ob, context.scene) self.snap_ob = ob self.bme = bme self.bvh = BVHTree.FromBMesh(self.bme) self.cut_pt = None self.cut_no_x = None self.cut_no_y = None self.slice_points_x = [] self.slice_points_y = [] self.reference_L = [] self.points_2d = [] self.active_point_2d = Vector((0, 0, 0)) self.mx = self.bracket_data.bracket_obj.matrix_world.to_3x3() b_gauge = self.bracket_data.bracket_obj.get('bracket_gauge') if b_gauge and not get_settings().bgauge_override: #read the prescription value from the objects self.b_gauge = b_gauge else: #override the rx value self.b_gauge = get_settings().bracket_gauge
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