fix(handtracking): reduce GPU pressure on WebGL context loss
Several mitigations against the WebGL context lost that fires when hand tracking starts on a loaded scene: - Canvas: fixed DPR [1,1], antialias off, scoped id="game-canvas", context-lost handler releases MediaPipe and logs GPU memory counters - optimizeGLTFScene: cap anisotropy at 2 and stop forcing mipmaps / needsUpdate on every pass — avoids massive texture re-uploads - MediaPipe: force CPU delegate (HAND_TRACKING_BROWSER_DELEGATE), cache the landmarker instance, and expose releaseBrowserHandLandmarker - useBrowserHandTracking / useRemoteHandTracking: idempotent cleanup guarded by a cleanedUp flag, try/catch around the detect loop, and release of the landmarker on stop - World: mount HandTrackingGlove only when the matching hand is actually present in the snapshot (status connected + hands.length > 0) - HandTrackingGlove: drop the eager useGLTF.preload that was running at startup whether or not hand tracking was used Does not yet absorb the React StrictMode double-mount — that is the follow-up commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+21
-5
@@ -31,11 +31,20 @@ import { CharacterSystem } from "@/world/characters/CharacterSystem";
|
||||
import { Player } from "@/world/player/Player";
|
||||
import { TestMap } from "@/world/debug/TestMap";
|
||||
import type { SceneLoadingChangeHandler } from "@/types/world/sceneLoading";
|
||||
import type { HandTrackingGloveHandedness } from "@/hooks/handTracking/useHandTrackingGloveStatus";
|
||||
import type { HandTrackingHand } from "@/types/handTracking/handTracking";
|
||||
|
||||
interface WorldProps {
|
||||
onLoadingStateChange?: SceneLoadingChangeHandler | undefined;
|
||||
}
|
||||
|
||||
function hasTrackedHand(
|
||||
hands: HandTrackingHand[],
|
||||
handedness: HandTrackingGloveHandedness,
|
||||
): boolean {
|
||||
return hands.some((hand) => hand.handedness.toLowerCase() === handedness);
|
||||
}
|
||||
|
||||
export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element {
|
||||
useEnvironmentDebug();
|
||||
useMapPerformanceDebug();
|
||||
@@ -49,7 +58,7 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element {
|
||||
(state) => state.showPlayerModel,
|
||||
);
|
||||
const showDebugOctree = useDebugVisualsStore((state) => state.showOctree);
|
||||
const { status, usageStatus } = useHandTrackingSnapshot();
|
||||
const { hands, status, usageStatus } = useHandTrackingSnapshot();
|
||||
const {
|
||||
octree,
|
||||
gameplayReady,
|
||||
@@ -63,8 +72,11 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element {
|
||||
? PLAYER_SPAWN_POSITION_GAME
|
||||
: PLAYER_SPAWN_POSITION_PHYSICS;
|
||||
const showHandTrackingGloves =
|
||||
sceneMode === "physics" ||
|
||||
(status !== "idle" && usageStatus !== "inactive");
|
||||
status === "connected" && usageStatus !== "inactive" && hands.length > 0;
|
||||
const showLeftHandTrackingGlove =
|
||||
showHandTrackingGloves && hasTrackedHand(hands, "left");
|
||||
const showRightHandTrackingGlove =
|
||||
showHandTrackingGloves && hasTrackedHand(hands, "right");
|
||||
const spawnPlayer =
|
||||
cameraMode !== "debug" &&
|
||||
(sceneMode === "game" ? gameplayReady : octree !== null);
|
||||
@@ -82,8 +94,12 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element {
|
||||
) : null}
|
||||
{showHandTrackingGloves ? (
|
||||
<Suspense fallback={null}>
|
||||
<HandTrackingGlove handedness="left" />
|
||||
<HandTrackingGlove handedness="right" />
|
||||
{showLeftHandTrackingGlove ? (
|
||||
<HandTrackingGlove handedness="left" />
|
||||
) : null}
|
||||
{showRightHandTrackingGlove ? (
|
||||
<HandTrackingGlove handedness="right" />
|
||||
) : null}
|
||||
</Suspense>
|
||||
) : null}
|
||||
{cameraMode === "debug" ? <DebugCameraControls /> : null}
|
||||
|
||||
Reference in New Issue
Block a user