|
1 | | - |
| 1 | +<img src="./images/logo.png" width="100%"> |
2 | 2 |
|
3 | 3 | --- |
4 | 4 |
|
5 | | -SlamDunk is a powerful and user-friendly Python library for making 3D and 2D visualizations for prototyping, data exploration, and algorithm development. |
| 5 | +<img src="./images/galaxy.gif" width="49%"> <img src="./images/lorenz_attractor.gif" width="49%"> |
6 | 6 |
|
7 | | -It is lightweight, built using OpenGL and ImGui. |
| 7 | +<img src="./images/double_pendulum.gif" width="49%"> <img src="./images/moving_spheres.gif" width="49%"> |
8 | 8 |
|
9 | | -# Examples |
| 9 | +`slamd` is a 3D visualization library for Python. `pip install`, write a few lines, and you have a GPU-accelerated interactive 3D viewer. No event loops, no boilerplate — just set geometry and it shows up. |
10 | 10 |
|
11 | | -## Hello world |
12 | | - |
13 | | -Here is a simple "hello world" program for a SlamDunk visualization. |
14 | | - |
15 | | -```python |
16 | | -import slamd |
17 | | - |
18 | | -if __name__ == "__main__": |
19 | | - vis = slamd.Visualizer("Hello world") |
20 | | - |
21 | | - scene = vis.scene("scene") |
22 | | - |
23 | | - scene.set_object("/origin", slamd.geom.Triad()) |
24 | | - |
25 | | - vis.hang_forever() |
| 11 | +```bash |
| 12 | +pip install slamd |
26 | 13 | ``` |
27 | 14 |
|
28 | | -Running this program results in the following interactive visualization: |
29 | | - |
30 | | - |
31 | | -This example highlights the main components of SlamDunk. |
32 | | - |
33 | | -The `Visualizer` object maintains the state of the visualization, and starts a TCP server that the visualization window connects to. |
| 15 | +## Why slamd? |
34 | 16 |
|
35 | | -By default, it spawns a window process that reads from it and displays the visualizations. You can opt out of this with the `spawn` argument, and control the port with the `port` argument. |
36 | | -In this case, you can start a window with the `slamd-window` executable: |
| 17 | +Most 3D visualization in Python is either painfully slow (matplotlib's 3D mode), or requires you to learn a massive framework. `slamd` is neither. |
37 | 18 |
|
38 | | -``` |
39 | | -slamd-window --port [port] --ip [ip] |
40 | | -``` |
| 19 | +- **Dead simple** — create a visualizer, set geometry, done. The viewer window spawns automatically in a separate process. No event loop, no main thread hijacking, no callbacks. |
| 20 | +- **Real 3D rendering** — GPU-accelerated OpenGL. Handles millions of points, animated meshes, and real geometry at interactive framerates. This is not a plot library pretending to do 3D. |
| 21 | +- **Pose tree** — objects live in a transform tree (like ROS TF or a scene graph). Set a parent transform and everything underneath moves. Makes articulated and hierarchical scenes trivial. |
| 22 | +- **The right primitives** — point clouds, meshes, camera frustums, triads, arrows, polylines, spheres, planes. The stuff you actually need when working with 3D data, robotics, or SLAM. |
41 | 23 |
|
42 | | -This client-server architecture allows launching a visualizer a remote server, and connecting to it on your local machine. |
| 24 | +## How is this different from Rerun? |
43 | 25 |
|
44 | | -A `Scene` object represents and contains a tree of 3D objects, accessed by paths like `/comp1/comp2/comp3`. 3D poses and `Geometry` objects can be assigned with the `set_transform` and `set_object` methods. |
| 26 | +`slamd` is a **stateful viewer**, not a logging database. There's no append-only log, no timeline, no timestamps forced onto your data. You have a tree of geometry — you set objects, move them, delete them, and what you see is what's there right now. |
45 | 27 |
|
46 | | -`Geometry` objects represent the objects that are displayed in the scene. |
| 28 | +Rerun is powerful, but it's a big tool with a lot of concepts. `slamd` does one thing: show your geometry, right now, with minimal API surface. If you want a data recording platform with time-series scrubbing, use Rerun. If you want to throw some geometry on screen and look at it, use `slamd`. |
47 | 29 |
|
48 | | -## Multiple scenes |
49 | | - |
50 | | -SlamDunk uses ImGui to allow multiple sub-windows with floating and docking support inside the SlamDunk viewer. The following example illustrates creating two windows, each showing its own scene. |
| 30 | +## Quick Start |
51 | 31 |
|
52 | 32 | ```python |
53 | 33 | import slamd |
54 | | -import numpy as np |
55 | | - |
56 | | -if __name__ == "__main__": |
57 | | - vis = slamd.Visualizer("two windows") |
58 | | - |
59 | | - scene1 = vis.scene("scene 1") |
60 | | - scene2 = vis.scene("scene 2") |
61 | | - |
62 | | - scene1.set_object("/box", slamd.geom.Box()) |
63 | | - |
64 | | - scene2.set_object("/origin", slamd.geom.Triad()) |
65 | | - |
66 | | - scene2.set_object("/ball", slamd.geom.Sphere(2.0)) |
67 | | - |
68 | | - sphere_transform = np.identity(4, dtype=np.float32) |
69 | | - sphere_transform[:, 3] = np.array([5.0, 1.0, 2.0, 1.0]) |
70 | | - |
71 | | - scene2.set_transform("/ball", sphere_transform) |
72 | | - |
73 | | - vis.hang_forever() |
74 | 34 |
|
| 35 | +vis = slamd.Visualizer("Hello world") |
| 36 | +scene = vis.scene("scene") |
| 37 | +scene.set_object("/origin", slamd.geom.Triad()) |
75 | 38 | ``` |
76 | 39 |
|
77 | | -The resulting window looks like this: |
78 | | - |
79 | | - |
| 40 | + |
80 | 41 |
|
81 | | -The windows are fully controllable - you can drag them around, make tabs, use them in floating mode, or dock them to the sides like you see in the screenshot. All of this is supported by [ImGui](https://github.com/ocornut/imgui). |
| 42 | +That's it. A window opens with an interactive 3D view. |
82 | 43 |
|
83 | | -Here is a slightly more elaborate example of something you can do with SlamDunk: |
| 44 | +Objects live in a transform tree — move a parent and children follow: |
84 | 45 |
|
85 | | - |
86 | | - |
87 | | -Or this one: |
| 46 | +```python |
| 47 | +scene.set_object("/robot/camera/frustum", slamd.geom.CameraFrustum(K, w, h, scale=0.2)) |
| 48 | +scene.set_object("/robot/lidar/cloud", slamd.geom.PointCloud(pts, colors, point_size)) |
88 | 49 |
|
89 | | - |
| 50 | +# Move the whole robot — camera and lidar come with it |
| 51 | +scene.set_transform("/robot", pose) |
| 52 | +``` |
90 | 53 |
|
91 | | -## Supported geometry primitives |
| 54 | +## Multiple Windows |
92 | 55 |
|
93 | | -### 3D |
| 56 | +Create multiple scenes — each gets its own sub-window with ImGui docking. Drag, tab, float, or dock them however you like: |
94 | 57 |
|
95 | | -- Camera Frustums (with optional image) (`slamd.geom.CameraFrustum`) |
96 | | -- Arrows/Vectors (`slamd.geom.Arrows`) |
97 | | -- Arbitrary meshes (`slamd.geom.Mesh`) |
98 | | -- Planes (`slamd.geom.Plane`) |
99 | | -- Point Clouds (`slamd.geom.PointCloud`) |
100 | | -- Piecewise linear curves (`slamd.geom.PolyLine`) |
101 | | -- Spheres (`slamd.geom.Sphere`) |
102 | | -- Triads/reference frames (`slamd.geom.Triad`) |
| 58 | +```python |
| 59 | +vis = slamd.Visualizer("multi-view") |
| 60 | +scene1 = vis.scene("RGB camera") |
| 61 | +scene2 = vis.scene("point cloud") |
103 | 62 |
|
104 | | -## 2D |
| 63 | +scene1.set_object("/frustum", slamd.geom.CameraFrustum(K, w, h, img, 1.0)) |
| 64 | +scene2.set_object("/cloud", slamd.geom.PointCloud(pts, colors, 0.3, 0.5)) |
| 65 | +``` |
105 | 66 |
|
106 | | -- Images (`slamd.geom2d.Image`) |
107 | | -- Points (`slamd.geom2d.Points`) |
108 | | -- Piecewise linear curves (`slamd.geom2d.PolyLine`) |
109 | | -- Circles (`slamd.geom2d.Circles`) |
| 67 | + |
110 | 68 |
|
111 | | -## Further reading |
| 69 | +## Geometry |
112 | 70 |
|
113 | | -The examples in `python_examples` showcase some more features of SlamDunk. Some examples are canvases for 2D visualizations and lots of additional geometry primitives such as point clouds, meshes, camera frustums, etc. |
| 71 | +- Point clouds — `slamd.geom.PointCloud` |
| 72 | +- Meshes — `slamd.geom.Mesh` |
| 73 | +- Camera frustums (with image) — `slamd.geom.CameraFrustum` |
| 74 | +- Arrows — `slamd.geom.Arrows` |
| 75 | +- Polylines — `slamd.geom.PolyLine` |
| 76 | +- Spheres — `slamd.geom.Sphere` / `slamd.geom.Spheres` |
| 77 | +- Triads — `slamd.geom.Triad` |
| 78 | +- Planes — `slamd.geom.Plane` |
| 79 | +- Boxes — `slamd.geom.Box` |
114 | 80 |
|
115 | | -# Installation |
| 81 | +## Installation |
116 | 82 |
|
117 | | -Wheels are available on [PyPi](https://pypi.org/project/slamd/), so you can simply |
| 83 | +Wheels on [PyPI](https://pypi.org/project/slamd/) for Linux and macOS (Python >= 3.11): |
118 | 84 |
|
119 | 85 | ```bash |
120 | 86 | pip install slamd |
121 | 87 | ``` |
122 | 88 |
|
123 | | -# Contributions |
| 89 | +Only runtime dependency is `numpy >= 1.23`. |
| 90 | + |
| 91 | +## Examples |
| 92 | + |
| 93 | +See [examples/](./examples) for the full set. |
| 94 | + |
| 95 | +## License |
124 | 96 |
|
125 | | -All contributions and feedback are welcome and appreciated! |
| 97 | +Apache 2.0 — see [LICENSE](./LICENSE). |
0 commit comments