immersive2/src/diagram/functions/buildEntityActionManager.ts
Michael Mainguy 0ad61bdde9 Fix XR component positioning to appear in front of user
- Use camera.getDirection() instead of manual Euler angle calculation to properly account for camera transform hierarchy
- Negate forward offsets to position objects in -Z direction (user faces -Z by design)
- Replace expensive HighlightLayer hover effect with lightweight EdgesRenderer (20-50x faster)
- Add comprehensive debug logging for position calculations

The camera has a parent transform with 180° Y rotation, causing the user to face -Z in world space. Components now correctly position in front of the user when entering XR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 22:41:51 -06:00

60 lines
2.3 KiB
TypeScript

import {
ActionManager,
Color4,
ExecuteCodeAction,
InstancedMesh,
Observable,
} from "@babylonjs/core";
import log from "loglevel";
import {DefaultScene} from "../../defaultScene";
import {ControllerEventType} from "../../controllers/types/controllerEventType";
import {ControllerEvent} from "../../controllers/types/controllerEvent";
export function buildEntityActionManager(controllerObservable: Observable<ControllerEvent>) {
const logger = log.getLogger('buildEntityActionManager');
const actionManager = new ActionManager(DefaultScene.Scene);
/*actionManager.registerAction(
new PlaySoundAction(ActionManager.OnPointerOverTrigger, sounds.tick));*/
actionManager.registerAction(
new ExecuteCodeAction(ActionManager.OnPointerOverTrigger, (evt) => {
if (evt.meshUnderPointer) {
try {
const mesh = evt.meshUnderPointer as InstancedMesh;
if (mesh.sourceMesh && !mesh.sourceMesh.edgesRenderer) {
// Enable edges rendering on the source mesh
mesh.sourceMesh.enableEdgesRendering(0.99);
mesh.sourceMesh.edgesWidth = 4.0;
mesh.sourceMesh.edgesColor = new Color4(1.5, 1.5, 1.5, 1.0);
// Track that edges are enabled
mesh.metadata = mesh.metadata || {};
mesh.metadata.edgesEnabled = true;
}
} catch (e) {
logger.error(e);
}
}
controllerObservable.notifyObservers({
type: ControllerEventType.PULSE,
gripId: evt?.additionalData?.pickResult?.gripTransform?.id
});
logger.debug(evt);
})
);
actionManager.registerAction(
new ExecuteCodeAction(ActionManager.OnPointerOutTrigger, (evt) => {
try {
const mesh = evt.source as InstancedMesh;
if (mesh.metadata?.edgesEnabled && mesh.sourceMesh?.edgesRenderer) {
mesh.sourceMesh.disableEdgesRendering();
mesh.metadata.edgesEnabled = false;
}
} catch (e) {
logger.error(e);
}
logger.debug(evt);
})
);
return actionManager;
}