201 lines
6.4 KiB
Python
201 lines
6.4 KiB
Python
import mujoco
|
|
from mujoco import viewer
|
|
import sys
|
|
import numpy as np
|
|
import time
|
|
import threading
|
|
|
|
|
|
class MjBasicRenderer:
|
|
def __new__(cls, *args, **kwargs):
|
|
return super().__new__(cls)
|
|
|
|
def __init__(self, mj_model=None, mj_data=None):
|
|
# keyboard flag
|
|
self.render_paused = True
|
|
self.exit_flag = False
|
|
# init param
|
|
self.mj_model = mj_model
|
|
self.mj_data = mj_data
|
|
self.renderer = "viewer" # default
|
|
self.viewer = None
|
|
self._image = None
|
|
|
|
# Set up mujoco viewer
|
|
self.image_renderer = mujoco.Renderer(self.mj_model)
|
|
|
|
def __del__(self):
|
|
pass
|
|
|
|
def _init_renderer(self):
|
|
"""Initialize renderer, choose official renderer with "viewer"(joined from version 2.3.3),
|
|
another renderer with "mujoco_viewer"
|
|
"""
|
|
|
|
def key_callback(keycode):
|
|
if keycode == 32: # space
|
|
self.render_paused = not self.render_paused
|
|
elif keycode == 256: # escape
|
|
self.exit_flag = not self.exit_flag
|
|
|
|
if self.renderer == "viewer":
|
|
# This function does not block, allowing user code to continue execution.
|
|
self.viewer = viewer.launch_passive(
|
|
self.mj_model,
|
|
self.mj_data,
|
|
key_callback=key_callback,
|
|
show_left_ui=False,
|
|
show_right_ui=False,
|
|
)
|
|
self.set_renderer_config()
|
|
else:
|
|
raise ValueError("Invalid renderer for some reason.")
|
|
|
|
def render(self):
|
|
"""mujoco render"""
|
|
if self.viewer is not None and self.render_paused is True:
|
|
if self.viewer.is_running() and self.exit_flag is False:
|
|
self.viewer: viewer.Handle
|
|
self.viewer.sync()
|
|
else:
|
|
self.viewer.close()
|
|
|
|
def set_renderer_config(self):
|
|
"""Setup mujoco global config while using viewer as renderer.
|
|
It should be noted that the render thread need locked.
|
|
"""
|
|
self.viewer.cam.lookat = np.array([0.4, 0, 0.5])
|
|
self.viewer.cam.azimuth -= 0.005
|
|
with self.viewer.lock():
|
|
self.viewer.opt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTPOINT] = int(
|
|
self.mj_data.time % 2
|
|
)
|
|
|
|
|
|
try:
|
|
import cv2
|
|
except ImportError:
|
|
print("Could not import cv2, please install it to enable camera viewer.")
|
|
|
|
|
|
class MjMultiRenderer(MjBasicRenderer):
|
|
|
|
# __slots__=('mj_model','mj_data','renderer','enable_camera_viewer')
|
|
def __new__(cls, *args, **kwargs):
|
|
return super().__new__(cls)
|
|
|
|
def __init__(
|
|
self,
|
|
mj_model=None,
|
|
mj_data=None,
|
|
renderer=None,
|
|
enable_camera_viewer=False,
|
|
enable_depth=False,
|
|
):
|
|
super().__init__(mj_model, mj_data)
|
|
self._depth = None
|
|
self.renderer = renderer
|
|
self._init_renderer()
|
|
self.enable_camera_viewer = enable_camera_viewer
|
|
if self.enable_camera_viewer:
|
|
self.enable_depth = enable_depth
|
|
self._init_window()
|
|
else:
|
|
self.enable_depth = False
|
|
print("No Camera View")
|
|
|
|
def __del__(self):
|
|
self.close()
|
|
|
|
def _init_renderer(self):
|
|
"""
|
|
Initialize renderer, choose official renderer with "viewer"(joined from version 2.3.3)
|
|
"""
|
|
if self.renderer == "unity":
|
|
# TODO: Support unity renderer.
|
|
raise ValueError("Unity renderer init failed for no supporting reason")
|
|
elif self.renderer == "viewer":
|
|
super()._init_renderer()
|
|
print("mujoco viewer init !")
|
|
else:
|
|
raise ValueError("renderer init failed for some reason.")
|
|
|
|
def _init_window(self, name="Camera view"):
|
|
if not self.enable_depth:
|
|
cv2.namedWindow(name, cv2.WINDOW_NORMAL)
|
|
else:
|
|
cv2.namedWindow(name, cv2.WINDOW_NORMAL)
|
|
cv2.namedWindow("Camera depth view", cv2.WINDOW_NORMAL)
|
|
|
|
def render(self):
|
|
"""render mujoco"""
|
|
if self.renderer == "viewer":
|
|
super().render()
|
|
elif self.renderer == "unity":
|
|
# TODO: Support unity renderer.
|
|
raise ValueError("Unity renderer not supported now.")
|
|
else:
|
|
raise ValueError("Invalid renderer for some reason.")
|
|
|
|
def render(self):
|
|
"""mujoco render"""
|
|
if self.viewer is not None and self.render_paused is True:
|
|
if self.viewer.is_running() and self.exit_flag is False:
|
|
self.viewer: viewer.Handle
|
|
self.viewer.sync()
|
|
else:
|
|
self.viewer.close()
|
|
|
|
def camera_render(self, cam=None):
|
|
if self.enable_camera_viewer:
|
|
if not self.enable_depth:
|
|
rgb, depth = self.render_from_camera(cam)
|
|
rgb = cv2.resize(rgb, (1920, 1600))
|
|
cv2.imshow("Camera view", rgb)
|
|
cv2.waitKey(1)
|
|
|
|
else:
|
|
rgb, depth = self.render_from_camera(cam)
|
|
cv2.imshow("Camera view", rgb)
|
|
cv2.imshow("Camera depth view", depth)
|
|
cv2.waitKey(1)
|
|
|
|
else:
|
|
print("camera info disable")
|
|
return
|
|
|
|
def render_from_camera(self, cam=None):
|
|
self.image_renderer.update_scene(self.mj_data, camera=cam)
|
|
if self.enable_depth is True:
|
|
self.image_renderer.enable_depth_rendering()
|
|
org = self.image_renderer.render()
|
|
depth = org[:, :]
|
|
self.image_renderer.disable_depth_rendering()
|
|
org = self.image_renderer.render()
|
|
image = org[:, :, ::-1]
|
|
else:
|
|
org = self.image_renderer.render()
|
|
image = org[:, :, ::-1]
|
|
depth = np.zeros([240, 320])
|
|
return image, depth
|
|
|
|
def close(self):
|
|
"""close the environment."""
|
|
if self.enable_camera_viewer and self.viewer.is_running() == False:
|
|
cv2.destroyAllWindows()
|
|
self.viewer.close()
|
|
# sys.exit(0)
|
|
|
|
# def get_cam_intrinsic(self, fovy=45.0, width=320, height=240):
|
|
# aspect = width * 1.0 / height
|
|
# fovx = np.degrees(2 * np.arctan(aspect * np.tan(np.radians(fovy / 2))))
|
|
|
|
# cx = 0.5 * width
|
|
# cy = 0.5 * height
|
|
# fx = cx / np.tan(fovx * np.pi / 180 * 0.5)
|
|
# fy = cy / np.tan(fovy * np.pi / 180 * 0.5)
|
|
|
|
# K = np.array([[fx, 0, cx],
|
|
# [0, fy, cy],
|
|
# [0, 0, 1]], dtype=np.float32)
|