Skip to content

Commit

Permalink
Fix state update bugs, version bump
Browse files Browse the repository at this point in the history
  • Loading branch information
brentyi committed Nov 29, 2023
1 parent ede1080 commit c161525
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 126 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "viser"
version = "0.1.11"
version = "0.1.12"
description = "3D visualization + Python"
readme = "README.md"
license = { text="MIT" }
Expand Down
135 changes: 68 additions & 67 deletions src/viser/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ function ViewerRoot() {
function ViewerContents() {
const viewer = React.useContext(ViewerContext)!;
const control_layout = viewer.useGui((state) => state.theme.control_layout);
const [aboutModelOpened, { open: openAbout, close: closeAbout }] =
useDisclosure(false);
return (
<MantineProvider
withGlobalStyles
Expand Down Expand Up @@ -174,30 +172,7 @@ function ViewerContents() {
<FrameSynchronizedMessageHandler />
</ViewerCanvas>
{viewer.useGui((state) => state.theme.show_logo) ? (
<>
<Box
sx={{
position: "absolute",
bottom: "1em",
left: "1em",
cursor: "pointer",
}}
component="a"
onClick={openAbout}
title="About Viser"
>
<Image src="/logo.svg" width="2.5em" height="auto" />
</Box>
<Modal
opened={aboutModelOpened}
onClose={closeAbout}
size="xl"
withCloseButton={false}
ta="center"
>
<AboutViser />
</Modal>
</>
<ViserLogo />
) : null}
</Box>
</MediaQuery>
Expand Down Expand Up @@ -433,48 +408,74 @@ export function Root() {
);
}

function AboutViser() {
/** Logo. When clicked, opens an info modal. */
function ViserLogo() {
const [aboutModelOpened, { open: openAbout, close: closeAbout }] =
useDisclosure(false);
return (
<Box>
<Image
src={
useMantineTheme().colorScheme === "dark"
? "viser_banner_dark.svg"
: "viser_banner.svg"
}
radius="xs"
/>
<Box mt="1.625em">
Viser is a 3D visualization toolkit developed at UC Berkeley.
<>
<Box
sx={{
position: "absolute",
bottom: "1em",
left: "1em",
cursor: "pointer",
}}
component="a"
onClick={openAbout}
title="About Viser"
>
<Image src="/logo.svg" width="2.5em" height="auto" />
</Box>
<p>
<Anchor
href="https://github.com/nerfstudio-project/"
target="_blank"
fw="600"
sx={{ "&:focus": { outline: "none" } }}
>
Nerfstudio
</Anchor>
&nbsp;&nbsp;&bull;&nbsp;&nbsp;
<Anchor
href="https://github.com/nerfstudio-project/viser"
target="_blank"
fw="600"
sx={{ "&:focus": { outline: "none" } }}
>
GitHub
</Anchor>
&nbsp;&nbsp;&bull;&nbsp;&nbsp;
<Anchor
href="https://viser.studio"
target="_blank"
fw="600"
sx={{ "&:focus": { outline: "none" } }}
>
Documentation
</Anchor>
</p>
</Box>
<Modal
opened={aboutModelOpened}
onClose={closeAbout}
withCloseButton={false}
size="xl"
ta="center"
>
<Box>
<Image
src={
useMantineTheme().colorScheme === "dark"
? "viser_banner_dark.svg"
: "viser_banner.svg"
}
radius="xs"
/>
<Box mt="1.625em">
Viser is a 3D visualization toolkit developed at UC Berkeley.
</Box>
<p>
<Anchor
href="https://github.com/nerfstudio-project/"
target="_blank"
fw="600"
sx={{ "&:focus": { outline: "none" } }}
>
Nerfstudio
</Anchor>
&nbsp;&nbsp;&bull;&nbsp;&nbsp;
<Anchor
href="https://github.com/nerfstudio-project/viser"
target="_blank"
fw="600"
sx={{ "&:focus": { outline: "none" } }}
>
GitHub
</Anchor>
&nbsp;&nbsp;&bull;&nbsp;&nbsp;
<Anchor
href="https://viser.studio"
target="_blank"
fw="600"
sx={{ "&:focus": { outline: "none" } }}
>
Documentation
</Anchor>
</p>
</Box>
</Modal>
</>
);
}
123 changes: 70 additions & 53 deletions src/viser/client/src/SceneTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Select } from "@react-three/postprocessing";
import { immerable } from "immer";
import { Text } from "@mantine/core";
import { useSceneTreeState } from "./SceneTreeState";
import { ErrorBoundary } from "react-error-boundary";

export type MakeObject<T extends THREE.Object3D = THREE.Object3D> = (
ref: React.Ref<T>,
Expand Down Expand Up @@ -176,6 +177,8 @@ export function SceneNodeThreeObject(props: {
const visibility = nodeAttributes.visibility;
if (visibility !== undefined) {
obj.visible = visibility;
} else {
obj.visible = true;
}

let changed = false;
Expand Down Expand Up @@ -214,61 +217,75 @@ export function SceneNodeThreeObject(props: {
} else if (clickable) {
return (
<>
<group
// Instead of using onClick, we use onPointerDown/Move/Up to check mouse drag,
// and only send a click if the mouse hasn't moved between the down and up events.
// - onPointerDown resets the click state (dragged = false)
// - onPointerMove, if triggered, sets dragged = true
// - onPointerUp, if triggered, sends a click if dragged = false.
// Note: It would be cool to have dragged actions too...
onPointerDown={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
const state = dragInfo.current;
state.startClientX = e.clientX;
state.startClientY = e.clientY;
state.dragging = false;
}}
onPointerMove={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
const state = dragInfo.current;
const deltaX = e.clientX - state.startClientX;
const deltaY = e.clientY - state.startClientY;
// Minimum motion.
if (Math.abs(deltaX) <= 3 && Math.abs(deltaY) <= 3) return;
state.dragging = true;
}}
onPointerUp={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
const state = dragInfo.current;
if (state.dragging) return;
sendClicksThrottled({
type: "SceneNodeClickMessage",
name: props.name,
// Note that the threejs up is +Y, but we expose a +Z up.
ray_origin: [e.ray.origin.x, -e.ray.origin.z, e.ray.origin.y],
ray_direction: [
e.ray.direction.x,
-e.ray.direction.z,
e.ray.direction.y,
],
});
}}
onPointerOver={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
setHovered(true);
}}
onPointerOut={() => {
if (!isDisplayed()) return;
setHovered(false);
<ErrorBoundary
fallbackRender={() => {
// This sometimes (but very rarely) catches a race condition when
// we remove scene nodes. I would guess it's related to portaling,
// but the issue is unnoticeable with ErrorBoundary in-place so not
// debugging further for now...
console.error(
"There was an error rendering a scene node object:",
objNode,
);
return null;
}}
>
<Select enabled={hovered}>{objNode}</Select>
</group>
{children}
<group
// Instead of using onClick, we use onPointerDown/Move/Up to check mouse drag,
// and only send a click if the mouse hasn't moved between the down and up events.
// - onPointerDown resets the click state (dragged = false)
// - onPointerMove, if triggered, sets dragged = true
// - onPointerUp, if triggered, sends a click if dragged = false.
// Note: It would be cool to have dragged actions too...
onPointerDown={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
const state = dragInfo.current;
state.startClientX = e.clientX;
state.startClientY = e.clientY;
state.dragging = false;
}}
onPointerMove={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
const state = dragInfo.current;
const deltaX = e.clientX - state.startClientX;
const deltaY = e.clientY - state.startClientY;
// Minimum motion.
if (Math.abs(deltaX) <= 3 && Math.abs(deltaY) <= 3) return;
state.dragging = true;
}}
onPointerUp={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
const state = dragInfo.current;
if (state.dragging) return;
sendClicksThrottled({
type: "SceneNodeClickMessage",
name: props.name,
// Note that the threejs up is +Y, but we expose a +Z up.
ray_origin: [e.ray.origin.x, -e.ray.origin.z, e.ray.origin.y],
ray_direction: [
e.ray.direction.x,
-e.ray.direction.z,
e.ray.direction.y,
],
});
}}
onPointerOver={(e) => {
if (!isDisplayed()) return;
e.stopPropagation();
setHovered(true);
}}
onPointerOut={() => {
if (!isDisplayed()) return;
setHovered(false);
}}
>
<Select enabled={hovered}>{objNode}</Select>
</group>
{children}
</ErrorBoundary>
</>
);
} else {
Expand Down
14 changes: 11 additions & 3 deletions src/viser/client/src/Titlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,11 @@ export function Titlebar() {
zIndex: 5,
}}
>
<Paper p="xs" shadow="0 0 0.8em 0 rgba(0,0,0,0.1)" sx={{ height: "100%" }}>
<Paper
p="xs"
shadow="0 0 0.8em 0 rgba(0,0,0,0.1)"
sx={{ height: "100%" }}
>
<Container
fluid
sx={() => ({
Expand All @@ -167,7 +171,9 @@ export function Titlebar() {
},
})}
>
{buttons?.map((btn) => TitlebarButton(btn))}
{buttons?.map((btn, index) => (
<TitlebarButton {...btn} key={index} />
))}
</Group>
<Burger
size="sm"
Expand Down Expand Up @@ -199,7 +205,9 @@ export function Titlebar() {
padding: burgerOpen ? "1rem" : "0",
})}
>
{buttons?.map((btn) => MobileTitlebarButton(btn))}
{buttons?.map((btn, index) => (
<MobileTitlebarButton {...btn} key={index} />
))}
</Paper>
</Paper>
</Header>
Expand Down
12 changes: 10 additions & 2 deletions src/viser/client/src/WebsocketInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ function useMessageHandler() {
);
}
addSceneNode(node);

const attrs = viewer.nodeAttributesFromName.current;
if (node.name in attrs) {
delete attrs[node.name];
}
}

const mantineTheme = useViserMantineTheme();
Expand Down Expand Up @@ -594,9 +599,12 @@ function useMessageHandler() {
new SceneNode<THREE.Group>(
message.name,
(ref) => {
// We wrap with <group /> because Html doesn't implement THREE.Object3D.
// We wrap with <group /> because Html doesn't implement
// THREE.Object3D. The initial position is intended to be
// off-screen; it will be overwritten with the actual position
// after the component is mounted.
return (
<group ref={ref}>
<group ref={ref} position={new THREE.Vector3(1e8, 1e8, 1e8)}>
<Html prepend={false}>
<MantineProvider
withGlobalStyles
Expand Down

0 comments on commit c161525

Please sign in to comment.