Procházet zdrojové kódy

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

David Catuhe před 5 roky
rodič
revize
d5e8189709

+ 1 - 1
dist/preview release/what's new.md

@@ -208,7 +208,7 @@
 - Selection has gaze mode (which can be forced) and touch-screen support ([#7395](https://github.com/BabylonJS/Babylon.js/issues/7395)) ([RaananW](https://github.com/RaananW/))
 - Laser pointers can be excluded from lighting influence so that they are always visible in both WebXR and WebVR ([#7323](https://github.com/BabylonJS/Babylon.js/issues/7323)) ([RaananW](https://github.com/RaananW/))
 - Full support for the online motion controller repository ([#7323](https://github.com/BabylonJS/Babylon.js/issues/7323)) ([RaananW](https://github.com/RaananW/))
-- New feature - XR Controller physics impostor for motion controllers ([RaananW](https://github.com/RaananW/))
+- New XR feature - XR Controller physics impostor for motion controllers ([RaananW](https://github.com/RaananW/))
 - Teleportation between different ground levels in WebXR is enabled ([RaananW](https://github.com/RaananW/))
 - Utility Meshes for XR (teleportation ring, selection rays) can now be rendered using a utility layer ([#7563](https://github.com/BabylonJS/Babylon.js/issues/7563)) ([RaananW](https://github.com/RaananW/))
 

+ 84 - 7
src/XR/features/WebXRControllerPhysics.ts

@@ -8,6 +8,7 @@ import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { SphereBuilder } from "../../Meshes/Builders/sphereBuilder";
 import { WebXRFeatureName, WebXRFeaturesManager } from "../webXRFeaturesManager";
 import { Logger } from '../../Misc/logger';
+import { Nullable } from '../../types';
 
 /**
  * Options for the controller physics feature
@@ -43,6 +44,33 @@ export class IWebXRControllerPhysicsOptions {
          */
         restitution?: number;
     };
+
+    /**
+     * Should the headset get its own impostor
+     */
+    enableHeadsetImpostor?: boolean;
+
+    /**
+     * Optional parameters for the headset impostor
+     */
+    headsetImpostorParams?: {
+        /**
+         * The type of impostor to create. Default is sphere
+         */
+        impostorType: number;
+        /**
+         * the size of the impostor. Defaults to 10cm
+         */
+        impostorSize?: number | { width: number, height: number, depth: number };
+        /**
+         * Friction definitions
+         */
+        friction?: number;
+        /**
+         * Restitution
+         */
+        restitution?: number;
+    };
 }
 
 /**
@@ -71,10 +99,14 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             impostorMesh?: AbstractMesh,
             impostor: PhysicsImpostor
             oldPos?: Vector3;
+            oldSpeed?: Vector3,
             oldRotation?: Quaternion;
         }
     } = {};
 
+    private _headsetImpostor?: PhysicsImpostor;
+    private _headsetMesh?: AbstractMesh;
+
     private _tmpVector: Vector3 = new Vector3();
     private _tmpQuaternion: Quaternion = new Quaternion();
 
@@ -108,6 +140,27 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
     }
 
     /**
+     * Get the physics impostor of a specific controller.
+     * The impostor is not attached to a mesh because a mesh for each controller is not obligatory
+     * @param controller the controller or the controller id of which to get the impostor
+     */
+    public getImpostorForController(controller: WebXRInputSource | string): Nullable<PhysicsImpostor> {
+        let id = typeof controller === "string" ? controller : controller.uniqueId;
+        if (this._controllers[id]) {
+            return this._controllers[id].impostor;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the headset impostor, if enabled
+     */
+    public getHeadsetImpostor() {
+        return this._headsetImpostor;
+    }
+
+    /**
      * attach this feature
      * Will usually be called by the features manager
      *
@@ -129,6 +182,23 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             this._detachController(controller.uniqueId);
         });
 
+        if (this._options.enableHeadsetImpostor) {
+            const params = this._options.headsetImpostorParams || {
+                impostorType: PhysicsImpostor.SphereImpostor,
+                restitution: 0.8,
+                impostorSize: 0.3
+            };
+            const impostorSize = params.impostorSize || 0.3;
+            this._headsetMesh = SphereBuilder.CreateSphere('headset-mesh', {
+                diameterX: typeof impostorSize === 'number' ? impostorSize : impostorSize.width,
+                diameterY: typeof impostorSize === 'number' ? impostorSize : impostorSize.height,
+                diameterZ: typeof impostorSize === 'number' ? impostorSize : impostorSize.depth
+            });
+            this._headsetMesh.rotationQuaternion = new Quaternion();
+            this._headsetMesh.isVisible = false;
+            this._headsetImpostor = new PhysicsImpostor(this._headsetMesh, params.impostorType, { mass: 0, ...params });
+        }
+
         return true;
     }
 
@@ -147,6 +217,10 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             this._detachController(controllerId);
         });
 
+        if (this._headsetMesh) {
+            this._headsetMesh.dispose();
+        }
+
         return true;
     }
 
@@ -238,6 +312,10 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
     protected _onXRFrame(_xrFrame: any): void {
         this._delta = (this._xrSessionManager.currentTimestamp - this._lastTimestamp);
         this._lastTimestamp = this._xrSessionManager.currentTimestamp;
+        if (this._headsetMesh) {
+            this._headsetMesh.position.copyFrom(this._options.xrInput.xrCamera.position);
+            this._headsetMesh.rotationQuaternion!.copyFrom(this._options.xrInput.xrCamera.rotationQuaternion!);
+        }
         Object.keys(this._controllers).forEach((controllerId) => {
             const controllerData = this._controllers[controllerId];
             const controllerMesh = controllerData.xrController.grip || controllerData.xrController.pointer;
@@ -245,14 +323,13 @@ export class WebXRControllerPhysics extends WebXRAbstractFeature {
             const comparedPosition = controllerData.oldPos || controllerData.impostorMesh!.position;
             const comparedQuaternion = controllerData.oldRotation || controllerData.impostorMesh!.rotationQuaternion!;
 
-            if (!controllerMesh.position.equalsWithEpsilon(comparedPosition)) {
-                controllerMesh.position.subtractToRef(comparedPosition, this._tmpVector);
-                this._tmpVector.scaleInPlace(this._delta);
-                controllerData.impostor.setLinearVelocity(this._tmpVector);
-                if (this._debugMode) {
-                    console.log(this._tmpVector, 'linear');
-                }
+            controllerMesh.position.subtractToRef(comparedPosition, this._tmpVector);
+            this._tmpVector.scaleInPlace(this._delta);
+            controllerData.impostor.setLinearVelocity(this._tmpVector);
+            if (this._debugMode) {
+                console.log(this._tmpVector, 'linear');
             }
+
             if (!comparedQuaternion.equalsWithEpsilon(controllerMesh.rotationQuaternion!)) {
                 // roughly based on this - https://www.gamedev.net/forums/topic/347752-quaternion-and-angular-velocity/
                 comparedQuaternion.conjugateInPlace().multiplyToRef(controllerMesh.rotationQuaternion!, this._tmpQuaternion);