Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions examples/jsm/webxr/ARButton.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
/**
* A utility class for creating a button that allows to initinate
* immersive AR sessions based on WebXR. The button can be created
* with a factory method and then appended ot the website's DOM.
*
* ```js
* document.body.appendChild( ARButton.createButton( renderer ) );
* ```
*
* @hideconstructor
*/
class ARButton {

/**
* Constructs a new AR button.
*
* @param {WebGLRenderer|WebGPURenderer} renderer - The renderer.
* @param {XRSessionInit} [sessionInit] - The a configuration object for the AR session.
* @return {HTMLElement} The button or an error message if `immersive-ar` isn't supported.
*/
static createButton( renderer, sessionInit = {} ) {

const button = document.createElement( 'button' );
Expand Down
82 changes: 82 additions & 0 deletions examples/jsm/webxr/OculusHandModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,77 @@ import { XRHandMeshModel } from './XRHandMeshModel.js';
const TOUCH_RADIUS = 0.01;
const POINTING_JOINT = 'index-finger-tip';

/**
* Represents an Oculus hand model.
*
* @augments Object3D
*/
class OculusHandModel extends Object3D {

/**
* Constructs a new Oculus hand model.
*
* @param {Group} controller - The hand controller.
* @param {?Loader} [loader=null] - A loader that is used to load hand models.
* @param {?Function} [onLoad=null] - A callback that is executed when a hand model has been loaded.
*/
constructor( controller, loader = null, onLoad = null ) {

super();

/**
* The hand controller.
*
* @type {Group}
*/
this.controller = controller;

/**
* The motion controller.
*
* @type {?MotionController}
* @default null
*/
this.motionController = null;

/**
* The model's environment map.
*
* @type {?Texture}
* @default null
*/
this.envMap = null;

/**
* A loader that is used to load hand models.
*
* @type {?Loader}
* @default null
*/
this.loader = loader;

/**
* A callback that is executed when a hand model has been loaded.
*
* @type {?Function}
* @default null
*/
this.onLoad = onLoad;

/**
* The path to the model repository.
*
* @type {?string}
* @default null
*/
this.path = null;

/**
* The model mesh.
*
* @type {Mesh}
* @default null
*/
this.mesh = null;

controller.addEventListener( 'connected', ( event ) => {
Expand All @@ -42,6 +100,12 @@ class OculusHandModel extends Object3D {

}

/**
* Overwritten with a custom implementation. Makes sure the motion controller updates the mesh.
*
* @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even
* when {@link Object3D#matrixWorldAutoUpdate} is set to `false`.
*/
updateMatrixWorld( force ) {

super.updateMatrixWorld( force );
Expand All @@ -54,6 +118,11 @@ class OculusHandModel extends Object3D {

}

/**
* Returns the pointer posiiton which is the position of the index finger tip.
*
* @return {Vector3|null} The pointer position. Returns `null` if not index finger tip joint was found.
*/
getPointerPosition() {

const indexFingerTip = this.controller.joints[ POINTING_JOINT ];
Expand All @@ -69,6 +138,13 @@ class OculusHandModel extends Object3D {

}

/**
* Returns `true` if the current pointer position (the index finger tip) intersections
* with the given box object.
*
* @param {Mesh} boxObject - The box object.
* @return {boolean} Whether an intersection was found or not.
*/
intersectBoxObject( boxObject ) {

const pointerPosition = this.getPointerPosition();
Expand All @@ -86,6 +162,12 @@ class OculusHandModel extends Object3D {

}

/**
* Executed actions depending on the interaction state with
* the given button.
*
* @param {Object} button - The button.
*/
checkButton( button ) {

if ( this.intersectBoxObject( button ) ) {
Expand Down
125 changes: 125 additions & 0 deletions examples/jsm/webxr/OculusHandPointerModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,97 @@ const ZAXIS = /* @__PURE__ */ new Vector3( 0, 0, 1 );
const CURSOR_RADIUS = 0.02;
const CURSOR_MAX_DISTANCE = 1.5;

/**
* Represents an Oculus hand pointer model.
*
* @augments Object3D
*/
class OculusHandPointerModel extends Object3D {

/**
* Constructs a new Oculus hand model.
*
* @param {Group} hand - The hand controller.
* @param {Group} controller - The WebXR controller in target ray space.
*/
constructor( hand, controller ) {

super();

/**
* The hand controller.
*
* @type {Group}
*/
this.hand = hand;

/**
* The WebXR controller in target ray space.
*
* @type {Group}
*/
this.controller = controller;

// Unused
this.motionController = null;
this.envMap = null;
this.mesh = null;

/**
* The pointer geometry.
*
* @type {?BufferGeometry}
* @default null
*/
this.pointerGeometry = null;

/**
* The pointer mesh.
*
* @type {?Mesh}
* @default null
*/
this.pointerMesh = null;

/**
* The pointer object that holds the pointer mesh.
*
* @type {?Object3D}
* @default null
*/
this.pointerObject = null;

/**
* Whether the model is pinched or not.
*
* @type {?boolean}
* @default false
*/
this.pinched = false;

/**
* Whether the model is attached or not.
*
* @type {?boolean}
* @default false
*/
this.attached = false;

/**
* The cursor object.
*
* @type {?Mesh}
* @default null
*/
this.cursorObject = null;

/**
* The internal raycaster used for detecting
* intersections.
*
* @type {?Raycaster}
* @default null
*/
this.raycaster = null;

this._onConnected = this._onConnected.bind( this );
Expand Down Expand Up @@ -143,6 +211,9 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Creates a pointer mesh and adds it to this model.
*/
createPointer() {

let i, j;
Expand Down Expand Up @@ -317,6 +388,12 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Overwritten with a custom implementation. Makes sure the internal pointer and raycaster are updated.
*
* @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even
* when {@link Object3D#matrixWorldAutoUpdate} is set to `false`.
*/
updateMatrixWorld( force ) {

super.updateMatrixWorld( force );
Expand All @@ -329,24 +406,47 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Returns `true` is the model is pinched.
*
* @return {boolean} Whether the model is pinched or not.
*/
isPinched() {

return this.pinched;

}

/**
* Sets the attached state.
*
* @param {boolean} attached - Whether the model is attached or not.
*/
setAttached( attached ) {

this.attached = attached;

}

/**
* Returns `true` is the model is attached.
*
* @return {boolean} Whether the model is attached or not.
*/
isAttached() {

return this.attached;

}

/**
* Perfoms an intersection test with the model's raycaster and the given object.
*
* @param {Object3D} object - The 3D object to check for intersection with the ray.
* @param {boolean} [recursive=true] - If set to `true`, it also checks all descendants.
* Otherwise it only checks intersection with the object.
* @return {Array<Raycaster~Intersection>} An array holding the intersection points.
*/
intersectObject( object, recursive = true ) {

if ( this.raycaster ) {
Expand All @@ -357,6 +457,14 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Perfoms an intersection test with the model's raycaster and the given objects.
*
* @param {Array<Object3D>} objects - The 3D objects to check for intersection with the ray.
* @param {boolean} [recursive=true] - If set to `true`, it also checks all descendants.
* Otherwise it only checks intersection with the object.
* @return {Array<Raycaster~Intersection>} An array holding the intersection points.
*/
intersectObjects( objects, recursive = true ) {

if ( this.raycaster ) {
Expand All @@ -367,6 +475,14 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Checks for intersections between the model's raycaster and the given objects. The method
* updates the cursor object to the intersection point.
*
* @param {Array<Object3D>} objects - The 3D objects to check for intersection with the ray.
* @param {boolean} [recursive=false] - If set to `true`, it also checks all descendants.
* Otherwise it only checks intersection with the object.
*/
checkIntersections( objects, recursive = false ) {

if ( this.raycaster && ! this.attached ) {
Expand All @@ -389,6 +505,11 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Sets the cursor to the given distance.
*
* @param {number} distance - The distance to set the cursor to.
*/
setCursor( distance ) {

const direction = new Vector3( 0, 0, - 1 );
Expand All @@ -400,6 +521,10 @@ class OculusHandPointerModel extends Object3D {

}

/**
* Frees the GPU-related resources allocated by this instance. Call this
* method whenever this instance is no longer used in your app.
*/
dispose() {

this._onDisconnected();
Expand Down
11 changes: 11 additions & 0 deletions examples/jsm/webxr/Text2D.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { DoubleSide, Mesh, MeshBasicMaterial, PlaneGeometry, Texture } from 'three';

/** @module Text2D */

/**
* A helper function for creating a simple plane mesh
* that can be used as a text label. The mesh's material
* holds a canvas texture that displays the given message.
*
* @param {string} message - The message to display.
* @param {number} height - The labels height.
* @return {Mesh} The plane mesh representing a text label.
*/
function createText( message, height ) {

const canvas = document.createElement( 'canvas' );
Expand Down
Loading
Loading