def _init_object(c: Controller, name: str, pos: Dict[str, float], rot: Dict[str, float]) -> List[dict]: """ :param c: The controller. :param name: The name of the model. :param pos: The initial position of the model. :param rot: The initial rotation of the model. :return: A list of commands to instantiate an object from ObjectInfo values. """ o_id = c.get_unique_id() Scene.OBJECT_IDS.update({o_id: name}) info = Scene._OBJECT_INFO[name] return [c.get_add_object(name, object_id=o_id, position=pos, rotation=rot, library=info.library), {"$type": "set_mass", "id": o_id, "mass": info.mass}, {"$type": "set_physic_material", "id": o_id, "bounciness": info.bounciness, "static_friction": 0.1, "dynamic_friction": 0.8}]
def start(c: Controller) -> None: """ Start the controller. :param c: The controller. """ c.start() c.communicate([{ "$type": "simulate_physics", "value": False }, { "$type": "create_empty_environment" }, { "$type": "set_render_quality", "render_quality": 0 }, { "$type": "set_post_process", "value": False }, { "$type": "create_avatar", "id": "a", "type": "A_Img_Caps_Kinematic" }, { "$type": "set_pass_masks", "pass_masks": ["_img"] }])
def start(c: Controller) -> None: """ Start the controller. :param c: The controller. """ print(f"Results will be saved to: {MissingMaterials.OUTPUT_FILE}") c.start() c.communicate([{ "$type": "simulate_physics", "value": False }, { "$type": "create_empty_environment" }, { "$type": "set_render_quality", "render_quality": 0 }, { "$type": "set_post_process", "value": False }, { "$type": "create_avatar", "id": "a", "type": "A_Img_Caps_Kinematic" }, { "$type": "set_pass_masks", "pass_masks": ["_img"] }])
def run(self, drag_on_land, angular_drag_on_land): self.start() self.communicate(TDWUtils.create_empty_room(40, 40)) # Create the avatar. self.communicate(TDWUtils.create_avatar(avatar_type="A_Simple_Body", position={"x": 0, "y": 1, "z": 0})) # When the y value of the avatar's position is this value, the avatar is on the ground. ground_y = 1 # When the y value of the avatar's position exceeds ground_y by this much, it is in the air. in_air_threshold = 0.05 # If true, the avatar is in the air. is_in_air = False # Set high default drag values. # Set a low mass. # Apply a force. # Request avatar data. resp = self.communicate([{"$type": "set_avatar_drag", "avatar_id": "a", "drag": 30, "angular_drag": 80}, {"$type": "send_avatars", "frequency": "always"}, {"$type": "apply_force_to_avatar", "avatar_id": "a", "direction": {"x": 0.3, "y": 0.7, "z": 0}, "magnitude": 900}]) for i in range(500): x, y, z = AvatarSimpleBody(resp[0]).get_position() # If the avatar just launched in to the air, set its drag values to 0. if y > ground_y + in_air_threshold and not is_in_air: is_in_air = True resp = self.communicate({"$type": "set_avatar_drag", "avatar_id": "a", "drag": 0, "angular_drag": 0}) print("The avatar is in the air on frame: " + str(Controller.get_frame(resp[-1]))) # If the avatar just landed on the ground, set drag values. elif y <= ground_y + in_air_threshold and is_in_air: resp = self.communicate({"$type": "set_avatar_drag", "avatar_id": "a", "drag": drag_on_land, "angular_drag": angular_drag_on_land}) is_in_air = False print("The avatar is on the ground on frame: " + str(Controller.get_frame(resp[-1]))) # Wait. else: resp = self.communicate({"$type": "do_nothing"})
def _initialize_scene(self, c: Controller) -> List[dict]: commands = super()._initialize_scene(c) model_name = self._get_model_name() o_id = c.get_unique_id() Scene.OBJECT_IDS.update({o_id: model_name}) commands.extend([c.get_add_object(model_name, object_id=o_id, library=self._get_library()), {"$type": "set_mass", "id": o_id, "mass": 1000}, {"$type": "set_physic_material", "id": o_id, "bounciness": Scene._OBJECT_INFO[model_name].bounciness, "static_friction": 0.1, "dynamic_friction": 0.8}]) return commands
def add_transforms_object(self, record: ModelRecord, position: Dict[str, float], rotation: Dict[str, float], o_id: Optional[int] = None) -> dict: """ This is a wrapper for `Controller.get_add_object()` and the `add_object` command. This caches the ID of the object so that it can be easily cleaned up later. :param record: The model record. :param position: The initial position of the object. :param rotation: The initial rotation of the object, in Euler angles. :param o_id: The unique ID of the object. If None, a random ID is generated. :return: An `add_object` command. """ if o_id is None: o_id: int = Controller.get_unique_id() # Log the static data. self.object_ids = np.append(self.object_ids, o_id) return { "$type": "add_object", "name": record.name, "url": record.get_url(), "scale_factor": record.scale_factor, "position": position, "rotation": rotation, "category": record.wcategory, "id": o_id }
def set_visual_material(c: Controller, substructure: List[dict], object_id: int, material: str, quality="med") -> List[dict]: """ :param c: The controller. :param substructure: The metadata substructure of the object. :param object_id: The ID of the object in the scene. :param material: The name of the new material. :param quality: The quality of the material. :return A list of commands to set ALL visual materials on an object to a single material. """ commands = [] for sub_object in substructure: for i in range(len(sub_object["materials"])): commands.extend([ c.get_add_material(material, library="materials_" + quality + ".json"), { "$type": "set_visual_material", "id": object_id, "material_name": material, "object_name": sub_object["name"], "material_index": i } ]) return commands
def get_image(self, record: ModelRecord): o_id = Controller.get_unique_id() self.communicate({"$type": "add_object", "name": record.name, "url": record.get_url(), "scale_factor": record.scale_factor, "rotation": record.canonical_rotation, "id": o_id}) s = TDWUtils.get_unit_scale(record) * 2 # Scale the model and get an image. # Look at the model's centroid. resp = self.communicate([{"$type": "scale_object", "id": o_id, "scale_factor": {"x": s, "y": s, "z": s}}, {"$type": "look_at", "avatar_id": "a", "object_id": o_id, "use_centroid": True}]) # Destroy the model and unload the asset bundle. self.communicate([{"$type": "destroy_object", "id": o_id}, {"$type": "unload_asset_bundles"}]) return Images(resp[0]), resp[-1]
def get_random_position_on_nav_mesh( c: Controller, width: float, length: float, x_e=0, z_e=0, bake=True, rng=random.uniform) -> Tuple[float, float, float]: """ Returns a random position on a NavMesh. :param c: The controller. :param width: The width of the environment. :param length: The length of the environment. :param bake: If true, send bake_nav_mesh. :param rng: Random number generator. :param x_e: The x position of the environment. :param z_e: The z position of the environment. :return The coordinates as a tuple `(x, y, z)` """ if bake: c.communicate({'$type': 'bake_nav_mesh'}) # Try to find a valid position on the NavMesh. is_on = False x, y, z = (0, 0, 0) while not is_on: # Get a random position. x = rng(-width / 2, width / 2) + x_e z = rng(-length / 2, length / 2) + z_e resp = c.communicate({ '$type': 'send_is_on_nav_mesh', 'position': { 'x': x, 'y': 0, 'z': z }, 'max_distance': 4.0 }) answer = IsOnNavMesh(resp[0]) is_on = answer.get_is_on() x, y, z = answer.get_position() return x, y, z
def run(): # Create the asset bundle and the record. asset_bundle_paths, record_path = AssetBundleCreator( ).create_asset_bundle("cube.fbx", True, 123, "", 1) # Get the name of the bundle for this platform. For example, Windows -> "StandaloneWindows64" bundle = SYSTEM_TO_UNITY[system()] # Get the correct asset bundle path. for p in asset_bundle_paths: # Get the path to the asset bundle. if bundle in str(p.parent.resolve()): url = "file:///" + str(p.resolve()) # Launch the controller. c = Controller() c.start() # Create the environment. # Add the object. commands = [{ "$type": "create_empty_environment" }, { "$type": "add_object", "name": "cube", "url": url, "scale_factor": 1, "id": c.get_unique_id() }] # Create the avatar. commands.extend( TDWUtils.create_avatar(position={ "x": 0, "y": 0, "z": -3.6 })) c.communicate(commands) return
def __init__(self, model_name: str, initial_position: Dict[str, float]): """ :param model_name: The name of the 3D model in the model library. :param initial_position: The initial position of the object. """ self.object_id = Controller.get_unique_id() self.initial_position = initial_position self.model_name = model_name
def run(c: Controller) -> None: """ Check every model for missing materials. :param c: The controller. """ # Create a new output file. if MissingMaterials.OUTPUT_FILE.exists(): MissingMaterials.OUTPUT_FILE.unlink() MissingMaterials.OUTPUT_FILE = str( MissingMaterials.OUTPUT_FILE.resolve()) MissingMaterials.start(c) print( f"The names of models with missing materials will be saved to: {MissingMaterials.OUTPUT_FILE}" ) for library_path in ModelLibrarian.get_library_filenames(): print(library_path) lib = ModelLibrarian(library=library_path) pbar = tqdm(total=len(lib.records)) for record in lib.records: if record.do_not_use: pbar.update(1) continue pbar.set_description(record.name) # Check for missing materials. if MissingMaterials.materials_are_missing( c, record, record.get_url()): with io.open(MissingMaterials.OUTPUT_FILE, "at") as f: f.write("\n" + record.name) # Cleanup. c.communicate([{ "$type": "destroy_object", "id": MissingMaterials.OBJECT_ID }, { "$type": "unload_asset_bundles" }]) pbar.update(1) pbar.close() c.communicate({"$type": "terminate"})
def get_commands(self) -> Tuple[int, List[dict]]: """ :return: Tuple: The ID of the object; a list of commands to create the object: `[add_object, rotate_object_to, scale_object, set_kinematic_state, set_object_collision_detection_mode]` """ record = TransformInitData.LIBRARIES[self.library].get_record( name=self.name) object_id = Controller.get_unique_id() commands = [{ "$type": "add_object", "name": record.name, "url": record.get_url(), "scale_factor": record.scale_factor, "position": self.position, "category": record.wcategory, "id": object_id }] # The rotation is a quaternion. if "w" in self.rotation: commands.append({ "$type": "rotate_object_to", "rotation": self.rotation, "id": object_id }) # The rotation is in Euler angles. else: commands.append({ "$type": "rotate_object_to_euler_angles", "euler_angles": self.rotation, "id": object_id }) commands.extend([{ "$type": "scale_object", "scale_factor": self.scale_factor, "id": object_id }, { "$type": "set_kinematic_state", "id": object_id, "is_kinematic": self.kinematic, "use_gravity": self.gravity }]) # Kinematic objects must be continuous_speculative. if self.kinematic: commands.append({ "$type": "set_object_collision_detection_mode", "id": object_id, "mode": "continuous_speculative" }) return object_id, commands
def _initialize_scene(self, c: Controller) -> List[dict]: c.model_librarian = ModelLibrarian("models_full.json") commands = super()._initialize_scene(c) # Add a table, chair, and boxes. commands.extend(self._init_object(c, "b05_table_new", pos={"x": 0, "y": 0, "z": 4.33}, rot=TDWUtils.VECTOR3_ZERO)) commands.extend(self._init_object(c, "chair_willisau_riale", pos={"x": 0, "y": 0, "z": 3.7}, rot=TDWUtils.VECTOR3_ZERO)) commands.extend(self._init_object(c, "iron_box", pos={"x": 0.13, "y": 0.65, "z": 4.83}, rot=TDWUtils.VECTOR3_ZERO)) commands.extend(self._init_object(c, "iron_box", pos={"x": -0.285, "y": 1.342, "z": 4.79}, rot={"x": 90, "y": 0, "z": 0})) # Add a shelf with a custom scale. shelf_id = c.get_unique_id() shelf_name = "metal_lab_shelf" Scene.OBJECT_IDS.update({shelf_id: shelf_name}) commands.extend([c.get_add_object(shelf_name, object_id=shelf_id, rotation={"x": 0, "y": -90, "z": 0}, position={"x": 0, "y": 0, "z": 4.93}), {"$type": "set_mass", "id": shelf_id, "mass": 400}, {"$type": "set_physic_material", "id": shelf_id, "bounciness": Scene._OBJECT_INFO[shelf_name].bounciness, "static_friction": 0.1, "dynamic_friction": 0.8}, {"$type": "scale_object", "id": shelf_id, "scale_factor": {"x": 1, "y": 1.5, "z": 1.8}}]) return commands
def _initialize_scene(self, c: Controller) -> List[dict]: c.model_librarian = ModelLibrarian("models_full.json") # Initialize the scene. commands = super()._initialize_scene(c) chair_name = "brown_leather_dining_chair" # Create the the table. commands.extend(self._init_object(c=c, name="quatre_dining_table", pos=TDWUtils.VECTOR3_ZERO, rot=TDWUtils.VECTOR3_ZERO)) # Create 8 chairs around the table. commands.extend(self._init_object(c=c, name=chair_name, pos={"x": 0, "y": 0, "z": -1.55}, rot={"x": 0, "y": 0, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": 0, "y": 0, "z": 1.55}, rot={"x": 0, "y": 180, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": -1, "y": 0, "z": -0.85}, rot={"x": 0, "y": 90, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": -1, "y": 0, "z": 0}, rot={"x": 0, "y": 90, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": -1, "y": 0, "z": 0.85}, rot={"x": 0, "y": 90, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": 1, "y": 0, "z": -0.85}, rot={"x": 0, "y": -90, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": 1, "y": 0, "z": 0}, rot={"x": 0, "y": -90, "z": 0})) commands.extend(self._init_object(c=c, name=chair_name, pos={"x": 1, "y": 0, "z": 0.85}, rot={"x": 0, "y": -90, "z": 0})) return commands
def precalculate_movements() -> None: """ Precalculate random movements for the avatar before running this test. This way the movements are "random" per frame but the same per trial. """ frames: List[List[dict]] = list() for i in range(num_frames): # Move and turn randomly. commands = [{ "$type": "move_avatar_forward_by", "magnitude": uniform(50, 100) }, { "$type": "rotate_avatar_by", "angle": uniform(-45, 45), "axis": "yaw", "is_world": True, "avatar_id": "a" }] # Bend arm joints randomly. for j in Baby.JOINTS: commands.append({ "$type": "bend_arm_joint_by", "angle": uniform(0, 89), "joint": j.joint, "axis": j.axis }) for is_left in [True, False]: if random() > 0.5: commands.append({ "$type": "pick_up_proximity", "distance": 3, "grip": 1000, "is_left": is_left }) else: commands.append({"$type": "put_down", "is_left": is_left}) frames.append(commands) movements = {"id": Controller.get_unique_id(), "frames": frames} VarianceAvatar.FRAME_PATH.write_text(json.dumps(movements))
def _orbit_and_capture_image(c: Controller, x: float, y: float, z: float) -> bool: """ Orbit around an object and check for missing materials. :param c: The controller. :param x: The next x positional coordinate. :param y: The next y positional coordinate. :param z: The next z positional coordinate. :return: True if there is a missing material in the image, False otherwise. """ # Teleport the avatar. # Look at the model. # Receive an image. resp = c.communicate([{ "$type": "teleport_avatar_to", "position": { "x": x, "y": y, "z": z } }, { "$type": "look_at", "object_id": MissingMaterials.OBJECT_ID, "use_centroid": True }]) # Check if there are any pink pixels. images = Images(resp[0]) img = Image.open(BytesIO(images.get_image(0))) for c in img.getcolors(maxcolors=100000): if c[1] == MissingMaterials.HELL_PINK: return True return False
from tdw.controller import Controller """ A minimal example of how to connect to the build and receive data. """ if __name__ == "__main__": Controller() print("Everything is OK!")
f"The names of models with missing materials will be saved to: {MissingMaterials.OUTPUT_FILE}" ) for library_path in ModelLibrarian.get_library_filenames(): print(library_path) lib = ModelLibrarian(library=library_path) pbar = tqdm(total=len(lib.records)) for record in lib.records: if record.do_not_use: pbar.update(1) continue pbar.set_description(record.name) # Check for missing materials. if MissingMaterials.materials_are_missing( c, record, record.get_url()): with io.open(MissingMaterials.OUTPUT_FILE, "at") as f: f.write("\n" + record.name) # Cleanup. c.communicate([{ "$type": "destroy_object", "id": MissingMaterials.OBJECT_ID }, { "$type": "unload_asset_bundles" }]) pbar.update(1) pbar.close() c.communicate({"$type": "terminate"}) if __name__ == "__main__": MissingMaterials.run(Controller())
f"The names of models with missing materials will be saved to: {MissingMaterials.OUTPUT_FILE}" ) for library_path in ModelLibrarian.get_library_filenames(): print(library_path) lib = ModelLibrarian(library=library_path) pbar = tqdm(total=len(lib.records)) for record in lib.records: if record.do_not_use: pbar.update(1) continue pbar.set_description(record.name) # Check for missing materials. if MissingMaterials.materials_are_missing( c, record, record.get_url()): with io.open(MissingMaterials.OUTPUT_FILE, "at") as f: f.write("\n" + record.name) # Cleanup. c.communicate([{ "$type": "destroy_object", "id": MissingMaterials.OBJECT_ID }, { "$type": "unload_asset_bundles" }]) pbar.update(1) pbar.close() c.communicate({"$type": "terminate"}) if __name__ == "__main__": MissingMaterials.run(Controller(launch_build=False))
import json from tdw.controller import Controller from tdw.tdw_utils import TDWUtils from tdw.output_data import CompositeObjects, SegmentationColors from sticky_mitten_avatar.util import get_data """ Get default audio data for each sub-object of a composite object. """ if __name__ == "__main__": from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("--model", default="puzzle_box_composite") args = parser.parse_args() c = Controller() c.start() resp = c.communicate([ TDWUtils.create_empty_room(12, 12), c.get_add_object(model_name=args.model, object_id=0), { "$type": "send_composite_objects" }, { "$type": "send_segmentation_colors" } ]) c.communicate({"$type": "terminate"}) # Get the name of each object. colors = get_data(resp=resp, d_type=SegmentationColors) names = dict() for i in range(colors.get_num()):
def get_trial_initialization_commands(self) -> List[dict]: self._table_id = Controller.get_unique_id() # Teleport the avatar. commands = [{ "$type": "teleport_avatar_to", "position": random.choice(_TableScripted._CAMERA_POSITIONS) }, { "$type": "look_at_position", "position": { "x": -10.8, "y": _TableScripted._TABLE_HEIGHT, "z": -5.5 } }] # Add the table. commands.extend( self.add_physics_object_default(name="quatre_dining_table", position=self._TABLE_POSITION, rotation={ "x": 0, "y": -90, "z": 0 }, o_id=self._table_id)) x0 = -9.35 x1 = -9.9 x2 = -10.15 x3 = -10.8 x4 = -11.55 x5 = -11.8 x6 = -12.275 z0 = -4.5 z1 = -5.05 z2 = -5.45 z3 = -5.95 z4 = -6.475 # Add chairs. for x, z, rot in zip([x2, x3, x4, x6, x4, x3, x2, x0], [z0, z0, z0, z2, z4, z4, z4, z2], [180, 180, 180, 90, 0, 0, 0, -90]): commands.extend( self.add_physics_object_default( name="brown_leather_dining_chair", position={ "x": x, "y": _TableScripted._FLOOR_HEIGHT, "z": z }, rotation={ "x": 0, "y": rot, "z": 0 })) # Add plates. plates_x = [x2, x3, x4, x5, x4, x3, x2, x1] plates_z = [z1, z1, z1, z2, z3, z3, z3, z2] for x, z in zip(plates_x, plates_z): commands.extend( self.add_physics_object_default( name="plate05", position={ "x": x, "y": _TableScripted._TABLE_HEIGHT, "z": z }, rotation=TDWUtils.VECTOR3_ZERO)) # Cutlery offset from plate (can be + or -). cutlery_off = 0.1 cutlery_rots = [180, 180, 180, 90, 0, 0, 0, -90] # Forks. fork_x_offsets = [ cutlery_off, cutlery_off, cutlery_off, 0, -cutlery_off, -cutlery_off, -cutlery_off, 0 ] fork_z_offsets = [0, 0, 0, cutlery_off, 0, 0, 0, -cutlery_off] forks_x = list(map(add, plates_x, fork_x_offsets)) forks_z = list(map(add, plates_z, fork_z_offsets)) for x, z, rot in zip(forks_x, forks_z, cutlery_rots): commands.extend( self.add_physics_object_default( name="vk0010_dinner_fork_subd0", position={ "x": x, "y": _TableScripted._TABLE_HEIGHT, "z": z }, rotation={ "x": 0, "y": rot, "z": 0 })) # Knives. knife_x_offsets = [ -cutlery_off, -cutlery_off, -cutlery_off, 0, cutlery_off, cutlery_off, cutlery_off, 0 ] knife_z_offsets = [0, 0, 0, -cutlery_off, 0, 0, 0, cutlery_off] knives_x = list(map(add, plates_x, knife_x_offsets)) knives_z = list(map(add, plates_z, knife_z_offsets)) for x, z, rot in zip(knives_x, knives_z, cutlery_rots): commands.extend( self.add_physics_object_default( name="vk0007_steak_knife", position={ "x": x, "y": _TableScripted._TABLE_HEIGHT, "z": z }, rotation={ "x": 0, "y": rot, "z": 0 })) incidental_names = [ "moet_chandon_bottle_vray", "peppermill", "salt_shaker", "coffeemug", "coffeecup004", "bowl_wood_a_01", "glass1", "glass2", "glass3" ] incidental_positions = [{ "x": -10.35, "y": _TableScripted._TABLE_HEIGHT, "z": -5.325 }, { "x": -10.175, "y": _TableScripted._TABLE_HEIGHT, "z": -5.635 }, { "x": -11.15, "y": _TableScripted._TABLE_HEIGHT, "z": -5.85 }, { "x": -11.525, "y": _TableScripted._TABLE_HEIGHT, "z": -5.625 }, { "x": -11.25, "y": _TableScripted._TABLE_HEIGHT, "z": -5.185 }, { "x": -10.5, "y": _TableScripted._TABLE_HEIGHT, "z": -5.05 }] random.shuffle(incidental_names) random.shuffle(incidental_positions) # Select 4 incidental objects. for i in range(4): name = incidental_names.pop(0) o_id = Controller.get_unique_id() commands.extend( self.add_physics_object_default( name=name, position=incidental_positions.pop(0), rotation=TDWUtils.VECTOR3_ZERO, o_id=o_id)) # These objects need further scaling. if name in ["salt_shaker", "peppermill"]: commands.append({ "$type": "scale_object", "id": o_id, "scale_factor": { "x": 0.254, "y": 0.254, "z": 0.254 } }) # Select 2 bread objects. bread_names = ["bread", "bread_01", "bread_02", "bread_03"] bread_positions = [{ "x": x2, "y": _TableScripted._TABLE_HEIGHT, "z": z2 }, { "x": x4, "y": _TableScripted._TABLE_HEIGHT, "z": z2 }, { "x": x3, "y": _TableScripted._TABLE_HEIGHT, "z": z2 }] random.shuffle(bread_names) random.shuffle(bread_positions) for i in range(2): commands.extend( self.add_physics_object_default( name=bread_names.pop(0), position=bread_positions.pop(0), rotation=TDWUtils.VECTOR3_ZERO)) return commands
from tdw.controller import Controller c = Controller() print("Alles ist gut!") c.communicate({"$type": "terminate"})
from pathlib import Path from tdw.controller import Controller from tdw.tdw_utils import TDWUtils from tdw.librarian import ModelLibrarian from tdw.output_data import OutputData, Bounds, Images """ 1. Add a table and place an object on the table. 2. Add a camera and receive an image. """ lib = ModelLibrarian("models_core.json") # Get the record for the table. table_record = lib.get_record("small_table_green_marble") c = Controller() table_id = 0 # 1. Load the scene. # 2. Create an empty room (using a wrapper function) # 3. Add the table. # 4. Request Bounds data. resp = c.communicate([{ "$type": "load_scene", "scene_name": "ProcGenScene" }, TDWUtils.create_empty_room(12, 12), c.get_add_object(model_name=table_record.name, object_id=table_id, position={ "x": 0,
def get_trial_initialization_commands(self) -> List[dict]: num_objects = random.choice([2, 3]) # Positions where objects will be placed (used to prevent interpenetration). object_positions: List[ObjectPosition] = [] # Randomize the order of the records and pick the first one. # This way, the objects are always different. random.shuffle(self.records) commands = [] # Add 2-3 objects. for i in range(num_objects): o_id = Controller.get_unique_id() record = self.records[i] # Set randomized physics values and update the physics info. scale = TDWUtils.get_unit_scale(record) * random.uniform(0.8, 1.1) # Get a random position. o_pos = self._get_object_position( object_positions=object_positions) # Add the object and the radius, which is defined by its scale. object_positions.append( ObjectPosition(position=o_pos, radius=scale)) commands.extend( self.add_physics_object(o_id=o_id, record=self.records[i], position=self._get_object_position( object_positions=object_positions), rotation={ "x": 0, "y": random.uniform(-90, 90), "z": 0 }, mass=random.uniform(1, 5), dynamic_friction=random.uniform( 0, 0.9), static_friction=random.uniform(0, 0.9), bounciness=random.uniform(0, 1))) # Scale the object. commands.append({ "$type": "scale_object", "id": o_id, "scale_factor": { "x": scale, "y": scale, "z": scale } }) # Point one object at the center, and then offset the rotation. # Apply a force allow the forward directional vector. # Teleport the avatar and look at the object that will be hit. Then slightly rotate the camera randomly. # Listen for output data. force_id = int(self.object_ids[0]) self._target_id = int(self.object_ids[1]) commands.extend([{ "$type": "object_look_at", "other_object_id": self._target_id, "id": force_id }, { "$type": "rotate_object_by", "angle": random.uniform(-5, 5), "id": force_id, "axis": "yaw", "is_world": True }, { "$type": "apply_force_magnitude_to_object", "magnitude": random.uniform(20, 60), "id": force_id }, { "$type": "teleport_avatar_to", "position": self.get_random_avatar_position(radius_min=0.9, radius_max=1.5, y_min=0.5, y_max=1.25, center=TDWUtils.VECTOR3_ZERO) }, { "$type": "look_at", "object_id": self._target_id, "use_centroid": True }, { "$type": "rotate_sensor_container_by", "axis": "pitch", "angle": random.uniform(-5, 5) }, { "$type": "rotate_sensor_container_by", "axis": "yaw", "angle": random.uniform(-5, 5) }, { "$type": "focus_on_object", "object_id": self._target_id }]) return commands
from time import time from tdw.controller import Controller """ This is a minimal controller to test network performance. """ if __name__ == "__main__": num_trials = 50000 sizes = [1, 1000, 10000, 700000] c = Controller(launch_build=False, check_version=False) results = dict() for size in sizes: c.communicate({ "$type": "send_junk", "length": size, "frequency": "always" }) t0 = time() for i in range(num_trials): if i % 200 == 0: print('num_trials=%d' % i) c.communicate({"$type": "do_nothing"}) results[size] = (num_trials / (time() - t0)) c.communicate({"stop": True}) c.socket.close() print("") for size in results: print(size, round(results[size]))
import json from pathlib import Path from tdw.controller import Controller from tdw.output_data import OutputData c = Controller(launch_build=True) p = Path.home().joinpath("Downloads/tdw_commands (1).json") txt = p.read_text() for i, line in enumerate(txt.split("\n")): try: if not line.startswith("["): continue commands = json.loads(line.split(" trial ")[0]) if not isinstance(commands, list): continue resp = c.communicate(commands) r_ids = [OutputData.get_data_type_id(r) for r in resp[:-1]] assert "imag" in r_ids, (i, line, r_ids) except json.JSONDecodeError: continue
from tdw.controller import Controller from tdw.tdw_utils import TDWUtils from tdw.output_data import OutputData, StaticRobot """ Add a camera to a Magnebot. """ if __name__ == "__main__": c = Controller(launch_build=False) c.start() robot_id = 0 avatar_id = "a" # Add a Magnebot to the scene. Request static robot data. resp = c.communicate([ TDWUtils.create_empty_room(12, 12), { "$type": "add_magnebot", "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "x": 0, "y": 0, "z": 0 }, "id": robot_id }, { "$type": "send_static_robots", "frequency": "once" }
def materials_are_missing(c: Controller, record: ModelRecord, url: str) -> bool: """ Check for missing materials. :param c: The controller. :param record: The model metadata record. :param url: The path to the model. :return: True if the model is missing materials. """ # Disable post-processing. # Disable shadows. # Create the avatar. # Set pass masks. # Send images. # Add the object. # Add the object. # Load the bounds of the model. scale = TDWUtils.get_unit_scale(record) c.communicate([{ "$type": "send_images", "frequency": "always" }, { "$type": "add_object", "name": record.name, "url": url, "scale_factor": record.scale_factor, "id": MissingMaterials.OBJECT_ID }, { "$type": "scale_object", "id": MissingMaterials.OBJECT_ID, "scale_factor": { "x": scale, "y": scale, "z": scale } }]) x = 1.75 y = 0.5 z = 0 # Equatorial orbit. theta = 0 while theta < 360: # Get the new position. rad = radians(theta) x1 = cos(rad) * x - sin(rad) * z z1 = sin(rad) * x + cos(rad) * z if MissingMaterials._orbit_and_capture_image(c, x1, y, z1): return True theta += MissingMaterials.DELTA_THETA # Polar orbit. theta = 0 while theta < 360: # Get the new position. rad = radians(theta) x1 = cos(rad) * x - sin(rad) * z y1 = (sin(rad) * x + cos(rad) * z) + y if MissingMaterials._orbit_and_capture_image(c, x1, y1, z): return True theta += MissingMaterials.DELTA_THETA return False
from tdw.controller import Controller from tdw.output_data import OutputData, StaticRobot from tdw.tdw_utils import TDWUtils """ Add a Magnebot and move it around the scene. """ if __name__ == "__main__": c = Controller(launch_build=False) print("This controller demonstrates low-level controls for the Magnebot") print( "For a high-level API, please see: https://github.com/alters-mit/magnebot" ) c.start() robot_id = 0 # Add a Magnebot to the scene and request static data. commands = [ TDWUtils.create_empty_room(12, 12), { "$type": "add_magnebot", "id": robot_id, "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "x": 0, "y": 0, "z": 0 } }, {