diff --git a/docs/source/reference/viewers.rst b/docs/source/reference/viewers.rst index a42aff9e..3085d030 100644 --- a/docs/source/reference/viewers.rst +++ b/docs/source/reference/viewers.rst @@ -70,7 +70,7 @@ PyrenderViewer The viewer is initialized with specified resolution, update interval, and rendering flags. Key parameters include: - ``resolution``: Window size (default: ``(640, 480)``) - - ``update_interval``: Update frequency in seconds (default: ``1.0``) + - ``update_interval``: Update frequency in seconds (default: ``1 / 30``, i.e. 30 Hz) - ``enable_collision_toggle``: Enable collision/visual mesh switching (default: ``True``) - ``title``: Window title (default: ``'scikit-robot PyrenderViewer'``) @@ -279,16 +279,17 @@ The following video demonstrates the interactive IK feature, where dragging the # Use viser viewer with visualize-urdf command (IK is enabled by default) skr visualize-urdf ~/.skrobot/pr2_description/pr2.urdf --viewer viser -.. caution:: +.. note:: - To speed up the rendering cycle in **TrimeshSceneViewer** and **PyrenderViewer**, adjust the ``update_interval`` to the reciprocal of the desired frequency. For example, to achieve updates at 30 Hz, set the ``update_interval`` to 1/30. This change will increase the frequency at which the ``redraw()`` function is called, making the rendering process faster. + Both **TrimeshSceneViewer** and **PyrenderViewer** update at 30 Hz by default (``update_interval=1/30``). The viewer only re-renders when the scene actually changes (e.g. after :func:`redraw`), so a static view stays cheap even at 30 Hz. The ``update_interval`` controls how often the ``redraw()`` request is polled: a smaller value gives a higher refresh rate (smoother interaction and animation) at the cost of more idle CPU, while a larger value lowers idle CPU usage. Example usage: .. code-block:: python - viewer = skrobot.viewers.TrimeshSceneViewer(resolution=(640, 480), update_interval=1.0/30) # Set update interval for 30 Hz - viewer = skrobot.viewers.PyrenderViewer(resolution=(640, 480), update_interval=1.0/30) # Same for PyrenderViewer + # 30 Hz is already the default; pass update_interval only to override it. + viewer = skrobot.viewers.TrimeshSceneViewer(resolution=(640, 480), update_interval=1.0/30) # 30 Hz (default) + viewer = skrobot.viewers.PyrenderViewer(resolution=(640, 480), update_interval=1.0) # 1 Hz, lower idle CPU Color Management diff --git a/skrobot/viewers/_pyrender.py b/skrobot/viewers/_pyrender.py index 6273ae2c..b751bada 100644 --- a/skrobot/viewers/_pyrender.py +++ b/skrobot/viewers/_pyrender.py @@ -99,7 +99,7 @@ class PyrenderViewer(pyrender.Viewer): The resolution of the viewer. Default is (640, 480). update_interval : float, optional The update interval (in seconds) for the viewer. Default is - 1.0 seconds. + 1 / 30 seconds (30 Hz). title : str, optional The title of the viewer window. Default is 'scikit-robot PyrenderViewer'. enable_collision_toggle : bool, optional @@ -123,7 +123,7 @@ class PyrenderViewer(pyrender.Viewer): # Class variable to hold the single instance of the class. _instance = None - def __init__(self, resolution=None, update_interval=1.0, + def __init__(self, resolution=None, update_interval=1 / 30.0, render_flags=None, title=None, enable_collision_toggle=True): if getattr(self, '_initialized', False): return @@ -279,7 +279,10 @@ def on_draw(self): with self._render_lock: if not self._redraw: - super(PyrenderViewer, self).on_draw() + # Nothing changed since the last frame, so skip rendering + # entirely. Without this, the scene is re-rendered on every + # refresh tick (e.g. 30 times per second), which keeps the + # CPU busy even when the view is completely static. return # apply latest angle-vector for link_id, (node, link) in self._visual_mesh_map.items(): diff --git a/skrobot/viewers/_trimesh.py b/skrobot/viewers/_trimesh.py index ee60b20b..e0811a93 100644 --- a/skrobot/viewers/_trimesh.py +++ b/skrobot/viewers/_trimesh.py @@ -55,7 +55,7 @@ class TrimeshSceneViewer(trimesh.viewer.SceneViewer): The resolution of the viewer. Default is (640, 480). update_interval : float, optional The update interval (in seconds) for the viewer. Default is - 1.0 seconds. + 1 / 30 seconds (30 Hz). title : str, optional The title of the viewer window. Default is 'scikit-robot TrimeshSceneViewer'. @@ -69,7 +69,7 @@ class TrimeshSceneViewer(trimesh.viewer.SceneViewer): _instance = None _version_warning_issued = False - def __init__(self, resolution=None, update_interval=1.0, title=None): + def __init__(self, resolution=None, update_interval=1 / 30.0, title=None): if getattr(self, '_initialized', False): return if resolution is None: @@ -145,9 +145,10 @@ def on_update(self, dt): def on_draw(self): if not self._redraw: - with self.lock: - self._update_vertex_list() - super(TrimeshSceneViewer, self).on_draw() + # Nothing changed since the last frame, so skip rendering + # entirely. Without this, the scene is re-rendered on every + # refresh tick (e.g. 30 times per second), which keeps the + # CPU busy even when the view is completely static. return with self.lock: @@ -263,6 +264,10 @@ def set_camera(self, *args, **kwargs): ) def save_image(self, file_obj): + # Force a redraw so the freshly rendered frame is captured. on_draw + # skips rendering when self._redraw is False, so without this the + # buffer read back below could contain a stale frame. + self._redraw = True self.switch_to() self.dispatch_events() self.dispatch_event('on_draw')