Skip to content

Instantly share code, notes, and snippets.

@lucasb-eyer
Created July 28, 2020 19:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucasb-eyer/7468124163ce69b7e8231a8e6884f803 to your computer and use it in GitHub Desktop.
Save lucasb-eyer/7468124163ce69b7e8231a8e6884f803 to your computer and use it in GitHub Desktop.
Puzzle falling onto table
# Commands can be sent in lists of arbitrary length, allowing for arbitrarily complex instructions per frame. The user must explicitly request output data:
from tdw.controller import Controller
from tdw.tdw_utils import TDWUtils
from tdw.librarian import ModelLibrarian
from tdw.output_data import OutputData, Bounds, Images
c = Controller(launch_build=True)
lib = ModelLibrarian("models_core.json")
# Get the record for the table.
table_record = lib.get_record("small_table_green_marble")
table_id = 0
resp = c.communicate([
# 0. General simulation settings
{"$type": "set_render_quality", "render_quality": 5}, # Default 5 = best
{"$type": "set_screen_size", "width": 1280, "height": 720},
# {"$type": "set_target_framerate", "framerate": 30},
# {"$type": "set_time_step", "time_step": 1/30},
{"$type": "set_physics_solver_iterations", "iterations": 120}, # Default 12, set 120 for much better.
# 1. Load the scene
{"$type": "load_scene", "scene_name": "ProcGenScene"},
# 2. Create an empty room
{"$type": "create_exterior_walls", "walls": TDWUtils.get_box(12, 12)},
# 3. Add the table.
{"$type": "add_object",
"name": table_record.name,
"url": table_record.get_url(),
"scale_factor": table_record.scale_factor,
"position": {"x": 0, "y": 0, "z": 0},
"rotation": {"x": 0, "y": 0, "z": 0},
"category": table_record.wcategory,
"id": table_id},
# 4. Request Bounds data.
{"$type": "send_bounds", "ids": [table_id], "frequency": "once"},
])
# The resp object is a list of byte arrays that can be deserialized into output data:
# Get the top of the table.
assert OutputData.get_data_type_id(resp[0]) == "boun"
_, top_y, _ = Bounds(resp[0]).get_top(0) # Table is the first and only item we ask for.
box_record = lib.get_record("puzzle_box_composite")
box_id = 1
c.communicate([
{"$type": "add_object",
"name": box_record.name,
"url": box_record.get_url(),
"scale_factor": box_record.scale_factor,
"position": {"x": 0, "y": top_y + 1.0, "z": 0},
"rotation": {"x": 0, "y": 0, "z": 0},
"category": box_record.wcategory,
"id": box_id},
{"$type": "set_object_collision_detection_mode", "id": box_id, "mode": "continuous_dynamic"}, # Slower but works for fast-moving objects!
])
# Then an avatar can be added to the scene. In this case, the avatar is just a camera. The avatar can then send an image:
avatar_id = "a"
resp = c.communicate([
{"$type": "create_avatar", "type": "A_Img_Caps_Kinematic", "avatar_id": avatar_id},
{"$type": "teleport_avatar_to", "position": {"x": 1, "y": 2.5, "z": 2}},
# {"$type": "look_at", "avatar_id": avatar_id, "object_id": table_id},
{"$type": "look_at_position", "avatar_id": avatar_id, "position": {"x": 0, "y": top_y + 0.3, "z": 0}},
{"$type": "set_pass_masks", "avatar_id": avatar_id, "pass_masks": ["_img"]},
{"$type": "send_images", "frequency": "once", "avatar_id": avatar_id},
])
import ipdb ; ipdb.set_trace()
for s in range(100):
# Slow: (looks like 2-5 fps)
# resp = c.communicate([{"$type": "send_images", "frequency": "once", "avatar_id": avatar_id}])
# Fast: (really smooth, 30+ fps)
resp = c.communicate([])
# Doesn't affect speed much:
# TDWUtils.save_images(Images(resp[0]), f"actor_{s}", output_directory="out")
# This is how we can get a PIL image out of it (and eventually a numpy array):
# img0 = TDWUtils.get_pil_image(img, 0)
c.communicate({"$type": "terminate"}) # Terminate the build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment