diff --git a/examples/python/visualization/remote_visualizer.py b/examples/python/visualization/remote_visualizer.py new file mode 100644 index 00000000000..e360e55272b --- /dev/null +++ b/examples/python/visualization/remote_visualizer.py @@ -0,0 +1,71 @@ +# ---------------------------------------------------------------------------- +# - Open3D: www.open3d.org - +# ---------------------------------------------------------------------------- +# Copyright (c) 2018-2023 www.open3d.org +# SPDX-License-Identifier: MIT +# ---------------------------------------------------------------------------- +"""This example shows Open3D's remote visualization feature using RPC +communication. To run this example, start the client first by running + +python remote_visualizer.py client + +and then run the server by running + +python remote_visualizer.py server + +Port 51454 is used by default for communication. For remote visualization (client +and server running on different machines), use ssh to forward the remote server +port to your local computer: + + ssh -N -R 51454:localhost:51454 user@remote_host + +See documentation for more details (e.g. to use a different port). +""" +import sys +import numpy as np +import open3d as o3d +import open3d.visualization as vis + + +def make_point_cloud(npts, center, radius, colorize): + pts = np.random.uniform(-radius, radius, size=[npts, 3]) + center + cloud = o3d.geometry.PointCloud() + cloud.points = o3d.utility.Vector3dVector(pts) + if colorize: + colors = np.random.uniform(0.0, 1.0, size=[npts, 3]) + cloud.colors = o3d.utility.Vector3dVector(colors) + return cloud + + +def server_time_animation(): + orig = make_point_cloud(200, (0, 0, 0), 1.0, True) + clouds = [{"name": "t=0", "geometry": orig, "time": 0}] + drift_dir = (1.0, 0.0, 0.0) + expand = 1.0 + n = 20 + ev = o3d.visualization.ExternalVisualizer() + for i in range(1, n): + amount = float(i) / float(n - 1) + cloud = o3d.geometry.PointCloud() + pts = np.asarray(orig.points) + pts = pts * (1.0 + amount * expand) + [amount * v for v in drift_dir] + cloud.points = o3d.utility.Vector3dVector(pts) + cloud.colors = orig.colors + ev.set(obj=cloud, time=i, path=f"points at t={i}") + print('.', end='', flush=True) + print() + + +def client_time_animation(): + o3d.visualization.draw(title="Open3D - Remote Visualizer Client", + show_ui=True, + rpc_interface=True) + + +if __name__ == "__main__": + assert len(sys.argv) == 2 and sys.argv[1] in ('client', 'server'), ( + "Usage: python remote_visualizer.py [client|server]") + if sys.argv[1] == "client": + client_time_animation() + elif sys.argv[1] == "server": + server_time_animation() diff --git a/python/open3d/visualization/_external_visualizer.py b/python/open3d/visualization/_external_visualizer.py index ac7209127f0..774ddbaebe1 100644 --- a/python/open3d/visualization/_external_visualizer.py +++ b/python/open3d/visualization/_external_visualizer.py @@ -37,17 +37,23 @@ def set(self, obj=None, path='', time=0, layer='', connection=None): Example: To quickly send a single object just write:: + ev.set(point_cloud) To place the object at a specific location in the scene tree do:: + ev.set(point_cloud, path='group/mypoints', time=42, layer='') + Note that depending on the visualizer some arguments like time or layer may not be supported and will be ignored. To set multiple objects use a list to pass multiple objects:: + ev.set([point_cloud, mesh, camera]) + Each entry in the list can be a tuple specifying all or some of the location parameters:: + ev.set(objs=[(point_cloud,'group/mypoints', 1, 'layer1'), (mesh, 'group/mymesh'), camera @@ -147,6 +153,7 @@ def draw(self, geometry=None, *args, **kwargs): Example: Here we use draw with the default external visualizer:: + import open3d as o3d torus = o3d.geometry.TriangleMesh.create_torus() diff --git a/python/open3d/visualization/draw.py b/python/open3d/visualization/draw.py index f7764b41400..aa6e29e2b2c 100644 --- a/python/open3d/visualization/draw.py +++ b/python/open3d/visualization/draw.py @@ -83,9 +83,10 @@ def draw(geometry=None, animation_time_step (float): Duration in seconds for each animation frame. animation_duration (float): Total animation duration in seconds. - rpc_interface (bool): Start an RPC interface at http://localhost:51454 and - listen for drawing requests. The requests can be made with - :class:`open3d.visualization.ExternalVisualizer`. + rpc_interface (bool or str): Start an RPC interface at this local + address and listen for drawing requests. If rpc_interface is True, the + default address "tcp://localhost:51454" is used. The requests can be + made with :class:`open3d.visualization.ExternalVisualizer`. on_init (Callable): Extra initialization procedure for the underlying GUI window. The procedure receives a single argument of type :class:`open3d.visualization.O3DVisualizer`. @@ -202,7 +203,9 @@ def add(g, n): w.show_skybox(show_skybox) if rpc_interface: - w.start_rpc_interface(address="tcp://127.0.0.1:51454", timeout=10000) + if not isinstance(rpc_interface, str): + rpc_interface = "tcp://127.0.0.1:51454" + w.start_rpc_interface(address=rpc_interface, timeout=10000) def stop_rpc(): w.stop_rpc_interface()