Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More consistent API for environment map orientation #334

Merged
merged 3 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/viser/_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,9 @@ class EnvironmentMapMessage(Message):
background: bool
background_blurriness: float
background_intensity: float
background_rotation: tuple[float, float, float]
background_wxyz: Tuple[float, float, float, float]
environment_intensity: float
environment_rotation: tuple[float, float, float]
environment_wxyz: Tuple[float, float, float, float]


@dataclasses.dataclass
Expand Down
29 changes: 22 additions & 7 deletions src/viser/_scene_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ def set_up_direction(
(similar to Blender, 3DS Max, ROS, etc), the most common alternative is
+Y (OpenGL, Maya, etc).

In practice, the impact of this can improve (1) the ergonomics of
camera controls, which will default to the same up direction as the
scene, and (2) lighting, because the default lights and environment map
are oriented to match the scene's up direction.

Args:
direction: New up direction. Can either be a string (one of +x, +y,
+z, -x, -y, -z) or a length-3 direction vector.
Expand Down Expand Up @@ -491,9 +496,19 @@ def set_environment_map(
background: bool = False,
background_blurriness: float = 0.0,
background_intensity: float = 1.0,
background_rotation: tuple[float, float, float] = (0.0, 0.0, 0.0),
background_wxyz: tuple[float, float, float, float] | np.ndarray = (
1.0,
0.0,
0.0,
0.0,
),
environment_intensity: float = 1.0,
environment_rotation: tuple[float, float, float] = (0.0, 0.0, 0.0),
environment_wxyz: tuple[float, float, float, float] | np.ndarray = (
1.0,
0.0,
0.0,
0.0,
),
) -> None:
"""Set the environment map for the scene. This will set some lights and background.

Expand All @@ -502,19 +517,19 @@ def set_environment_map(
background: Show or hide the environment map in the background.
background_blurriness: Blur factor of the environment map background (0-1).
background_intensity: Intensity of the background.
background_rotation: Rotation of the background in radians.
background_wxyz: Orientation of the background.
environment_intensity: Intensity of the environment lighting.
environment_rotation: Rotation of the environment lighting in radians.
environment_wxyz: Orientation of the environment lighting.
"""
self._websock_interface.queue_message(
_messages.EnvironmentMapMessage(
hdri=hdri,
background=background,
background_blurriness=background_blurriness,
background_intensity=background_intensity,
background_rotation=background_rotation,
background_wxyz=cast_vector(background_wxyz, 4),
environment_intensity=environment_intensity,
environment_rotation=environment_rotation,
environment_wxyz=cast_vector(environment_wxyz, 4),
)
)

Expand All @@ -526,7 +541,7 @@ def enable_default_lights(self, enabled: bool = True) -> None:
see :meth:`SceneApi.set_environment_map()`.

Args:
enabled: True if user wants default lighting. False is user does
enabled: True if user wants default lighting. False if user does
not want default lighting.
"""
self._websock_interface.queue_message(_messages.EnableLightsMessage(enabled))
Expand Down
50 changes: 48 additions & 2 deletions src/viser/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,52 @@ function DefaultLights() {
);
const environmentMap = viewer.useSceneTree((state) => state.environmentMap);

// Environment map frames:
// - We want the `background_wxyz` and `environment_wxyz` to be in the Viser
// world frame. This is different from the threejs world frame, which should
// not be exposed to the user.
// - `backgroundRotation` and `environmentRotation` for the `Environment` component
// are in the threejs world frame.
const [R_threeworld_world, setR_threeworld_world] = React.useState(
// In Python, this will be set by `set_up_direction()`.
viewer.nodeAttributesFromName.current![""]!.wxyz!,
);
useFrame(() => {
const currentR_threeworld_world =
viewer.nodeAttributesFromName.current![""]!.wxyz!;
if (currentR_threeworld_world !== R_threeworld_world) {
setR_threeworld_world(currentR_threeworld_world);
}
});

const Rquat_threeworld_world = new THREE.Quaternion(
R_threeworld_world[1],
R_threeworld_world[2],
R_threeworld_world[3],
R_threeworld_world[0],
);
const Rquat_world_threeworld = Rquat_threeworld_world.clone().invert();
const backgroundRotation = new THREE.Euler().setFromQuaternion(
new THREE.Quaternion(
environmentMap.background_wxyz[1],
environmentMap.background_wxyz[2],
environmentMap.background_wxyz[3],
environmentMap.background_wxyz[0],
)
.premultiply(Rquat_threeworld_world)
.multiply(Rquat_world_threeworld),
);
const environmentRotation = new THREE.Euler().setFromQuaternion(
new THREE.Quaternion(
environmentMap.environment_wxyz[1],
environmentMap.environment_wxyz[2],
environmentMap.environment_wxyz[3],
environmentMap.environment_wxyz[0],
)
.premultiply(Rquat_threeworld_world)
.multiply(Rquat_world_threeworld),
);

let envMapNode;
if (environmentMap.hdri === null) {
envMapNode = null;
Expand All @@ -510,9 +556,9 @@ function DefaultLights() {
background={environmentMap.background}
backgroundBlurriness={environmentMap.background_blurriness}
backgroundIntensity={environmentMap.background_intensity}
backgroundRotation={environmentMap.background_rotation}
backgroundRotation={backgroundRotation}
environmentIntensity={environmentMap.environment_intensity}
environmentRotation={environmentMap.environment_rotation}
environmentRotation={environmentRotation}
/>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/viser/client/src/SceneTreeState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ export function useSceneTreeState(
background: false,
background_blurriness: 0,
background_intensity: 1,
background_rotation: [0, 0, 0],
background_wxyz: [1, 0, 0, 0],
environment_intensity: 1,
environment_rotation: [0, 0, 0],
environment_wxyz: [1, 0, 0, 0],
},
setClickable: (name, clickable) =>
set((state) => {
Expand Down
4 changes: 2 additions & 2 deletions src/viser/client/src/WebsocketMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,9 @@ export interface EnvironmentMapMessage {
background: boolean;
background_blurriness: number;
background_intensity: number;
background_rotation: [number, number, number];
background_wxyz: [number, number, number, number];
environment_intensity: number;
environment_rotation: [number, number, number];
environment_wxyz: [number, number, number, number];
}
/** Spot light message.
*
Expand Down
7 changes: 3 additions & 4 deletions src/viser/transforms/_so3.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import dataclasses
from typing import Tuple
from typing import NamedTuple, Tuple

import numpy as onp
import numpy.typing as onpt
Expand All @@ -11,8 +11,7 @@
from .utils import broadcast_leading_axes, get_epsilon


@dataclasses.dataclass(frozen=True)
class RollPitchYaw:
class RollPitchYaw(NamedTuple):
"""Struct containing roll, pitch, and yaw Euler angles."""

roll: onpt.NDArray[onp.floating]
Expand Down Expand Up @@ -131,7 +130,7 @@ def as_rpy_radians(self) -> RollPitchYaw:
"""Computes roll, pitch, and yaw angles. Uses the ZYX mobile robot convention.

Returns:
Named tuple containing Euler angles in radians.
NamedTuple containing Euler angles in radians.
"""
return RollPitchYaw(
roll=self.compute_roll_radians(),
Expand Down
Loading