Skip to content

Commit

Permalink
working again
Browse files Browse the repository at this point in the history
  • Loading branch information
brentyi committed Apr 29, 2024
1 parent e9e2fa3 commit 78b55aa
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 73 deletions.
39 changes: 35 additions & 4 deletions src/viser/_message_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
from . import transforms as tf
from ._scene_handles import (
BatchedAxesHandle,
BoneHandle,
BoneState,
CameraFrustumHandle,
FrameHandle,
GlbHandle,
Expand Down Expand Up @@ -858,7 +860,8 @@ def add_mesh_skinned(
stacklevel=2,
)

assert skin_weights.shape == (vertices.shape[0], len(bone_wxyzs))
num_bones = len(bone_wxyzs)
assert skin_weights.shape == (vertices.shape[0], num_bones)

# Take the four biggest indices.
top4_skin_indices = onp.argsort(skin_weights, axis=-1)[:, -4:]
Expand All @@ -871,6 +874,8 @@ def add_mesh_skinned(

bone_wxyzs = onp.asarray(bone_wxyzs)
bone_positions = onp.asarray(bone_positions)
assert bone_wxyzs.shape == (num_bones, 4)
assert bone_positions.shape == (num_bones, 3)
self._queue(
_messages.SkinnedMeshMessage(
name,
Expand All @@ -884,13 +889,39 @@ def add_mesh_skinned(
flat_shading=flat_shading,
side=side,
material=material,
bone_wxyzs=bone_wxyzs.astype(onp.float32),
bone_positions=bone_positions.astype(onp.float32),
bone_wxyzs=tuple(
(
float(wxyz[0]),
float(wxyz[1]),
float(wxyz[2]),
float(wxyz[3]),
)
for wxyz in bone_wxyzs.astype(onp.float32)
),
bone_positions=tuple(
(float(xyz[0]), float(xyz[1]), float(xyz[2]))
for xyz in bone_positions.astype(onp.float32)
),
skin_indices=top4_skin_indices.astype(onp.uint16),
skin_weights=top4_skin_weights.astype(onp.float32),
)
)
return SkinnedMeshHandle._make(self, name, wxyz, position, visible)
handle = MeshHandle._make(self, name, wxyz, position, visible)
return SkinnedMeshHandle(
handle._impl,
bones=tuple(
BoneHandle(
_impl=BoneState(
name=name,
api=self,
bone_index=i,
wxyz=bone_wxyzs[i],
position=bone_positions[i],
)
)
for i in range(num_bones)
),
)

def add_mesh_simple(
self,
Expand Down
36 changes: 32 additions & 4 deletions src/viser/_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ class SkinnedMeshMessage(MeshMessage):
Vertices are internally canonicalized to float32, faces to uint32."""

bone_wxyzs: onpt.NDArray[onp.float32]
bone_positions: onpt.NDArray[onp.float32]
bone_wxyzs: Tuple[Tuple[float, float, float, float], ...]
bone_positions: Tuple[Tuple[float, float, float], ...]
skin_indices: onpt.NDArray[onp.uint32]
skin_weights: onpt.NDArray[onp.float32]

Expand All @@ -276,8 +276,36 @@ def __post_init__(self):
== self.skin_weights.shape
== (self.vertices.shape[0], 4)
)
assert self.bone_wxyzs.shape[-1] == 4
assert self.bone_positions.shape[-1] == 3


@dataclasses.dataclass
class SetBoneOrientationMessage(Message):
"""Server -> client message to set a skinned mesh bone's orientation.
As with all other messages, transforms take the `T_parent_local` convention."""

name: str
bone_index: int
wxyz: Tuple[float, float, float, float]

@override
def redundancy_key(self) -> str:
return type(self).__name__ + "-" + self.name + "-" + str(self.bone_index)


@dataclasses.dataclass
class SetBonePositionMessage(Message):
"""Server -> client message to set a skinned mesh bone's position.
As with all other messages, transforms take the `T_parent_local` convention."""

name: str
bone_index: int
position: Tuple[float, float, float]

@override
def redundancy_key(self) -> str:
return type(self).__name__ + "-" + self.name + "-" + str(self.bone_index)


@dataclasses.dataclass
Expand Down
58 changes: 58 additions & 0 deletions src/viser/_scene_handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,64 @@ class MeshHandle(_ClickableSceneNodeHandle):
class SkinnedMeshHandle(_ClickableSceneNodeHandle):
"""Handle for skinned mesh objects."""

bones: Tuple[BoneHandle, ...]
"""Bones of the skinned mesh. These handles can be used for reading and
writing poses, which are defined relative to the mesh root."""


@dataclasses.dataclass
class BoneState:
name: str
api: MessageApi
bone_index: int
wxyz: onp.ndarray
position: onp.ndarray


@dataclasses.dataclass
class BoneHandle:
"""Handle for reading and writing the poses of bones in a skinned mesh."""

_impl: BoneState

@property
def wxyz(self) -> onp.ndarray:
"""Orientation of the bone. This is the quaternion representation of the R
in `p_parent = [R | t] p_local`. Synchronized to clients automatically when assigned.
"""
return self._impl.wxyz

@wxyz.setter
def wxyz(self, wxyz: Tuple[float, float, float, float] | onp.ndarray) -> None:
from ._message_api import cast_vector

wxyz_cast = cast_vector(wxyz, 4)
self._impl.wxyz = onp.asarray(wxyz)
self._impl.api._queue(
_messages.SetBoneOrientationMessage(
self._impl.name, self._impl.bone_index, wxyz_cast
)
)

@property
def position(self) -> onp.ndarray:
"""Position of the bone. This is equivalent to the t in
`p_parent = [R | t] p_local`. Synchronized to clients automatically when assigned.
"""
return self._impl.position

@position.setter
def position(self, position: Tuple[float, float, float] | onp.ndarray) -> None:
from ._message_api import cast_vector

position_cast = cast_vector(position, 3)
self._impl.position = onp.asarray(position)
self._impl.api._queue(
_messages.SetBonePositionMessage(
self._impl.name, self._impl.bone_index, position_cast
)
)


@dataclasses.dataclass
class GlbHandle(_ClickableSceneNodeHandle):
Expand Down
11 changes: 11 additions & 0 deletions src/viser/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ export type ViewerContextContents = {
}>;
// 2D canvas for drawing -- can be used to give feedback on cursor movement, or more.
canvas2dRef: React.MutableRefObject<HTMLCanvasElement | null>;
// Poses for bones in skinned meshes.
skinnedMeshState: React.MutableRefObject<{
[name: string]: {
initialized: boolean;
poses: {
wxyz: [number, number, number, number];
position: [number, number, number];
}[];
};
}>;
};
export const ViewerContext = React.createContext<null | ViewerContextContents>(
null,
Expand Down Expand Up @@ -152,6 +162,7 @@ function ViewerRoot() {
listening: false,
}),
canvas2dRef: React.useRef(null),
skinnedMeshState: React.useRef({}),
};

return (
Expand Down
Loading

0 comments on commit 78b55aa

Please sign in to comment.