Skip to content

Commit

Permalink
Merge pull request #55 from threedworld-mit/floorplan_controller
Browse files Browse the repository at this point in the history
Floorplan controller
  • Loading branch information
alters-mit authored Sep 21, 2020
2 parents b370524 + 1e08b14 commit 6f021b0
Show file tree
Hide file tree
Showing 10 changed files with 2,216 additions and 3 deletions.
38 changes: 38 additions & 0 deletions Documentation/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@

## v1.6.11

### `tdw` module

- Added: `FloorplanController`. Load a interior environment scene and populate it with furniture and props.
- Added: object initialization data classes:
- `TransformInitData`: Create object and set their positions, rotations, etc.
- `RigidbodyInitData`: Create objects and set their positions, rotations, and physics properties.
- `AudioInitData`: Create objects and set their positions, rotations, and physics properties from their PyImpact audio values.
- Added: `floorplan_layouts.json` Floorplan layouts recipes are stored in this file.

#### `PyImpact`

- Added default audio values for many more objects.

### Model Library

- Added to `models_core.json` and `models_full.json`:
Expand Down Expand Up @@ -37,6 +50,31 @@
- Removed from `models_core.json` and `models_full.json`:
- `flat-woven-rug`

### Scene Library

- Added new scenes:
- floorplan_2a
- floorplan_2b
- floorplan_2c
- floorplan_3a
- floorplan_3b
- floorplan_3c
- floorplan_4a
- floorplan_4b
- floorplan_4c
- floorplan_5a
- floorplan_5b
- floorplan_5c

### Documentation

#### New Documentation

| Document | Description |
| ------------------------- | ------------------------------------------------------------ |
| `floorplan_controller.md` | API document for `FloorplanController` |
| `object_init_data.md` | API document for `TransformInitData`, `RigidbodyInitData`, and `AudioInitData` |

## v1.6.10

### Command API
Expand Down
36 changes: 36 additions & 0 deletions Documentation/python/floorplan_controller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# `floorplan_controller.py`

## `FloorplanController(Controller)`

`from tdw.floorplan_controller import FloorplanController`

A controller that can create an interior scene populated with objects.

```python
from tdw.floorplan_controller import FloorplanController

c = FloorplanController()
init_commands = c.get_scene_init_commands(scene="2a", layout=0, audio=True)
c.communicate(init_commands)
```

***

#### `get_scene_init_commands(self, scene: str, layout: int, audio: bool) -> List[dict]`

Get commands to create a scene and populate it with objects.
Valid scenes and layouts:
| `scene` | `layout` |
| --- | --- |
| `"2a"`, `"2b"`, or `"2b"` | 0 |

| Parameter | Description |
| --- | --- |
| scene | The name of the scene. Corresponds to a record named: `floorplan_[scene]`. |
| layout | The layout index. |
| audio | If True, instantiate physics values per object from audio properties. |

_Returns:_ A list of commands to initialize the scene and populate it with objects.

***

95 changes: 95 additions & 0 deletions Documentation/python/object_init_data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# `object_init_data.py`

## `TransformInitData`

`from tdw.object_init_data import TransformInitData`

Basic initialization parameters for an object. Can be converted to and from a list of commands.

This is similar to [`Controller.get_add_object()`](controller.md) except that it includes more parameters.

***

#### `__init__(self, name: str, library: str = "models_core.json", scale_factor: Dict[str, float] = None, position: Dict[str, float] = None, rotation: Dict[str, float] = None, kinematic: bool = False, gravity: bool = True)`


| Parameter | Description |
| --- | --- |
| name | The name of the model. |
| library | The filename of the library containing the model's record. |
| scale_factor | The [scale factor](../api/command_api.md#scale_object). |
| position | The initial position. If None, defaults to: `{"x": 0, "y": 0, "z": 0`}. |
| rotation | The initial rotation as a quaternion. If None, defaults to: `{"w": 1, "x": 0, "y": 0, "z": 0}` |
| kinematic | If True, the object will be [kinematic](../api/command_api.md#set_kinematic_state). |
| gravity | If True, the object won't respond to [gravity](../api/command_api.md#set_kinematic_state). |

***

#### `get_commands(self) -> Tuple[int, List[dict]]`

_Returns:_ 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]`

***

## `RigidbodyInitData(TransformInitData)`

`from tdw.object_init_data import RigidbodyInitData`

A subclass of `TransformInitData`. Includes data and commands to set the mass and physic material of the object.

***

#### `__init__(self, name: str, mass: float, dynamic_friction: float, static_friction: float, bounciness: float, library: str = "models_core.json", scale_factor: Dict[str, float] = None, position: Dict[str, float] = None, rotation: Dict[str, float] = None, kinematic: bool = False, gravity: bool = True)`


| Parameter | Description |
| --- | --- |
| name | The name of the model. |
| library | The filename of the library containing the model's record. |
| scale_factor | The [scale factor](../api/command_api.md#scale_object). |
| position | The initial position. If None, defaults to: `{"x": 0, "y": 0, "z": 0`}. |
| rotation | The initial rotation as a quaternion. If None, defaults to: `{"w": 1, "x": 0, "y": 0, "z": 0}` |
| kinematic | If True, the object will be [kinematic](../api/command_api.md#set_kinematic_state). |
| gravity | If True, the object won't respond to [gravity](../api/command_api.md#set_kinematic_state). |
| mass | The mass of the object. |
| dynamic_friction | The [dynamic friction](../api/command_api.md#set_physic_material) of the object. |

***

#### `get_commands(self) -> Tuple[int, List[dict]]`

_Returns:_ 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, set_mass, set_physic_material]`

***

## `AudioInitData(RigidbodyInitData)`

`from tdw.object_init_data import AudioInitData`

A subclass of `RigidbodyInitData` that includes [audio values](py_impact.md#objectinfo).
Physics values are derived from these audio values.

***

#### `__init__(self, name: str, library: str = "models_core.json", scale_factor: Dict[str, float] = None, position: Dict[str, float] = None, rotation: Dict[str, float] = None, kinematic: bool = False, gravity: bool = True, audio: ObjectInfo = None)`


| Parameter | Description |
| --- | --- |
| name | The name of the model. |
| library | The filename of the library containing the model's record. |
| scale_factor | The [scale factor](../api/command_api.md#scale_object). |
| position | The initial position. If None, defaults to: `{"x": 0, "y": 0, "z": 0`}. |
| rotation | The initial rotation as a quaternion. If None, defaults to: `{"w": 1, "x": 0, "y": 0, "z": 0}` |
| kinematic | If True, the object will be [kinematic](../api/command_api.md#set_kinematic_state). |
| gravity | If True, the object won't respond to [gravity](../api/command_api.md#set_kinematic_state). |
| audio | If None, derive physics data from the audio data in `PyImpact.get_object_info()` (if the object isn't in this dictionary, this constructor will throw an error). If not None, use these values instead of the default audio values. |

***

#### `get_commands(self) -> Tuple[int, List[dict]]`

_Returns:_ 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, set_mass, set_physic_material]`

***

2 changes: 2 additions & 0 deletions Documentation/python/tdw.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ pip3 install tdw
| [PyImpact](https://github.com/threedworld-mit/tdw/blob/master/Documentation/python/py_impact.md) | Generate impact sounds at runtime. |
| [DebugController](https://github.com/threedworld-mit/tdw/blob/master/Documentation/python/debug_controller.md) | Child class of `Controller` that has useful debug features. |
| [KeyboardController](keyboard_controller.md) | Child class of `Controller` that can listen for keyboard input. |
| [FloorplanController](floorplan_controller.md) | Child class of `Controller` that creates an interior environment and populates it with objects. |
| [Librarian](https://github.com/threedworld-mit/tdw/blob/master/Documentation/python/librarian/librarian.md) | "Librarians" hold asset bundle metadata records. |
| [FluidTypes](https://github.com/threedworld-mit/tdw/blob/master/Documentation/python/fluid_types.md) | Access different NVIDIA Flex fluid types. |
| [Object Init Data](object_init_data.md) | Wrapper classes for storing object initialization data. |

### Backend

Expand Down
73 changes: 73 additions & 0 deletions Python/tdw/floorplan_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from pathlib import Path
from json import loads
from pkg_resources import resource_filename
from typing import List
from tdw.controller import Controller
from tdw.object_init_data import TransformInitData, AudioInitData


class FloorplanController(Controller):
"""
A controller that can create an interior scene populated with objects.
```python
from tdw.floorplan_controller import FloorplanController
c = FloorplanController()
init_commands = c.get_scene_init_commands(scene="2a", layout=0, audio=True)
c.communicate(init_commands)
```
"""

def get_scene_init_commands(self, scene: str, layout: int, audio: bool) -> List[dict]:
"""
Get commands to create a scene and populate it with objects.
Valid scenes and layouts:
| `scene` | `layout` |
| --- | --- |
| `"2a"`, `"2b"`, or `"2b"` | 0 |
:param scene: The name of the scene. Corresponds to a record named: `floorplan_[scene]`.
:param layout: The layout index.
:param audio: If True, instantiate physics values per object from audio properties.
:return: A list of commands to initialize the scene and populate it with objects.
"""

scene = scene
scene_index = scene[0]
layout = str(layout)

floorplans = loads(Path(resource_filename(__name__, "floorplan_layouts.json")).
read_text(encoding="utf-8"))
if scene_index not in floorplans:
raise Exception(f"Floorplan not found: {scene_index}")
if layout not in floorplans[scene_index]:
raise Exception(f"Layout not found: {layout}")

objects = floorplans[scene_index][layout]

commands = [self.get_add_scene(scene_name=f"floorplan_{scene}"),
{"$type": "set_aperture",
"aperture": 8.0},
{"$type": "set_focus_distance",
"focus_distance": 2.25},
{"$type": "set_post_exposure",
"post_exposure": 0.4},
{"$type": "set_ambient_occlusion_intensity",
"intensity": 0.175},
{"$type": "set_ambient_occlusion_thickness_modifier",
"thickness": 3.5}]
# Deserialize the JSON data.
if audio:
objects = [AudioInitData(**o) for o in objects]
else:
objects = [TransformInitData(**o) for o in objects]
# Get the commands to initialize each object.
for o in objects:
object_id, object_commands = o.get_commands()
commands.extend(object_commands)
return commands
Loading

0 comments on commit 6f021b0

Please sign in to comment.