Skip to content

Commit

Permalink
Merge branch 'main' into gina/notification
Browse files Browse the repository at this point in the history
  • Loading branch information
ginazhouhuiwu committed Aug 24, 2024
2 parents 4ea83c6 + 783ea09 commit a5a41b7
Show file tree
Hide file tree
Showing 47 changed files with 1,700 additions and 892 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ htmlcov
.DS_Store
.envrc
.vite
build
src/viser/client/build
src/viser/client/.nodeenv
3 changes: 1 addition & 2 deletions docs/source/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ where `wxyz` is the quaternion form of the :math:`\mathrm{SO}(3)` matrix
## 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()`.
overridden with :func:`viser.SceneApi.set_up_direction()`.

## Cameras

Expand Down
4 changes: 3 additions & 1 deletion docs/source/examples/02_gui.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Examples of basic GUI elements that we can create, read from, and write to.
initial_value=0,
disabled=True,
)
gui_slider = server.gui.add_slider(
"Slider",
min=0,
Expand All @@ -38,6 +37,7 @@ Examples of basic GUI elements that we can create, read from, and write to.
initial_value=0,
disabled=True,
)
gui_progress = server.gui.add_progress_bar(25, animated=True)
with server.gui.add_folder("Editable"):
gui_vector2 = server.gui.add_vector2(
Expand Down Expand Up @@ -119,6 +119,8 @@ Examples of basic GUI elements that we can create, read from, and write to.
point_shape="circle",
)
gui_progress.value = float((counter % 100))
# We can use `.visible` and `.disabled` to toggle GUI elements.
gui_text.visible = not gui_checkbox_hide.value
gui_button.visible = not gui_checkbox_hide.value
Expand Down
2 changes: 0 additions & 2 deletions docs/source/examples/23_smpl_visualizer_skinned.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@ See here for download instructions:
# Match transform control gizmos to joint positions.
for i, control in enumerate(gui_elements.transform_controls):
control.position = smpl_outputs.T_parent_joint[i, :3, 3]
print(control.position)
skinned_handle.bones[i].wxyz = tf.SO3.from_matrix(
smpl_outputs.T_world_joint[i, :3, :3]
).wxyz
Expand Down
2 changes: 0 additions & 2 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ pip install viser[examples]
After an example script is running, you can connect by navigating to the printed
URL (default: `http://localhost:8080`).

See also: our [development docs](https://viser.studio/development/).

<!-- prettier-ignore-start -->

.. toctree::
Expand Down
4 changes: 3 additions & 1 deletion examples/02_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def main() -> None:
initial_value=0,
disabled=True,
)

gui_slider = server.gui.add_slider(
"Slider",
min=0,
Expand All @@ -27,6 +26,7 @@ def main() -> None:
initial_value=0,
disabled=True,
)
gui_progress = server.gui.add_progress_bar(25, animated=True)

with server.gui.add_folder("Editable"):
gui_vector2 = server.gui.add_vector2(
Expand Down Expand Up @@ -108,6 +108,8 @@ def _(_) -> None:
point_shape="circle",
)

gui_progress.value = float((counter % 100))

# We can use `.visible` and `.disabled` to toggle GUI elements.
gui_text.visible = not gui_checkbox_hide.value
gui_button.visible = not gui_checkbox_hide.value
Expand Down
2 changes: 1 addition & 1 deletion examples/20_scene_pointer.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _(event: viser.ScenePointerEvent) -> None:
client.scene.remove_pointer_callback()

# Get the first hit position (based on distance from the ray origin).
hit_pos = min(hit_pos, key=lambda x: onp.linalg.norm(x - origin))
hit_pos = hit_pos[onp.argmin(onp.sum((hit_pos - origin) ** 2, axis=-1))]

# Create a sphere at the hit location.
hit_pos_mesh = trimesh.creation.icosphere(radius=0.1)
Expand Down
2 changes: 0 additions & 2 deletions examples/23_smpl_visualizer_skinned.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ def main(model_path: Path) -> None:
# Match transform control gizmos to joint positions.
for i, control in enumerate(gui_elements.transform_controls):
control.position = smpl_outputs.T_parent_joint[i, :3, 3]
print(control.position)

skinned_handle.bones[i].wxyz = tf.SO3.from_matrix(
smpl_outputs.T_world_joint[i, :3, :3]
).wxyz
Expand Down
6 changes: 2 additions & 4 deletions examples/assets/mdx_example.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ In inline code blocks, you can show off colors with color chips: `#FED363`

Adding images from a remote origin is simple.

![Viser Logo](http://nerfstudio-project.github.io/viser/_static/viser.svg)
![Viser Logo](https://viser.studio/latest/_static/logo.svg)

For local images with relative paths, you can either directly use a
[data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)
Expand All @@ -30,7 +30,7 @@ Tables follow the standard markdown spec:

| Application | Description |
| ---------------------------------------------------- | -------------------------------------------------- |
| [Nerfstudio](https://nerf.studio) | A collaboration friendly studio for NeRFs |
| [NS](https://nerf.studio) | A collaboration friendly studio for NeRFs |
| [Viser](https://nerfstudio-project.github.io/viser/) | An interactive 3D visualization toolbox for Python |

Code blocks, while being not nearly as exciting as some of the things presented,
Expand Down Expand Up @@ -90,5 +90,3 @@ So that's MDX in Viser. It has support for:
blocks, inline code
- [x] Color chips
- [x] JSX enhanced components
- [ ] Prism highlighted code blocks and code block tabs
- [ ] Exposed Mantine in markdown
81 changes: 33 additions & 48 deletions examples/experimental/gaussian_splats.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class SplatFile(TypedDict):

def load_splat_file(splat_path: Path, center: bool = False) -> SplatFile:
"""Load an antimatter15-style splat file."""
start_time = time.time()
splat_buffer = splat_path.read_bytes()
bytes_per_gaussian = (
# Each Gaussian is serialized as:
Expand All @@ -43,22 +44,23 @@ def load_splat_file(splat_path: Path, center: bool = False) -> SplatFile:
)
assert len(splat_buffer) % bytes_per_gaussian == 0
num_gaussians = len(splat_buffer) // bytes_per_gaussian
print("Number of gaussians to render: ", f"{num_gaussians=}")

# Reinterpret cast to dtypes that we want to extract.
splat_uint8 = onp.frombuffer(splat_buffer, dtype=onp.uint8).reshape(
(num_gaussians, bytes_per_gaussian)
)
scales = splat_uint8[:, 12:24].copy().view(onp.float32)
wxyzs = splat_uint8[:, 28:32] / 255.0 * 2.0 - 1.0
Rs = onp.array([tf.SO3(wxyz).as_matrix() for wxyz in wxyzs])
Rs = tf.SO3(wxyzs).as_matrix()
covariances = onp.einsum(
"nij,njk,nlk->nil", Rs, onp.eye(3)[None, :, :] * scales[:, None, :] ** 2, Rs
)
centers = splat_uint8[:, 0:12].copy().view(onp.float32)
if center:
centers -= onp.mean(centers, axis=0, keepdims=True)
print("Splat file loaded")
print(
f"Splat file with {num_gaussians=} loaded in {time.time() - start_time} seconds"
)
return {
"centers": centers,
# Colors should have shape (N, 3).
Expand All @@ -70,64 +72,40 @@ def load_splat_file(splat_path: Path, center: bool = False) -> SplatFile:


def load_ply_file(ply_file_path: Path, center: bool = False) -> SplatFile:
plydata = PlyData.read(ply_file_path)
vert = plydata["vertex"]
sorted_indices = onp.argsort(
-onp.exp(vert["scale_0"] + vert["scale_1"] + vert["scale_2"])
/ (1 + onp.exp(-vert["opacity"]))
)
numgaussians = len(vert)
print("Number of gaussians to render: ", numgaussians)
colors = onp.zeros((numgaussians, 3))
opacities = onp.zeros((numgaussians, 1))
positions = onp.zeros((numgaussians, 3))
wxyzs = onp.zeros((numgaussians, 4))
scales = onp.zeros((numgaussians, 3))
for idx in sorted_indices:
v = plydata["vertex"][idx]
position = onp.array([v["x"], v["y"], v["z"]], dtype=onp.float32)
scale = onp.exp(
onp.array([v["scale_0"], v["scale_1"], v["scale_2"]], dtype=onp.float32)
)
"""Load Gaussians stored in a PLY file."""
start_time = time.time()

rot = onp.array(
[v["rot_0"], v["rot_1"], v["rot_2"], v["rot_3"]], dtype=onp.float32
)
SH_C0 = 0.28209479177387814
color = onp.array(
[
0.5 + SH_C0 * v["f_dc_0"],
0.5 + SH_C0 * v["f_dc_1"],
0.5 + SH_C0 * v["f_dc_2"],
]
)
opacity = 1 / (1 + onp.exp(-v["opacity"]))
wxyz = rot / onp.linalg.norm(rot) # normalize
scales[idx] = scale
colors[idx] = color
opacities[idx] = onp.array([opacity])
positions[idx] = position
wxyzs[idx] = wxyz

Rs = onp.array([tf.SO3(wxyz).as_matrix() for wxyz in wxyzs])
SH_C0 = 0.28209479177387814

plydata = PlyData.read(ply_file_path)
v = plydata["vertex"]
positions = onp.stack([v["x"], v["y"], v["z"]], axis=-1)
scales = onp.exp(onp.stack([v["scale_0"], v["scale_1"], v["scale_2"]], axis=-1))
wxyzs = onp.stack([v["rot_0"], v["rot_1"], v["rot_2"], v["rot_3"]], axis=1)
colors = 0.5 + SH_C0 * onp.stack([v["f_dc_0"], v["f_dc_1"], v["f_dc_2"]], axis=1)
opacities = 1.0 / (1.0 + onp.exp(-v["opacity"][:, None]))

Rs = tf.SO3(wxyzs).as_matrix()
covariances = onp.einsum(
"nij,njk,nlk->nil", Rs, onp.eye(3)[None, :, :] * scales[:, None, :] ** 2, Rs
)
if center:
positions -= onp.mean(positions, axis=0, keepdims=True)
print("PLY file loaded")

num_gaussians = len(v)
print(
f"PLY file with {num_gaussians=} loaded in {time.time() - start_time} seconds"
)
return {
"centers": positions,
# Colors should have shape (N, 3).
"rgbs": colors,
"opacities": opacities,
# Covariances should have shape (N, 3, 3).
"covariances": covariances,
}


def main(splat_paths: tuple[Path, ...], test_multisplat: bool = False) -> None:
server = viser.ViserServer(share=True)
def main(splat_paths: tuple[Path, ...]) -> None:
server = viser.ViserServer()
server.gui.configure_theme(dark_mode=True)
gui_reset_up = server.gui.add_button(
"Reset up direction",
Expand All @@ -151,14 +129,21 @@ def _(event: viser.GuiEvent) -> None:
raise SystemExit("Please provide a filepath to a .splat or .ply file.")

server.scene.add_transform_controls(f"/{i}")
server.scene._add_gaussian_splats(
gs_handle = server.scene._add_gaussian_splats(
f"/{i}/gaussian_splats",
centers=splat_data["centers"],
rgbs=splat_data["rgbs"],
opacities=splat_data["opacities"],
covariances=splat_data["covariances"],
)

remove_button = server.gui.add_button(f"Remove splat object {i}")

@remove_button.on_click
def _(_, gs_handle=gs_handle, remove_button=remove_button) -> None:
gs_handle.remove()
remove_button.remove()

while True:
time.sleep(10.0)

Expand Down
9 changes: 8 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ classifiers = [
dependencies = [
"websockets>=10.4",
"numpy>=1.0.0",
"msgpack>=1.0.7",
"msgspec>=0.18.6",
"imageio>=2.0.0",
"pyliblzfse>=0.4.1; platform_system!='Windows'",
"scikit-image>=0.18.0",
Expand Down Expand Up @@ -71,6 +71,13 @@ examples = [
viser = ["py.typed", "*.pyi", "_icons/tabler-icons.tar", "client/**/*", "client/**/.*"]
# </>

[tool.setuptools.exclude-package-data]
# We exclude node_modules to prevent long build times for wheels when
# installing from source, eg via `pip install .`.
#
# https://github.com/nerfstudio-project/viser/issues/271
viser = ["**/node_modules/**"]

[project.scripts]
viser-dev-checks = "viser.scripts.dev_checks:entrypoint"

Expand Down
Loading

0 comments on commit a5a41b7

Please sign in to comment.