def intersect_from_objects(a, b, depsgraph, eps_threshold=0.01): print(a.full_mesh, b.full_mesh) for acomp in a.full_mesh: acomp = BVHTree.FromObject(acomp, depsgraph, epsilon=eps_threshold) for bcomp in b.full_mesh: bcomp = BVHTree.FromObject(bcomp, depsgraph, epsilon=eps_threshold) print(acomp.overlap(bcomp)) if acomp.overlap(bcomp) != []: return True return False
def get_obj_mesh_bvht(obj, depsgraph, applyModifiers=True, world_space=True): if applyModifiers: if world_space: depsgraph.objects[obj.name].data.transform(obj.matrix_world) bvh = BVHTree.FromObject(obj, depsgraph) depsgraph.objects[obj.name].data.transform(obj.matrix_world.inverted()) return bvh else: return BVHTree.FromObject(obj, depsgraph) else: if world_space: return BVHTree.FromPolygons([obj.matrix_world @ v.co for v in obj.data.vertices], [p.vertices for p in obj.data.polygons]) else: return BVHTree.FromPolygons([v.co for v in obj.data.vertices], [p.vertices for p in obj.data.polygons])
def execute(self, context): self.points.clear() bvh = BVHTree.FromObject(context.object, context.depsgraph) # Get object data # TODO: Make these into properties stored external to the operator camera = bpy.data.objects['Camera'] # Find out which direction the camera is pointing angle_x = camera.data.angle_x angle_y = camera.data.angle_y self.points = self.scan(bvh, angle_x, angle_y, self.count_x, self.count_y, camera.location, camera.rotation_euler) try: exists = bpy.data.meshes['scan'] bpy.data.meshes.remove(exists) except KeyError: pass try: obj = bpy.data.objects['scan'] bpy.data.objects.remove(obj) except KeyError: pass # Add a mesh to the scene containing the points mesh = bpy.data.meshes.new("scan") mesh.from_pydata(self.points, [], []) obj = bpy.data.objects.new('scan', mesh) bpy.context.collection.objects.link(obj) # obj.select = False return {'FINISHED'}
def process(self): Points, Colors = self.inputs obj = bpy.data.objects[self.object_ref] # triangulate faces bvh = BVHTree.FromObject(obj, bpy.context.scene, deform=True, render=False, cage=False, epsilon=0.0) point = Points.sv_get()[0] color = Colors.sv_get()[0] ran = range(3) image = bpy.data.images[self.image] width, height = image.size uvMap = obj.data.uv_layers[0].data pixels = np.array(image.pixels[:]).reshape(width, height, 4) for P, C in zip(point, safc(point, color)): loc, norm, ind, dist = bvh.find_nearest(P) found_poly = obj.data.polygons[ind] verticesIndices = found_poly.vertices p1, p2, p3 = [ obj.data.vertices[verticesIndices[i]].co for i in ran ] uvMapIndices = found_poly.loop_indices uv1, uv2, uv3 = [uvMap[uvMapIndices[i]].uv.to_3d() for i in ran] V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3) Vx, Vy = int(V.x * (width - 1)), int(V.y * (height - 1)) pixels[Vy, Vx] = C image.pixels = pixels.flatten().tolist()
def CreateBVHTree(self, context): bvh = BVHTree.FromObject(self.ExtrudeObject, context.evaluated_depsgraph_get(), deform=False, cage=False, epsilon=0.0) self.BVHTree = bvh size = len(self.ExtrudeObject.data.vertices) kd = kdtree.KDTree(size) for i in self.ExtrudeObject.data.vertices: kd.insert(self.ExtrudeObject.matrix_world @ i.co.copy(), i.index) kd.balance() self.KDTree = kd size = len(self.MainObject.data.vertices) size2 = len(self.MainObject.data.edges) size3 = len(self.MainObject.data.polygons) kd2 = kdtree.KDTree(size + size2 + size3) for i in self.MainObject.data.vertices: kd2.insert(self.MainObject.matrix_world @ i.co, i.index) for i in self.MainObject.data.edges: pos = (self.MainObject.data.vertices[i.vertices[0]].co + self.MainObject.data.vertices[i.vertices[1]].co) / 2 kd2.insert(self.MainObject.matrix_world @ pos, i.index + size) for i in self.MainObject.data.polygons: kd2.insert(self.MainObject.matrix_world @ i.center, i.index + size + size2) kd2.balance() self.KDTreeSnap = kd2
def constructMapping(self): c = bpy.context owner_mesh = self.id_data if (not createmapping): return try: map_to = c.scene.objects[self.map_to_mesh] btree = BVHTree.FromObject(map_to, c.scene) n_count = len(owner_mesh.data.vertices) self.mapped_points.clear() for vid, v in enumerate(owner_mesh.data.vertices): mapped_point = self.mapped_points.add() x, y, z = v.co.to_tuple() co, n, i, d = btree.find_nearest(Vector((x, y, z))) #Also check if the normals deviation is < 45 degrees # if(co and n and i and d and (n.normalized().dot(v.normal.normalized()) > 0.75)): if (co and n and i and d and (n.normalized().dot(v.normal.normalized()) > 0.95)): # if(co and n and i and d): face = map_to.data.polygons[i] u, v, w, ratio, isinside, vid1, vid2, vid3 = getBarycentricCoordinateFromPolygonFace( co, face, map_to, snapping=False, extra_info=True) mapped_point.bary_ratios = [u, v, w] mapped_point.bary_indices = [vid1, vid2, vid3] else: mapped_point.is_valid = False except KeyError: print('MAP TO MESH NEEDS TO BE SET BEFORE CONSTRUCTING A MAPPING') raise
def get_obj_dup_meshes(obj_snap_mode, convert_instances, context, add_active_obj=False): """Get all meshes""" objects_array = None active_obj = context.active_object if obj_snap_mode == 'Selected': objects_array = [obj for obj in context.selected_objects if obj != active_obj] else: objects_array = [obj for obj in context.visible_objects if obj != active_obj] # add active obj if add_active_obj is True and active_obj: objects_array.append(active_obj) listObjMatrix = [] depsgraph = context.evaluated_depsgraph_get() for obj in objects_array: BVHTree.FromObject(obj, depsgraph) # Update BVHTree (FIX) if obj.type == 'MESH': listObjMatrix.append((obj, obj.matrix_world.copy())) # convert particles and dupligroups if convert_instances is True: for dup in depsgraph.object_instances: if dup.is_instance: # Real dupli instance obj_dupli = dup.instance_object listObjMatrix.append( (obj_dupli, dup.matrix_world.copy()) ) return listObjMatrix
def process(self): Points = self.inputs[1] Colors = self.outputs[0] if Colors.is_linked: dps = get_sv_depsgraph() obj = self.inputs[0].sv_get()[0] # triangulate faces bvh = BVHTree.FromObject(obj, dps) point = Points.sv_get()[0] outc = [] ran = range(3) image = bpy.data.images[self.image] width, height = image.size # Must be exactly the same vertically and horizontally, square image. pixels = np.array(image.pixels[:]).reshape(width, height, 4) uvMap = obj.data.uv_layers[0].data for P in point: loc, norm, ind, dist = bvh.find_nearest(P) found_poly = obj.data.polygons[ind] verticesIndices = found_poly.vertices p1, p2, p3 = [ obj.data.vertices[verticesIndices[i]].co for i in ran ] uvMapIndices = found_poly.loop_indices uv1, uv2, uv3 = [ uvMap[uvMapIndices[i]].uv.to_3d() for i in ran ] V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3) outc.append(pixels[int(V.y * (width - 1)), int(V.x * (height - 1))].tolist()) Colors.sv_set([outc])
def process(self): Points = self.inputs[0] Colors = self.outputs[0] if Colors.is_linked: obj = bpy.data.objects[self.object_ref] # triangulate faces bvh = BVHTree.FromObject(obj, bpy.context.scene, deform=True, render=False, cage=False, epsilon=0.0) point = Points.sv_get()[0] outc = [] ran = range(3) image = bpy.data.images[self.image] width, height = image.size pixels = np.array(image.pixels[:]).reshape(width, height, 4) uvMap = obj.data.uv_layers[0].data for P in point: loc, norm, ind, dist = bvh.find_nearest(P) found_poly = obj.data.polygons[ind] verticesIndices = found_poly.vertices p1, p2, p3 = [ obj.data.vertices[verticesIndices[i]].co for i in ran ] uvMapIndices = found_poly.loop_indices uv1, uv2, uv3 = [ uvMap[uvMapIndices[i]].uv.to_3d() for i in ran ] V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3) outc.append(pixels[int(V.x * (width - 1)), int(V.y * (height - 1))].tolist()) Colors.sv_set([outc])
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 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(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 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 __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 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 invoke(self, context, event): self.x1 = self.x2 = event.mouse_region_x self.y1 = self.y2 = event.mouse_region_y # Load the object's BVH, we'll use it for ray casting self.bvh = BVHTree.FromObject(context.vertex_paint_object, context.view_layer.depsgraph) # Draw the starting pixel draw_face_op_main(self, context) context.window_manager.modal_handler_add(self) return {"RUNNING_MODAL"}
def __init__(self, mesh_filepath, samples_filepath, n_rays=1000): bpy.ops.import_mesh.stl(filepath = mesh_filepath) self.mesh = bpy.context.object #BVH tree is a technique for speeding up the ray - mesh intersection calculations self.tree = BVHTree.FromObject(self.mesh, bpy.context.scene) self.samples = [] with open(samples_filepath) as samplesfile: rdr = csv.reader(samplesfile, quoting=csv.QUOTE_NONNUMERIC) for line in rdr: new_sample = Sample(location=Vector(line), n_rays=n_rays) self.samples.append(new_sample) for sample in self.samples: self.intersect_cosrays(sample=sample) sample.in_rock_lengths = get_lengths_from_intersections(sample.ray_intersections) sample.calculate_shielding_factor(particle_attenuation_length=208, m=2.2)
def getMappedContourSegments(context, subject, reference, isocontours, reference_meshnames=[]): bvhtree = BVHTree.FromObject(subject, context.scene); mappedcontours = []; references = []; if(len(subject.multimaps)): for mname in reference_meshnames: mappedcontours.append([]); references.append(bpy.data.objects[mname]); else: mappedcontours.append([]); for segment in isocontours: co_start = segment['start']; co_end = segment['end']; co_s, n, index1, distance = bvhtree.find(co_start); co_e, n, index2, distance = bvhtree.find(co_end); u1, v1, w1 = getBarycentricValue(context, subject, subject.data.polygons[index1], co_s); u2, v2, w2 = getBarycentricValue(context, subject, subject.data.polygons[index2], co_e); if(len(subject.multimaps)): for index, mmap in enumerate(subject.multimaps): reference = references[index]; map_co_s_1, map_co_s_2, map_co_s_3 = getTriangleMappedPoints(subject, reference, subject.data.polygons[index1], mmap.map_items); map_co_e_1, map_co_e_2, map_co_e_3 = getTriangleMappedPoints(subject, reference, subject.data.polygons[index2], mmap.map_items); map_co_start = getGeneralCartesianFromBarycentre([u1, v1, w1], [map_co_s_1, map_co_s_2, map_co_s_3]); map_co_end = getGeneralCartesianFromBarycentre([u2, v2, w2], [map_co_e_1, map_co_e_2, map_co_e_3]); mapped_segment = {'start':map_co_start, 'end':map_co_end, 'contour_index':segment['contour_index']}; mappedcontours[index].append(mapped_segment); else: map_co_s_1, map_co_s_2, map_co_s_3 = getTriangleMappedPoints(subject, reference, subject.data.polygons[index1]); map_co_e_1, map_co_e_2, map_co_e_3 = getTriangleMappedPoints(subject, reference, subject.data.polygons[index2]); map_co_start = getGeneralCartesianFromBarycentre([u1, v1, w1], [map_co_s_1, map_co_s_2, map_co_s_3]); map_co_end = getGeneralCartesianFromBarycentre([u2, v2, w2], [map_co_e_1, map_co_e_2, map_co_e_3]); mapped_segment = {'start':map_co_start, 'end':map_co_end, 'contour_index':segment['contour_index']}; mappedcontours[0].append(mapped_segment); return mappedcontours;
def mft_selected_objects_and_duplis(self, context): """Loop over (object, matrix) pairs (mesh only)""" listObjMatrix = [] depsgraph = context.evaluated_depsgraph_get() for obj in self.drawOnObjects: BVHTree.FromObject(obj, depsgraph) # Update BVHTree (FIX) if obj.type == 'MESH': listObjMatrix.append((obj, obj.matrix_world.copy())) # convert particles and dupligroups for dup in depsgraph.object_instances: if dup.is_instance: # Real dupli instance obj_dupli = dup.instance_object listObjMatrix.append((obj_dupli, dup.matrix_world.copy())) return listObjMatrix
def constructMappingBVH(self, owner_mesh, map_to): c = bpy.context btree = BVHTree.FromObject(map_to, c.scene) n_count = len(owner_mesh.data.vertices) self.mapped_points.clear() for vid, v in enumerate(owner_mesh.data.vertices): mapped_point = self.mapped_points.add() x, y, z = v.co.to_tuple() co, n, i, d = btree.find_nearest(Vector((x, y, z))) if (co and n and i and d): face = map_to.data.polygons[i] u, v, w, ratio, isinside, vid1, vid2, vid3 = getBarycentricCoordinateFromPolygonFace( co, face, map_to, snapping=False, extra_info=True) mapped_point.bary_ratios = [u, v, w] mapped_point.bary_indices = [vid1, vid2, vid3] else: mapped_point.is_valid = False self.mapping_is_valid = True return True
def start_object(self, obj): options = self.options context = self.context depsgraph = context.evaluated_depsgraph_get() # The object to bake. self.active_object = obj self.active_mesh = self.active_object.data # Objects that we'll check AO on. self.bake_cast_objects = BakeAO.get_cast_objects(self.context, self.options) print("{} object(s) contributing to bake of '{}'".format(len(self.bake_cast_objects), self.active_object.name)) print("Creating BVH trees...") # Finally, get all the BVH tree objects from each object. self.bake_object_cache = [(bake_obj, BVHTree.FromObject(bake_obj, depsgraph), bake_obj.matrix_world.inverted(), bake_obj.matrix_world.inverted().to_3x3()) for bake_obj in self.bake_cast_objects] # Make sure to set our seed here, too. np.random.seed(self.options.seed) self.points_to_bake = [] mesh = self.active_mesh mesh.calc_normals_split() print("Finding all points to be baked...") for poly in mesh.polygons: for poly_vertex_index in range(len(poly.vertices)): vertex_index = poly.vertices[poly_vertex_index] loop_index = poly.loop_indices[poly_vertex_index] self.points_to_bake.append(BakeVertexPoint(mesh.vertices[vertex_index].co, mesh.loops[loop_index].normal, vertex_index, loop_index)) self.last_point_index = 0 return False
def invoke(self, context, event): depsgraph = bpy.context.depsgraph ob = bpy.context.active_object obj_eval = depsgraph.objects.get(ob.name, None) particleObj = self.particleObj = obj_eval global EVAL_PARTICLE_OBJ EVAL_PARTICLE_OBJ = obj_eval # particleObj = self.particleObj = context.active_object self.diagonal = diagonal = pow(particleObj.dimensions[0], 2) + pow(particleObj.dimensions[1], 2) + \ pow(particleObj.dimensions[2], 2) # diagonal -to normalize some values self.sourceSurface_BVHT = BVHTree.FromObject( particleObj, context.depsgraph ) # only for chair with children - calculate in once on init self.sourceSurface_BVHT_world = get_obj_mesh_bvht(particleObj, context.depsgraph, applyModifiers=True, world_space=True) partsysMod = self.particleObj.particle_systems.active # use last diagonal = self.diagonal #find and add to ignore list particles with same root # pointsList_hair = [] # ignore_list = [] # for i,particle in enumerate(partsysMod.particles): # for strand point # if particle.hair_keys[0] not in pointsList_hair: # pointsList_hair.append(particle.hair_keys[0]) # DONE: exclude duplicates if first strand[0] in list already # else: # ignore_list.append(i) # self.particle_duplicates_ids = ignore_list bpy.ops.particle.select_all(action='SELECT') bpy.ops.particle.remove_doubles() bpy.ops.particle.select_all(action='DESELECT') self.create_hair(context) self._timer = context.window_manager.event_timer_add( 0.2, window=context.window) context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'}
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 bvhtree_from_object(self, context, object): # bm = bmesh.new() # mesh = object.to_mesh() # bm.from_mesh(mesh) # bm.transform(object.matrix_world) # bvhtree = BVHTree.FromBMesh(bm) # object.data.transform(object.matrix_world) # bpy.context.view_layer.depsgraph.update() # bm.free() # bvhtree = BVHTree.FromObject(object, bpy.context.view_layer.depsgraph ) snapSurface = object context.view_layer.depsgraph.objects[snapSurface.name].data.transform( snapSurface.matrix_world) sourceSurface_BVHT = BVHTree.FromObject(snapSurface, context.view_layer.depsgraph) context.view_layer.depsgraph.objects[snapSurface.name].data.transform( snapSurface.matrix_world.inverted()) return sourceSurface_BVHT
def execute(self, context): selected = bpy.context.selected_objects obj = selected[-1] surf = bpy.context.scene.objects['surface'] loc = bpy.context.scene.cursor_location bvh = BVHTree.FromObject(surf, bpy.context.scene) loc = surf.matrix_world.inverted() * loc (loc, normal, index, dist) = bvh.find_nearest(loc) if self.use_smooth: normal = smooth_normal(surf, loc, index) loc = surf.matrix_world * loc bpy.ops.object.duplicate() new_obj = bpy.context.selected_objects[-1] (unused, surf_rot, unused) = surf.matrix_world.decompose() (unused, obj_rot, scale) = obj.matrix_world.decompose() normal = surf_rot * normal vec = obj_rot * Vector((0.0, 0.0, 1.0)) q = vec.rotation_difference(normal) q = Quaternion().slerp(q, self.align_with_normal) mat_scale = Matrix() for i in range(3): mat_scale[i][i] = scale[i] new_obj.matrix_world = (Matrix.Translation(loc) * q.to_matrix().to_4x4() * obj_rot.to_matrix().to_4x4() * mat_scale) bpy.context.scene.objects.active = new_obj return {'FINISHED'}
def execute(self, context): settings = get_addon_preferences() align_meth = settings.align_meth start = time.time() align_obj = context.object base_obj = [ obj for obj in context.selected_objects if obj != align_obj ][0] base_bvh = BVHTree.FromObject(base_obj, context.scene) align_obj.rotation_mode = 'QUATERNION' vlist = [] #figure out if we need to do any inclusion/exclusion group_lookup = {g.name: g.index for g in align_obj.vertex_groups} if 'icp_include' in align_obj.vertex_groups: group = group_lookup['icp_include'] for v in align_obj.data.vertices: for g in v.groups: if g.group == group and g.weight > 0.9: vlist.append(v.index) elif 'icp_exclude' in align_obj.vertex_groups: group = group_lookup['icp_exclude'] for v in align_obj.data.vertices: v_groups = [g.group for g in v.groups] if group not in v_groups: vlist.append(v.index) else: for g in v.groups: if g.group == group and g.weight < 0.1: vlist.append(v.index) #unfortunate way to do this.. else: vlist = [v.index for v in align_obj.data.vertices] settings = get_addon_preferences() thresh = settings.min_start sample = settings.sample_fraction iters = settings.icp_iterations target_d = settings.target_d use_target = settings.use_target factor = round(1 / sample) n = 0 converged = False conv_t_list = [target_d * 2] * 5 #store last 5 translations conv_r_list = [None] * 5 while n < iters and not converged: (A, B, d_stats) = make_pairs(align_obj, base_obj, base_bvh, vlist, thresh, factor, calc_stats=use_target) if align_meth == '0': #rigid transform M = affine_matrix_from_points(A, B, shear=False, scale=False, usesvd=True) elif align_meth == '1': # rot, loc, scale M = affine_matrix_from_points(A, B, shear=False, scale=True, usesvd=True) new_mat = Matrix.Identity(4) for y in range(0, 4): for z in range(0, 4): new_mat[y][z] = M[y][z] align_obj.matrix_world = align_obj.matrix_world * new_mat trans = new_mat.to_translation() quat = new_mat.to_quaternion() align_obj.update_tag() context.scene.update() if d_stats: i = fmod(n, 5) conv_t_list[i] = trans.length conv_r_list[i] = abs(quat.angle) if all(d < target_d for d in conv_t_list): converged = True print('Converged in %s iterations' % str(n + 1)) print('Final Translation: %f ' % conv_t_list[i]) print('Final Avg Dist: %f' % d_stats[0]) print('Final St Dev %f' % d_stats[1]) print('Avg last 5 rotation angle: %f' % np.mean(conv_r_list)) n += 1 time_taken = time.time() - start if use_target and not converged: print('Maxed out iterations') print('Final Translation: %f ' % conv_t_list[i]) print('Final Avg Dist: %f' % d_stats[0]) print('Final St Dev %f' % d_stats[1]) print('Avg last 5 rotation angle: %f' % np.mean(conv_r_list)) print('Aligned obj in %f sec' % time_taken) return {'FINISHED'}
def execute(self, context): ch = bpy.context.active_object sel = bpy.context.selected_objects obj = sel[0] if sel[1] == ch else sel[1] amt = ch.parent bvh = BVHTree.FromObject(ch, bpy.context.scene) obj.vertex_groups.clear() for g in ch.vertex_groups: obj.vertex_groups.new(g.name) closest_idx = np.zeros(len(obj.data.vertices), dtype=np.int) closest_dist = np.zeros(len(obj.data.vertices)) for v in obj.data.vertices: loc = obj.matrix_world * v.co # to world loc = ch.matrix_world.inverted() * loc # to child (loc, normal, index, dist) = bvh.find_nearest(loc) # loc = ch.matrix_world * loc # to world # loc = obj.matrix_world.inverted() * loc # to obj # v.co = loc closest_idx[v.index] = index closest_dist[v.index] = dist ttl = 5 n_obj_v = len(obj.data.vertices) obj_connected = [[] for i in range(n_obj_v)] for e in obj.data.edges: v_1 = e.vertices[0] v_2 = e.vertices[1] obj_connected[v_1].append(v_2) obj_connected[v_2].append(v_1) n_ch_v = len(ch.data.vertices) ch_connected = [[] for i in range(n_ch_v)] for e in ch.data.edges: v_1 = e.vertices[0] v_2 = e.vertices[1] ch_connected[v_1].append(v_2) ch_connected[v_2].append(v_1) # reassigned = True '''for i in range(10): print('i:', i) reassigned = 0 for v in obj.data.vertices: if v.index % 100 == 0: print('v.index:', v.index, 'reassigned:', reassigned) for neigh in obj_connected[v.index]: # print('neigh:', neigh) delta = np.linalg.norm(v.co - obj.data.vertices[neigh].co) thresh = 50 * delta w_dist = _walk_dist(ch.data.vertices, closest_idx[neigh], closest_idx[v.index], ch_connected, thresh) # print('_walk_dist done') # delta = closest_dist[v.index] - closest_dist[neigh] if w_dist > thresh: closest_idx[v.index] = closest_idx[neigh] closest_dist[v.index] = np.linalg.norm( obj.data.vertices[v.index].co - ch.data.vertices[closest_idx[v.index]].co) reassigned += 1 # print('reassigned!') break if reassigned == 0: break''' for v in obj.data.vertices: # N = _neighbors(obj.data.vertices, v.index, ttl, connected) # dists = closest_dist[N] # indices = closest_idx[N] # order = np.argsort(dists) # dists = dists[order] # indices = indices[order] # med_dist = dists[len(N) // 2] # med_idx = indices[len(N) // 2] index = closest_idx[v.index] f_ch = ch.data.polygons[index] weights = [0.0] * len(obj.vertex_groups) n_vert = len(f_ch.vertices) for v_ch_idx in f_ch.vertices: v_ch = ch.data.vertices[v_ch_idx] for ge in v_ch.groups: weights[ge.group] += ge.weight for g in obj.vertex_groups: if weights[g.index] > 0: g.add([v.index], weights[g.index] / n_vert, 'ADD') obj.parent = amt obj.matrix_parent_inverse = amt.matrix_world.inverted() mod = obj.modifiers.new('Armature', 'ARMATURE') mod.object = amt return {'FINISHED'}
def execute_slow_ParallelTransport(self, context): snapTargetName = context.active_object.targetObjPointer snapTarget = bpy.data.objects[snapTargetName] Curve = context.active_object #apply transformation to prevetn 90 deg offset bug snapTarget.data.transform(snapTarget.matrix_world) if Curve.mode == 'EDIT': # to make transfrom() work in edit mode bpy.ops.object.mode_set(mode="OBJECT") Curve.data.transform(Curve.matrix_world) bpy.ops.object.mode_set(mode="EDIT") else: Curve.data.transform(Curve.matrix_world) if self.resetTilt: self.resetTiltFunction(Curve.data) curveData = Curve.data snapTarget_BVHT_tree = BVHTree.FromObject( snapTarget, context.depsgraph) # render eg use subsurf render settin for i, polyline in enumerate(curveData.splines): # for strand point strand_len = len( polyline.bezier_points) if polyline.type == 'BEZIER' else len( polyline.points) if polyline.type == 'NURBS' or polyline.type == 'POLY': if self.onlySelection: spline_selection_mask = np.zeros(strand_len, dtype=np.bool) polyline.points.foreach_get('select', spline_selection_mask) if not any(spline_selection_mask): continue # if not even one pointis selected points = polyline.points else: if self.onlySelection: spline_selection_mask = np.zeros(strand_len, dtype=np.bool) polyline.bezier_points.foreach_get('select_control_point', spline_selection_mask) if not any(spline_selection_mask): continue # if not even one point is selected points = polyline.bezier_points # helper for tangetnt function (to detect last point on cuve) prevAngle = 0 corrective_angles = np.zeros(strand_len, dtype=np.float16) current_tilt = np.zeros(strand_len, dtype=np.float16) points.foreach_get('tilt', current_tilt) (T, N) = parallel_transport_TNB(points) strand_Ts = [Vector((i)) for i in T] strand_Ns = [Vector((i)) for i in N] for j, (point_T, point_N, curvePoint) in enumerate(zip(strand_Ts, strand_Ns, points)): # for strand point pointOnMeshLoc, normSnapTarget, face_index, distance, isInside = \ self.find_nearest(curvePoint.co.xyz, snapTarget_BVHT_tree, 11) vecSurfaceHit = curvePoint.co.xyz - pointOnMeshLoc if isInside: # if curve point is outside snapSurface flip it vecSurfaceHit *= -1 vectSurfHitProjected90 = point_T.cross(vecSurfaceHit) vectSurfHitProjectedToTangent = vectSurfHitProjected90.cross( point_T) # angle = biTangentCurve.angle(vectSurfHitProjectedToTangent) #unsigned angle <0, 180> angle = self.angle_signed( point_N, vectSurfHitProjectedToTangent, point_T) - math.pi / 2 # a,b, vN - signed (-180, 180) corrective_angles[j] = angle + 1.57 # add 90deg fix prevAngle = angle if strand_len >= 4: corrective_angles[1] = (corrective_angles[2] + corrective_angles[3]) / 2 corrective_angles[0] = (corrective_angles[1] + corrective_angles[2]) / 2 elif strand_len == 3: corrective_angles[0] = (corrective_angles[1] + corrective_angles[2]) / 2 if self.onlySelection: current_tilt[spline_selection_mask] += corrective_angles[ spline_selection_mask] else: current_tilt = corrective_angles points.foreach_set('tilt', current_tilt) # in radians # manually smooth first two points cos they are usually broken snapTarget.data.transform(snapTarget.matrix_world.inverted()) if Curve.mode == 'EDIT': # to make transfrom() work in edit mode bpy.ops.object.mode_set(mode="OBJECT") Curve.data.transform(Curve.matrix_world.inverted()) bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) bpy.ops.object.mode_set(mode="EDIT") else: Curve.data.transform(Curve.matrix_world.inverted()) bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) return {"FINISHED"}
def execute(self, context): obj = bpy.context.active_object surf = bpy.context.scene.objects['surface'] growth = bpy.context.scene.objects['growth'] verts_growth = growth.data.vertices verts_surf = surf.data.vertices verts_obj = obj.data.vertices bvh_surf = BVHTree.FromObject(surf, bpy.context.scene) bvh_obj = BVHTree.FromObject(obj, bpy.context.scene) connected = [[] for i in range(len(verts_surf))] for e in surf.data.edges: connected[e.vertices[0]].append(e.vertices[1]) connected[e.vertices[1]].append(e.vertices[0]) obj_z = [v.co[2] for v in verts_obj] obj_h = max(obj_z) - min(obj_z) print('obj_h:', obj_h) obj_radius = [np.linalg.norm([v.co[0], v.co[1], 0]) for v in verts_obj] obj_radius = np.max(obj_radius) print('obj_radius:', obj_radius) loc = growth.matrix_world * verts_growth[-1].co loc = surf.matrix_world.inverted() * loc (loc, normal, index, dist) = bvh_surf.find_nearest(loc) dist = [ np.linalg.norm(verts_surf[v].co - loc) for v in surf.data.polygons[index].vertices ] v_from = surf.data.polygons[index].vertices[np.argmin(dist)] f_from = index print('v_from:', v_from, 'f_from:', f_from) loc = bpy.context.scene.cursor_location loc = surf.matrix_world.inverted() * loc (loc, normal, index, dist) = bvh_surf.find_nearest(loc) dist = [ np.linalg.norm(verts_surf[v].co - loc) for v in surf.data.polygons[index].vertices ] v_to = surf.data.polygons[index].vertices[np.argmin(dist)] f_to = index print('v_to:', v_to, 'f_to:', f_to) (cumdist, path) = _dijkstra(verts_surf, v_from, v_to, connected) for i in range(1, len(path)): v = verts_surf[path[i]] z = cumdist[i] obj_z = np.mod(z, obj_h) print('v.co:', v.co, 'z:', z, 'obj_z:', obj_z) (loc, normal, index, dist) = bvh_surf.find_nearest(v.co) normal = _smooth_normal(surf, loc, index) radius = [] for angle in np.linspace(0, 2 * np.pi, 10)[:-1]: dx = np.cos(angle) dy = np.sin(angle) (loc, _, _, _) = bvh_obj.ray_cast( Vector((dx * obj_radius * 2, dy * obj_radius * 2, obj_z)), Vector((-dx, -dy, 0))) radius.append(np.linalg.norm([loc[0], loc[1], 0])) print('radius:', radius) radius = np.max(radius) verts_growth.add(1) verts_growth[-1].co = v.co + Vector(radius * normal) return {'FINISHED'}
def invoke(self, context, event): active_obj = context.active_object sourceSurface = None self.source_grid_mesh = None if active_obj.type == 'CURVE': if active_obj.hair_grid_settings.was_created_from_grid and active_obj.targetObjPointer in bpy.data.objects.keys( ): # obtain source grid surface, that hair was generated from self.source_curve = active_obj.name # somewho if I refrence sourceSurface, then in execute it is lost. So use name instead sourceSurface = bpy.data.objects[active_obj.targetObjPointer] else: self.report({ 'INFO' }, 'Selected is not recognized as generated from grid surface. Cancelling' ) return {"CANCELLED"} elif active_obj.type == 'MESH': for face in active_obj.data.polygons: if len(face.edge_keys) != 4: self.report({ 'INFO' }, 'Non quad polygon detected. This operation works on quad only meshes' ) return {"CANCELLED"} sourceSurface = active_obj if sourceSurface is None: self.report({ 'INFO' }, 'Select grid mesh type or generated curve hairs first. Cancelling' ) return {"CANCELLED"} if self.source_curve: #if operator wa executed on curve use its settigns self.load_settings(bpy.data.objects[ self.source_curve]) #load settings from cure hairs else: self.load_settings(sourceSurface) #else from target mesh # Get a BMesh representation me = sourceSurface.data bm = bmesh.new() # create an empty BMesh bm.from_mesh(me) bm.edges.ensure_lookup_table() sharp_edges = [e for e in bm.edges if not e.smooth] if len(sharp_edges) == 0: self.report( {'INFO'}, 'No edges marked as sharp! Mark one border edge loop as sharp') bm.free() return {"CANCELLED"} sharp_boundary_edges = [e for e in sharp_edges if e.is_boundary] if len(sharp_boundary_edges) == 0: self.report({ 'INFO' }, 'None of sharp edges are boundary edges! Mark one border edge loop as sharp' ) bm.free() return {"CANCELLED"} if len(sharp_boundary_edges) == 1: self.hairMethod = 'vert' bm.free() self.sourceSurface_BVHT = BVHTree.FromObject( sourceSurface, context.depsgraph) # TODO: broken in 2.8 # to normalize some values self.diagonal = math.sqrt( pow(sourceSurface.dimensions[0], 2) + pow(sourceSurface.dimensions[1], 2) + pow(sourceSurface.dimensions[2], 2)) self.source_grid_mesh = sourceSurface.name # somewho if I refrence sourceSurface, then in execute it is lost. So use name instead return self.execute(context)