def run(self): """ Replaces mesh objects with another mesh objects and scales them accordingly, the replaced objects and the objects to replace with in following steps: 1. Find which object to replace. 2. Place the new object in place of the object to be replaced and scale accordingly. 2. If there is no collision, between that object and the objects in the scene, then do replace and delete the original object. """ if self.config.has_param("relative_rotation_sampler"): def relative_pose_sampler(obj): # Sample random rotation and apply it to the objects pose obj.get_rotation().rotate( Euler(self.config.get_list("relative_rotation_sampler"))) else: relative_pose_sampler = None ObjectReplacer.replace_multiple( objects_to_be_replaced=MeshObject.convert_to_meshes( self.config.get_list("objects_to_be_replaced", [])), objects_to_replace_with=MeshObject.convert_to_meshes( self.config.get_list("objects_to_replace_with", [])), ignore_collision_with=MeshObject.convert_to_meshes( self.config.get_list("ignore_collision_with", [])), replace_ratio=self.config.get_float("replace_ratio", 1), copy_properties=self.config.get_float("copy_properties", 1), max_tries=self.config.get_int("max_tries", 100), relative_pose_sampler=relative_pose_sampler)
def sample(objects_to_sample: [MeshObject], sample_pose_func: Callable[[MeshObject], None], objects_to_check_collisions: [MeshObject] = None, max_tries: int = 1000): """ Samples positions and rotations of selected object inside the sampling volume while performing mesh and bounding box collision checks. :param objects_to_sample: A list of mesh objects whose poses are sampled based on the given function. :param sample_pose_func: The function to use for sampling the pose of a given object. :param objects_to_check_collisions: A list of mesh objects who should not be considered when checking for collisions. :param max_tries: Amount of tries before giving up on an object and moving to the next one. """ # After this many tries we give up on current object and continue with the rest if objects_to_check_collisions is None: objects_to_check_collisions = MeshObject.convert_to_meshes(get_all_blender_mesh_objects()) # Among objects_to_sample only check collisions against already placed objects cur_objects_to_check_collisions = list(set(objects_to_check_collisions) - set(objects_to_sample)) if max_tries <= 0: raise ValueError("The value of max_tries must be greater than zero: {}".format(max_tries)) if not objects_to_sample: raise Exception("The list of objects_to_sample can not be empty!") # cache to fasten collision detection bvh_cache = {} # for every selected object for obj in objects_to_sample: no_collision = True amount_of_tries_done = -1 # Try max_iter amount of times for i in range(max_tries): # Put the top object in queue at the sampled point in space sample_pose_func(obj) bpy.context.view_layer.update() # Remove bvh cache, as object has changed if obj.get_name() in bvh_cache: del bvh_cache[obj.get_name()] no_collision = CollisionUtility.check_intersections(obj, bvh_cache, cur_objects_to_check_collisions, []) # If no collision then keep the position if no_collision: amount_of_tries_done = i break # After placing an object, we will check collisions with it cur_objects_to_check_collisions.append(obj) if amount_of_tries_done == -1: amount_of_tries_done = max_tries if not no_collision: print("Could not place " + obj.get_name() + " without a collision.") else: print("It took " + str(amount_of_tries_done + 1) + " tries to place " + obj.get_name())
def run(self): """ Run this current module. """ # get all objects which material should be changed objects = MeshObject.convert_to_meshes( self.config.get_list("selector")) self.add_emission_to_materials(objects)
def run(self): """ :return: Point of interest in the scene. Type: mathutils.Vector. """ # For every selected object in the scene selected_objects = MeshObject.convert_to_meshes( self.config.get_list("selector", get_all_blender_mesh_objects())) if len(selected_objects) == 0: raise Exception("No objects were selected!") return MeshObject.compute_poi(selected_objects)
def run(self): """ Run this current module. """ # get all objects which material should be changed objects = MeshObject.convert_to_meshes(self.config.get_list("selector")) SurfaceLighting.run( objects, emission_strength=self.emission_strength, keep_using_base_color=self.keep_using_base_color, emission_color=self.emission_color )
def run(self): """ Samples positions and rotations of selected object inside the sampling volume while performing mesh and bounding box collision checks in the following steps: 1. While we have objects remaining and have not run out of tries - sample a point. 2. If no collisions are found keep the point. """ objects_to_sample = self.config.get_list( "objects_to_sample", get_all_blender_mesh_objects()) objects_to_check_collisions = self.config.get_list( "objects_to_check_collisions", get_all_blender_mesh_objects()) max_tries = self.config.get_int("max_iterations", 1000) def sample_pose(obj: MeshObject): obj.set_location(self.config.get_vector3d("pos_sampler")) obj.set_rotation_euler(self.config.get_vector3d("rot_sampler")) ObjectPoseSampler.sample( objects_to_sample=MeshObject.convert_to_meshes(objects_to_sample), sample_pose_func=sample_pose, objects_to_check_collisions=MeshObject.convert_to_meshes( objects_to_check_collisions), max_tries=max_tries)
def run(self): """ Samples based on the description above. :return: Sampled value. Type: mathutils.Vector """ # invoke a Getter, get a list of objects to manipulate objects = MeshObject.convert_to_meshes( self.config.get_list("to_sample_on")) if len(objects) == 0: raise Exception( "The used selector returns an empty list, check the self.config value: \"to_sample_on\"" ) # relative area on selected face where to sample points face_sample_range = self.config.get_vector2d("face_sample_range", [0.0, 1.0]) # min and max distance to the bounding box min_height = self.config.get_float("min_height", 0.0) max_height = self.config.get_float("max_height", 1.0) if max_height < min_height: raise Exception("The minimum height ({}) must be smaller " "than the maximum height ({})!".format( min_height, max_height)) use_ray_trace_check = self.config.get_bool('use_ray_trace_check', False) # the upper direction, to define what is up in the scene # is used to selected the correct face upper_dir = self.config.get_vector3d("upper_dir", [0.0, 0.0, 1.0]) upper_dir.normalize() # if this is true the up direction is determined by the upper_dir vector, if it is false the # face normal is used use_upper_dir = self.config.get_bool("use_upper_dir", True) return UpperRegionSampler.sample( objects_to_sample_on=objects, face_sample_range=face_sample_range, min_height=min_height, max_height=max_height, use_ray_trace_check=use_ray_trace_check, upper_dir=upper_dir, use_upper_dir=use_upper_dir)
def load(filepath: str, cached_objects: dict = None, **kwargs) -> List[MeshObject]: """ Import all objects for the given file and returns the loaded objects In .obj files a list of objects can be saved in. In .ply files only one object can saved so the list has always at most one element :param filepath: the filepath to the location where the data is stored :param cached_objects: a dict of filepath to objects, which have been loaded before, to avoid reloading (the dict is updated in this function) :param kwargs: all other params are handed directly to the bpy loading fct. check the corresponding documentation :return: The list of loaded mesh objects. """ if os.path.exists(filepath): if cached_objects is not None and isinstance(cached_objects, dict): if filepath in cached_objects.keys(): created_obj = [] for obj in cached_objects[filepath]: # duplicate the object created_obj.append(obj.duplicate()) return created_obj else: loaded_objects = ObjectLoader.load(filepath, cached_objects=None, **kwargs) cached_objects[filepath] = loaded_objects return loaded_objects else: # save all selected objects previously_selected_objects = set(bpy.context.selected_objects) if filepath.endswith('.obj'): # load an .obj file: bpy.ops.import_scene.obj(filepath=filepath, **kwargs) elif filepath.endswith('.ply'): # load a .ply mesh bpy.ops.import_mesh.ply(filepath=filepath, **kwargs) # add a default material to ply file mat = bpy.data.materials.new(name="ply_material") mat.use_nodes = True loaded_objects = list(set(bpy.context.selected_objects) - previously_selected_objects) for obj in loaded_objects: obj.data.materials.append(mat) # return all currently selected objects return MeshObject.convert_to_meshes(list(set(bpy.context.selected_objects) - previously_selected_objects)) else: raise Exception("The given filepath does not exist: {}".format(filepath))
def run(self): # use a loader module to load objects bpy.ops.object.select_all(action='SELECT') previously_selected_objects = set(bpy.context.selected_objects) module_list_config = self.config.get_list("used_loader_config") modules = Utility.initialize_modules(module_list_config) for module in modules: print("Running module " + module.__class__.__name__) module.run() bpy.ops.object.select_all(action='SELECT') loaded_objects = list( set(bpy.context.selected_objects) - previously_selected_objects) # only select non see through materials config = { "conditions": { "cp_is_cc_texture": True, "cf_principled_bsdf_Alpha_eq": 1.0 } } material_getter = MaterialProvider(Config(config)) all_cc_materials = Material.convert_to_materials(material_getter.run()) RandomRoomConstructor.construct( used_floor_area=self.used_floor_area, interior_objects=MeshObject.convert_to_meshes(loaded_objects), materials=all_cc_materials, amount_of_extrusions=self.amount_of_extrusions, fac_from_square_room=self.fac_from_square_room, corridor_width=self.corridor_width, wall_height=self.wall_height, amount_of_floor_cuts=self.amount_of_floor_cuts, only_use_big_edges=self.only_use_big_edges, create_ceiling=self.create_ceiling, assign_material_to_ceiling=self.assign_material_to_ceiling, placement_tries_per_face=self.tries_per_face, amount_of_objects_per_sq_meter=self.amount_of_objects_per_sq_meter)
def run(self): self.point_sampler = Front3DPointInRoomSampler( MeshObject.convert_to_meshes(get_all_blender_mesh_objects())) super().run()
def _sample_cam_poses(self, config): """ Samples camera poses according to the given config :param config: The config object """ cam_ob = bpy.context.scene.camera cam = cam_ob.data # Set global parameters self.sqrt_number_of_rays = config.get_int("sqrt_number_of_rays", 10) self.max_tries = config.get_int("max_tries", 10000) self.proximity_checks = config.get_raw_dict("proximity_checks", {}) self.excluded_objects_in_proximity_check = config.get_list( "excluded_objs_in_proximity_check", []) self.min_interest_score = config.get_float("min_interest_score", 0.0) self.interest_score_range = config.get_float("interest_score_range", self.min_interest_score) self.interest_score_step = config.get_float("interest_score_step", 0.1) self.special_objects = config.get_list("special_objects", []) self.special_objects_weight = config.get_float( "special_objects_weight", 2) self._above_objects = MeshObject.convert_to_meshes( config.get_list("check_if_pose_above_object_list", [])) self.check_visible_objects = MeshObject.convert_to_meshes( config.get_list("check_if_objects_visible", [])) # Set camera intrinsics self._set_cam_intrinsics( cam, Config(self.config.get_raw_dict("intrinsics", {}))) if self.proximity_checks: # needs to build an bvh tree mesh_objects = [ MeshObject(obj) for obj in get_all_blender_mesh_objects() if obj not in self.excluded_objects_in_proximity_check ] self.bvh_tree = MeshObject.create_bvh_tree_multi_objects( mesh_objects) if self.interest_score_step <= 0.0: raise Exception( "Must have an interest score step size bigger than 0") # Determine the number of camera poses to sample number_of_poses = config.get_int("number_of_samples", 1) print("Sampling " + str(number_of_poses) + " cam poses") # Start with max interest score self.interest_score = self.interest_score_range # Init all_tries = 0 tries = 0 existing_poses = [] for i in range(number_of_poses): # Do until a valid pose has been found or the max number of tries has been reached while tries < self.max_tries: tries += 1 all_tries += 1 # Sample a new cam pose and check if its valid if self.sample_and_validate_cam_pose(config, existing_poses): break # If max tries has been reached if tries >= self.max_tries: # Decrease interest score and try again, if we have not yet reached minimum continue_trying, self.interest_score = CameraValidation.decrease_interest_score( self.interest_score, self.min_interest_score, self.interest_score_step) if continue_trying: tries = 0 print(str(all_tries) + " tries were necessary")
def run(self): self.point_sampler = SuncgPointInRoomSampler( MeshObject.convert_to_meshes(bpy.context.scene.objects)) super().run()
def get_all_mesh_objects(): return MeshObject.convert_to_meshes(get_all_blender_mesh_objects())
def get_all_meshes_with_name(name: str): return MeshObject.convert_to_meshes([obj for obj in get_all_blender_mesh_objects() if obj.name == name])