Skip to content

Commit

Permalink
Init XR camera's transform correctly (#72)
Browse files Browse the repository at this point in the history
* Init XR camera's transform correctly

* Lint fixes
  • Loading branch information
willeastcott authored Dec 13, 2024
1 parent c523176 commit 936764e
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 10 deletions.
2 changes: 1 addition & 1 deletion examples/animation.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<pc-asset id="camera-controls" src="../node_modules/playcanvas/scripts/esm/camera-controls.mjs" preload></pc-asset>
<pc-asset id="shadow-catcher" src="scripts/shadow-catcher.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="lake-bed" src="assets/skies/dry-lake-bed-2k.hdr" preload></pc-asset>
<pc-asset id="t-rex" src="assets/models/t-rex.glb" preload></pc-asset>
<!-- Scene -->
Expand Down
2 changes: 1 addition & 1 deletion examples/basic-shapes.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- Assets -->
<pc-asset id="camera-controls" src="../node_modules/playcanvas/scripts/esm/camera-controls.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<!-- Materials -->
<pc-material id="crimson" diffuse="crimson"></pc-material>
<pc-material id="mediumseagreen" diffuse="mediumseagreen"></pc-material>
Expand Down
2 changes: 1 addition & 1 deletion examples/car-configurator.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<pc-asset id="camera-frame" src="scripts/camera-frame.mjs" preload></pc-asset>
<pc-asset id="choose-color" src="scripts/choose-color.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="studio" src="assets/skies/octagon-lamps-photo-studio-2k.hdr" preload></pc-asset>
<pc-asset id="car" src="assets/models/porsche-911-carrera-4s.glb" preload></pc-asset>
<!-- Scene -->
Expand Down
2 changes: 1 addition & 1 deletion examples/glb.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<pc-asset id="camera-controls" src="../node_modules/playcanvas/scripts/esm/camera-controls.mjs" preload></pc-asset>
<pc-asset id="rotate" src="scripts/rotate.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="studio" src="assets/skies/octagon-lamps-photo-studio-2k.hdr" preload></pc-asset>
<pc-asset id="cube" src="assets/models/playcanvas-cube.glb" preload></pc-asset>
<!-- Scene -->
Expand Down
2 changes: 1 addition & 1 deletion examples/physics.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<pc-asset id="camera-controls" src="../node_modules/playcanvas/scripts/esm/camera-controls.mjs" preload></pc-asset>
<pc-asset id="grid" src="scripts/grid.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="studio" src="assets/skies/octagon-lamps-photo-studio-2k.hdr" preload></pc-asset>
<pc-asset id="cube" src="assets/models/playcanvas-cube.glb" preload></pc-asset>
<!-- Scene -->
Expand Down
2 changes: 1 addition & 1 deletion examples/positional-sound.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- Assets -->
<pc-asset id="orbit" src="scripts/orbit.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="lake-bed" src="assets/skies/dry-lake-bed-2k.hdr" preload></pc-asset>
<pc-asset id="robot" src="assets/models/walking-robot.glb" preload></pc-asset>
<pc-asset id="footsteps" src="assets/sounds/footsteps.mp3" preload></pc-asset>
Expand Down
162 changes: 162 additions & 0 deletions examples/scripts/xr-navigation.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { Color, Quat, Script, Vec3 } from 'playcanvas';

/** @import { XrInputSource } from 'playcanvas' */

/**
* Handles VR teleportation navigation by allowing users to point and teleport using either
* hands or tracked controllers. Shows a visual ray and target indicator when the user holds
* the select button (trigger) or makes a pinch gesture with hand tracking, and teleports to
* the target location when released.
*
* This script should be attached to a parent entity of the camera entity used for the XR
* session. Use it in conjunction with the `XrControllers` script to handle the rendering of
* the controllers.
*/
export class XrNavigation extends Script {
/** @type {Set<XrInputSource>} */
inputSources = new Set();

/** @type {Map<XrInputSource, boolean>} */
activePointers = new Map();

validColor = new Color(0, 1, 0); // Green for valid teleport

invalidColor = new Color(1, 0, 0); // Red for invalid teleport

/** @type {Map<XrInputSource, { handleSelectStart: Function, handleSelectEnd: Function }>} */
inputHandlers = new Map();

initialize() {
const positionRoot = new Vec3();
const rotationRoot = new Quat();
const positionCamera = new Vec3();
const rotationCamera = new Quat();

this.app.xr.on('start', () => {
positionRoot.copy(this.entity.getPosition());
rotationRoot.copy(this.entity.getRotation());

const camera = this.entity.findComponent('camera')?.entity;
if (camera) {
positionCamera.copy(camera.getPosition());
rotationCamera.copy(camera.getRotation());

this.entity.setPosition(positionCamera.x, 0, positionCamera.z);
this.entity.lookAt(Vec3.ZERO, Vec3.UP);
}
});

this.app.xr.on('end', () => {
this.entity.setPosition(positionRoot);
this.entity.setRotation(rotationRoot);

const camera = this.entity.findComponent('camera')?.entity;
if (camera) {
camera.setPosition(positionCamera);
camera.setRotation(rotationCamera);
}
});

this.app.xr.input.on('add', (inputSource) => {
const handleSelectStart = () => {
this.activePointers.set(inputSource, true);
};

const handleSelectEnd = () => {
this.activePointers.set(inputSource, false);
this.tryTeleport(inputSource);
};

// Attach the handlers
inputSource.on('selectstart', handleSelectStart);
inputSource.on('selectend', handleSelectEnd);

// Store the handlers in the map
this.inputHandlers.set(inputSource, { handleSelectStart, handleSelectEnd });
this.inputSources.add(inputSource);
});

this.app.xr.input.on('remove', (inputSource) => {
const handlers = this.inputHandlers.get(inputSource);
if (handlers) {
inputSource.off('selectstart', handlers.handleSelectStart);
inputSource.off('selectend', handlers.handleSelectEnd);
this.inputHandlers.delete(inputSource);
}
this.activePointers.delete(inputSource);
this.inputSources.delete(inputSource);
});
}

findPlaneIntersection(origin, direction) {
// Find intersection with y=0 plane
if (Math.abs(direction.y) < 0.00001) return null; // Ray is parallel to plane

const t = -origin.y / direction.y;
if (t < 0) return null; // Intersection is behind the ray

return new Vec3(
origin.x + direction.x * t,
0,
origin.z + direction.z * t
);
}

tryTeleport(inputSource) {
const origin = inputSource.getOrigin();
const direction = inputSource.getDirection();

const hitPoint = this.findPlaneIntersection(origin, direction);
if (hitPoint) {
const cameraY = this.entity.getPosition().y;
hitPoint.y = cameraY;
this.entity.setPosition(hitPoint);
}
}

update() {
for (const inputSource of this.inputSources) {
// Only show ray when trigger is pressed
if (!this.activePointers.get(inputSource)) continue;

const start = inputSource.getOrigin();
const direction = inputSource.getDirection();

const hitPoint = this.findPlaneIntersection(start, direction);

if (hitPoint) {
// Draw line to intersection point
this.app.drawLine(start, hitPoint, this.validColor);
this.drawTeleportIndicator(hitPoint);
} else {
// Draw full length ray if no intersection
const end = start.clone().add(
direction.clone().mulScalar(100)
);
this.app.drawLine(start, end, this.invalidColor);
}
}
}

drawTeleportIndicator(point) {
// Draw a circle at the teleport point
const segments = 32;
const radius = 0.2;

for (let i = 0; i < segments; i++) {
const angle1 = (i / segments) * Math.PI * 2;
const angle2 = ((i + 1) / segments) * Math.PI * 2;

const x1 = point.x + Math.cos(angle1) * radius;
const z1 = point.z + Math.sin(angle1) * radius;
const x2 = point.x + Math.cos(angle2) * radius;
const z2 = point.z + Math.sin(angle2) * radius;

this.app.drawLine(
new Vec3(x1, 0.01, z1), // Slightly above ground to avoid z-fighting
new Vec3(x2, 0.01, z2),
this.validColor
);
}
}
}
2 changes: 1 addition & 1 deletion examples/shoe-configurator.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<pc-asset id="camera-controls" src="../node_modules/playcanvas/scripts/esm/camera-controls.mjs" preload></pc-asset>
<pc-asset id="shadow-catcher" src="scripts/shadow-catcher.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="studio" src="assets/skies/octagon-lamps-photo-studio-2k.hdr" preload></pc-asset>
<pc-asset id="shoe" src="assets/models/shoe.glb" preload></pc-asset>
<!-- Scene -->
Expand Down
2 changes: 1 addition & 1 deletion examples/splat.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- Assets -->
<pc-asset id="camera-controls" src="../node_modules/playcanvas/scripts/esm/camera-controls.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="angel" src="assets/splats/angel.compressed.ply" preload></pc-asset>
<pc-asset id="rotunda" src="assets/skies/sepulchral-chapel-rotunda-4k.webp" preload></pc-asset>
<!-- Scene -->
Expand Down
2 changes: 1 addition & 1 deletion examples/text3d.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<pc-asset id="grid" src="scripts/grid.mjs" preload></pc-asset>
<pc-asset id="text3d" src="scripts/text3d.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="arial" src="assets/fonts/arial.ttf" type="binary" preload></pc-asset>
<!-- Scene -->
<pc-scene>
Expand Down
2 changes: 1 addition & 1 deletion examples/video-texture.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<pc-asset id="shadow-catcher" src="scripts/shadow-catcher.mjs" preload></pc-asset>
<pc-asset id="video-texture" src="scripts/video-texture.mjs" preload></pc-asset>
<pc-asset id="xr-controllers" src="../node_modules/playcanvas/scripts/esm/xr-controllers.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="../node_modules/playcanvas/scripts/esm/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="xr-navigation" src="scripts/xr-navigation.mjs" preload></pc-asset>
<pc-asset id="studio" src="assets/skies/octagon-lamps-photo-studio-2k.hdr" preload></pc-asset>
<pc-asset id="vintage-pc" src="assets/models/vintage-pc.glb" preload></pc-asset>
<!-- Scene -->
Expand Down

0 comments on commit 936764e

Please sign in to comment.