Skip to content

Commit

Permalink
Fix rendering for render_mode=human (#56)
Browse files Browse the repository at this point in the history
* fix human rendering

* add render_mode attr

* add test

* RGBA to RGB

* fix python3.10

* render Move render kwargs to constructor, add renderer arg

* doc

* Fix render docstring

* target pos default handling in render

* fix defaults typo

* Clarify renderer documentation

* update test

* fix doc

* update version
  • Loading branch information
qgallouedec authored Jan 24, 2023
1 parent 175149a commit 9d75d6a
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 142 deletions.
Binary file added docs/_static/img/opengl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/tiny.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/top_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
author = "Quentin Gallouédec"

# The full version, including alpha/beta/rc tags
release = "v3.0.3"
release = "v3.0.4"


# -- General configuration ---------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Welcome to ``panda-gym``'s documentation!

usage/environments
usage/manual_control
usage/advanced_rendering
usage/save_restore_state
usage/train_with_sb3

Expand Down
75 changes: 75 additions & 0 deletions docs/usage/advanced_rendering.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.. _advanced_rendering:

Advanced rendering
==================

Renderer
--------

There are two render modes available - ``"human"`` and ``"rgb_array"``. The ``"human"`` mode opens a window to display the live scene, while the ``"rgb_array"`` mode renders the scene as an RGB array.

When it comes to renderers, there are two options: OpenGL and Tiny Renderer. The OpenGL engine is used when the render mode is set to ``"human"``. However, when the render mode is set to ``"rgb_array"`` you have the choice between using either the OpenGL or Tiny Renderer engine. The Tiny Renderer can work in headless mode, but it may not produce as high-quality results as the OpenGL engine, particularly in regards to transparency, background and shadows. If headless mode is not a requirement, it is recommended to use the OpenGL engine. To do this, pass ``renderer="OpenGL"`` to the ``gymnasium.make`` function:

.. code-block:: python
import gymnasium as gym
import panda_gym
env = gym.make("PandaReach-v3", render_mode="rgb_array", renderer="OpenGL")
env.reset()
image = env.render() # RGB rendering of shape (480, 720, 3)
env.close()
.. |tiny| image:: ../_static/img/tiny.png
.. |opengl| image:: ../_static/img/opengl.png

.. list-table::
:widths: 50 50
:header-rows: 1
:align: center

* - ``renderer="Tiny"``
- ``renderer="OpenGL"``
* - |tiny|
- |opengl|


Viewpoint
---------

You can render from a different point of view than the default. For this, the following arguments are available:

- ``render_width`` (int, optional): Image width. Defaults to 720.
- ``render_height`` (int, optional): Image height. Defaults to 480.
- ``render_target_position`` (np.ndarray, optional): Camera targetting this postion, as (x, y, z). Defaults to [0., 0., 0.].
- ``render_distance`` (float, optional): Distance of the camera. Defaults to 1.4.
- ``render_yaw`` (float, optional): Yaw of the camera. Defaults to 45.
- ``render_pitch`` (float, optional): Pitch of the camera. Defaults to -30.
- ``render_roll`` (int, optional): Rool of the camera. Defaults to 0.

Example
~~~~~~~

.. code-block:: python
import gymnasium as gym
import panda_gym
env = gym.make(
"PandaSlide-v3",
render_mode="rgb_array",
renderer="OpenGL",
render_width=480,
render_height=480,
render_target_position=[0.2, 0, 0],
render_distance=1.0,
render_yaw=90,
render_pitch=-70,
render_roll=0,
)
env.reset()
image = env.render() # RGB rendering of shape (480, 480, 3)
env.close()
.. figure:: ../_static/img/top_view.png
78 changes: 38 additions & 40 deletions panda_gym/envs/core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import warnings
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional, Tuple

Expand Down Expand Up @@ -201,13 +200,33 @@ class RobotTaskEnv(gym.Env):
Args:
robot (PyBulletRobot): The robot.
task (Task): The task.
render_width (int, optional): Image width. Defaults to 720.
render_height (int, optional): Image height. Defaults to 480.
render_target_position (np.ndarray, optional): Camera targetting this postion, as (x, y, z).
Defaults to [0., 0., 0.].
render_distance (float, optional): Distance of the camera. Defaults to 1.4.
render_yaw (float, optional): Yaw of the camera. Defaults to 45.
render_pitch (float, optional): Pitch of the camera. Defaults to -30.
render_roll (int, optional): Rool of the camera. Defaults to 0.
"""

metadata = {"render_modes": ["human", "rgb_array"]}

def __init__(self, robot: PyBulletRobot, task: Task) -> None:
def __init__(
self,
robot: PyBulletRobot,
task: Task,
render_width: int = 720,
render_height: int = 480,
render_target_position: Optional[np.ndarray] = None,
render_distance: float = 1.4,
render_yaw: float = 45,
render_pitch: float = -30,
render_roll: float = 0,
) -> None:
assert robot.sim == task.sim, "The robot and the task must belong to the same simulation."
self.sim = robot.sim
self.render_mode = self.sim.render_mode
self.metadata["render_fps"] = 1 / self.sim.dt
self.robot = robot
self.task = task
Expand All @@ -226,6 +245,14 @@ def __init__(self, robot: PyBulletRobot, task: Task) -> None:
self.compute_reward = self.task.compute_reward
self._saved_goal = dict() # For state saving and restoring

self.render_width = render_width
self.render_height = render_height
self.render_target_position = render_target_position
self.render_distance = render_distance
self.render_yaw = render_yaw
self.render_pitch = render_pitch
self.render_roll = render_roll

def _get_obs(self) -> Dict[str, np.ndarray]:
robot_obs = self.robot.get_obs().astype(np.float32) # robot state
task_obs = self.task.get_obs().astype(np.float32) # object position, velococity, etc...
Expand Down Expand Up @@ -291,49 +318,20 @@ def step(self, action: np.ndarray) -> Tuple[Dict[str, np.ndarray], float, bool,
def close(self) -> None:
self.sim.close()

def render(
self,
width: int = 720,
height: int = 480,
target_position: Optional[np.ndarray] = None,
distance: float = 1.4,
yaw: float = 45,
pitch: float = -30,
roll: float = 0,
mode: Optional[str] = None,
) -> Optional[np.ndarray]:
def render(self) -> Optional[np.ndarray]:
"""Render.
If render mode is "rgb_array", return an RGB array of the scene. Else, do nothing.
Args:
width (int, optional): Image width. Defaults to 720.
height (int, optional): Image height. Defaults to 480.
target_position (np.ndarray, optional): Camera targetting this postion, as (x, y, z).
Defaults to [0., 0., 0.].
distance (float, optional): Distance of the camera. Defaults to 1.4.
yaw (float, optional): Yaw of the camera. Defaults to 45.
pitch (float, optional): Pitch of the camera. Defaults to -30.
roll (int, optional): Rool of the camera. Defaults to 0.
mode (str, optional): Deprecated: This argument is deprecated and will be removed in a future
version. Use the render_mode argument of the constructor instead.
If render mode is "rgb_array", return an RGB array of the scene. Else, do nothing and return None.
Returns:
RGB np.ndarray or None: An RGB array if mode is 'rgb_array', else None.
"""
if mode is not None:
warnings.warn(
"The 'mode' argument is deprecated and will be removed in "
"a future version. Use the 'render_mode' argument of the constructor instead.",
DeprecationWarning,
)
target_position = target_position if target_position is not None else np.zeros(3)
return self.sim.render(
width=width,
height=height,
target_position=target_position,
distance=distance,
yaw=yaw,
pitch=pitch,
roll=roll,
width=self.render_width,
height=self.render_height,
target_position=self.render_target_position,
distance=self.render_distance,
yaw=self.render_yaw,
pitch=self.render_pitch,
roll=self.render_roll,
)
Loading

0 comments on commit 9d75d6a

Please sign in to comment.