-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Sphinx build info version 1 | ||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. | ||
config: ffe18ab041802816329183a4ddfa3813 | ||
tags: d77d1c0d9ca2f4c8421862c7c5a0d620 |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Camera Handles | ||
|
||
<!-- prettier-ignore-start --> | ||
|
||
.. autoclass:: viser.CameraHandle | ||
:members: | ||
:undoc-members: | ||
:inherited-members: | ||
|
||
<!-- prettier-ignore-end --> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Client Handles | ||
|
||
<!-- prettier-ignore-start --> | ||
|
||
.. autoclass:: viser.ClientHandle | ||
:members: | ||
:undoc-members: | ||
:inherited-members: | ||
|
||
<!-- prettier-ignore-end --> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Frame Conventions | ||
|
||
In this note, we describe the coordinate frame conventions used in `viser`. | ||
|
||
## Scene tree naming | ||
|
||
Each object that we add to the scene in viser is instantiated as a node in a | ||
scene tree. The structure of this tree is determined by the names assigned to | ||
the nodes. | ||
|
||
If we add a coordinate frame called `/base_link/shoulder/wrist`, it signifies | ||
three nodes: the `wrist` is a child of the `shoulder` which is a child of the | ||
`base_link`. | ||
|
||
If we set the transformation of a given node like `/shoulder`, both it and all | ||
of its children will move. Its parent, `/base_link`, will be unaffected. | ||
|
||
## Poses | ||
|
||
Poses in `viser` are defined using a pair of fields: | ||
|
||
- `wxyz`, a unit quaternion orientation term. This should always be 4D. | ||
- `position`, a translation term. This should always be 3D. | ||
|
||
These correspond to a transformation from coordinates in the local frame to the | ||
parent frame: | ||
|
||
<!-- prettier-ignore-start --> | ||
|
||
.. math:: | ||
|
||
p_\mathrm{parent} = \begin{bmatrix} R \mid t \end{bmatrix}p_\mathrm{local} | ||
|
||
<!-- prettier-ignore-end --> | ||
|
||
where `wxyz` is the quaternion form of the :math:`\mathrm{SO}(3)` matrix | ||
:math:`R` and `position` is the translation term :math:`t`. | ||
|
||
## World coordinates | ||
|
||
In the world coordinate space, +Z points upward by default. This can be | ||
overridden with :func:`viser.ViserServer.set_up_direction()` or | ||
:func:`viser.ClientHandle.set_up_direction()`. | ||
|
||
## Cameras | ||
|
||
All camera parameters exposed to the Python API use the COLMAP/OpenCV | ||
convention: | ||
|
||
- Forward: +Z | ||
- Up: -Y | ||
- Right: +X | ||
|
||
Confusingly, this is different from Nerfstudio, which adopts the OpenGL/Blender | ||
convention: | ||
|
||
- Forward: -Z | ||
- Up: +Y | ||
- Right: +X | ||
|
||
Note that conversion between the two is a simple 180 degree rotation around the | ||
X-axis. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# Development | ||
|
||
In this note, we outline current practices, tools, and workflows for `viser` | ||
development. We assume that the repository is cloned to `~/viser`. | ||
|
||
## Python install | ||
|
||
We recommend an editable install for Python development, ideally in a virtual | ||
environment (eg via conda). | ||
|
||
```bash | ||
# Install package. | ||
cd ~/viser | ||
pip install -e . | ||
|
||
# Install example dependencies. | ||
pip install -e .[examples] | ||
``` | ||
|
||
After installation, any of the example scripts (`~/viser/examples`) should be | ||
runnable. A few of them require downloading assets, which can be done via the | ||
scripts in `~/viser/examples/assets`. | ||
|
||
**Linting, formatting, type-checking.** | ||
|
||
First, install developer tools: | ||
|
||
```bash | ||
# Using pip. | ||
pip install -e .[dev] | ||
pre-commit install | ||
``` | ||
|
||
It would be hard to write unit tests for `viser`. We rely on static typing for | ||
robustness. To check your code, you can run the following: | ||
|
||
```bash | ||
# runs linting, formatting, and type-checking | ||
viser-dev-checks | ||
``` | ||
|
||
## Message updates | ||
|
||
The `viser` frontend and backend communicate via a shared set of message | ||
definitions: | ||
|
||
- On the server, these are defined as Python dataclasses in | ||
`~/viser/src/viser/_messages.py`. | ||
- On the client, these are defined as TypeScript interfaces in | ||
`~/viser/src/viser/client/src/WebsocketMessages.tsx`. | ||
|
||
Note that there is a 1:1 correspondence between the dataclasses message types | ||
and the TypeScript ones. | ||
|
||
The TypeScript definitions should not be manually modified. Instead, changes | ||
should be made in Python and synchronized via the `sync_message_defs.py` script: | ||
|
||
``` | ||
cd ~/viser | ||
python sync_message_defs.py | ||
``` | ||
|
||
## Client development | ||
|
||
For client development, we can start by launching a relevant Python script. The | ||
examples are a good place to start: | ||
|
||
``` | ||
cd ~/viser/examples | ||
python 05_camera_commands.py | ||
``` | ||
|
||
When a `viser` script is launched, two URLs will be printed: | ||
|
||
- An HTTP URL, like `http://localhost:8080`, which can be used to open a | ||
_pre-built_ version of the React frontend. | ||
- A websocket URL, like `ws://localhost:8080`, which client applications can | ||
connect to. | ||
|
||
If changes to the client source files are detected on startup, `viser` will | ||
re-build the client automatically. This is okay for quick changes, but for | ||
faster iteration we can also launch a development version of the frontend, which | ||
will reflect changes we make to the client source files | ||
(`~/viser/src/viser/client/src`) without a full build. This requires a few more | ||
steps. | ||
|
||
**Installing dependencies.** | ||
|
||
1. [Install nodejs.](https://nodejs.dev/en/download/package-manager) | ||
2. [Install yarn.](https://yarnpkg.com/getting-started/install) | ||
3. Install dependencies. | ||
``` | ||
cd ~/viser/src/viser/client | ||
yarn install | ||
``` | ||
|
||
**Launching client.** | ||
|
||
To launch the client, we can run: | ||
|
||
``` | ||
cd ~/viser/src/viser/client | ||
yarn start | ||
``` | ||
|
||
from the `viser/src/viser/client` directory. After opening the client in a web | ||
browser, the websocket server address typically needs to be updated in the | ||
"Server" tab. | ||
|
||
**Formatting.** | ||
|
||
We use [prettier](https://prettier.io/docs/en/install.html). This can be run via | ||
one of: | ||
|
||
- `prettier -w .` | ||
- `npx prettier -w .` | ||
|
||
from `~/viser/client`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Events | ||
|
||
We define a small set of event types, which are passed to callback functions | ||
when events like clicks or GUI updates are triggered. | ||
|
||
<!-- prettier-ignore-start --> | ||
|
||
.. autoclass:: viser.ScenePointerEvent() | ||
|
||
.. autoclass:: viser.SceneNodePointerEvent() | ||
|
||
.. autoclass:: viser.GuiEvent() | ||
|
||
<!-- prettier-ignore-end --> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
.. Comment: this file is automatically generated by `update_example_docs.py`. | ||
It should not be modified manually. | ||
Coordinate frames | ||
========================================== | ||
|
||
|
||
In this basic example, we visualize a set of coordinate frames. | ||
|
||
Naming for all scene nodes are hierarchical; /tree/branch, for example, is defined | ||
relative to /tree. | ||
|
||
|
||
|
||
.. code-block:: python | ||
:linenos: | ||
import random | ||
import time | ||
import viser | ||
server = viser.ViserServer() | ||
while True: | ||
# Add some coordinate frames to the scene. These will be visualized in the viewer. | ||
server.scene.add_frame( | ||
"/tree", | ||
wxyz=(1.0, 0.0, 0.0, 0.0), | ||
position=(random.random() * 2.0, 2.0, 0.2), | ||
) | ||
server.scene.add_frame( | ||
"/tree/branch", | ||
wxyz=(1.0, 0.0, 0.0, 0.0), | ||
position=(random.random() * 2.0, 2.0, 0.2), | ||
) | ||
leaf = server.scene.add_frame( | ||
"/tree/branch/leaf", | ||
wxyz=(1.0, 0.0, 0.0, 0.0), | ||
position=(random.random() * 2.0, 2.0, 0.2), | ||
) | ||
time.sleep(5.0) | ||
# Remove the leaf node from the scene. | ||
leaf.remove() | ||
time.sleep(0.5) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
.. Comment: this file is automatically generated by `update_example_docs.py`. | ||
It should not be modified manually. | ||
Images | ||
========================================== | ||
|
||
|
||
Example for sending images to the viewer. | ||
|
||
We can send backgrond images to display behind the viewer (useful for visualizing | ||
NeRFs), or images to render as 3D textures. | ||
|
||
|
||
|
||
.. code-block:: python | ||
:linenos: | ||
import time | ||
from pathlib import Path | ||
import imageio.v3 as iio | ||
import numpy as onp | ||
import viser | ||
def main() -> None: | ||
server = viser.ViserServer() | ||
# Add a background image. | ||
server.scene.set_background_image( | ||
iio.imread(Path(__file__).parent / "assets/Cal_logo.png"), | ||
format="png", | ||
) | ||
# Add main image. | ||
server.scene.add_image( | ||
"/img", | ||
iio.imread(Path(__file__).parent / "assets/Cal_logo.png"), | ||
4.0, | ||
4.0, | ||
format="png", | ||
wxyz=(1.0, 0.0, 0.0, 0.0), | ||
position=(2.0, 2.0, 0.0), | ||
) | ||
while True: | ||
server.scene.add_image( | ||
"/noise", | ||
onp.random.randint( | ||
0, | ||
256, | ||
size=(400, 400, 3), | ||
dtype=onp.uint8, | ||
), | ||
4.0, | ||
4.0, | ||
format="jpeg", | ||
wxyz=(1.0, 0.0, 0.0, 0.0), | ||
position=(2.0, 2.0, -1e-2), | ||
) | ||
time.sleep(0.2) | ||
if __name__ == "__main__": | ||
main() |