Kaynağa Gözat

Merge pull request #4909 from atulyar/vr-obserables-fix

Vr obserables fix
sebavan 7 yıl önce
ebeveyn
işleme
e439ea12c3

+ 13 - 0
Viewer/src/managers/observablesManager.ts

@@ -54,6 +54,15 @@ export class ObservablesManager {
      */
     public onFrameRenderedObservable: Observable<any>;
 
+    /**
+     * Will notify when VR mode is entered.
+     */
+    public onEnteringVRObservable: Observable<any>;
+    /**
+     * Will notify when VR mode is exited.
+     */
+    public onExitingVRObservable: Observable<any>;
+
     constructor() {
         this.onSceneInitObservable = new Observable();
         this.onEngineInitObservable = new Observable();
@@ -66,6 +75,8 @@ export class ObservablesManager {
         this.onViewerInitStartedObservable = new Observable();
         this.onLoaderInitObservable = new Observable();
         this.onFrameRenderedObservable = new Observable();
+        this.onEnteringVRObservable = new Observable();
+        this.onExitingVRObservable = new Observable();
     }
 
     dispose() {
@@ -79,6 +90,8 @@ export class ObservablesManager {
         this.onViewerInitDoneObservable.clear();
         this.onLoaderInitObservable.clear();
         this.onFrameRenderedObservable.clear();
+        this.onEnteringVRObservable.clear();
+        this.onExitingVRObservable.clear();
     }
 
 }

+ 10 - 0
Viewer/src/managers/sceneManager.ts

@@ -798,6 +798,16 @@ export class SceneManager {
                 });
             });
         }
+        this._vrHelper.onEnteringVRObservable.add(() => {
+            if (this._observablesManager) {
+                this._observablesManager.onEnteringVRObservable.notifyObservers(this);
+            }
+        });
+        this._vrHelper.onExitingVRObservable.add(() => {
+            if (this._observablesManager) {
+                this._observablesManager.onExitingVRObservable.notifyObservers(this);
+            }
+        });
         this.onVRConfiguredObservable.notifyObservers({
             sceneManager: this,
             object: this._vrHelper,

+ 41 - 22
Viewer/src/viewer/viewer.ts

@@ -1,4 +1,4 @@
-import { Database, Effect, Engine, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Observable, RenderingManager, Scene, SceneLoaderProgressEvent, TargetCamera, Tools, Vector3 } from 'babylonjs';
+import { Database, Effect, Engine, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Observable, RenderingManager, Scene, SceneLoaderProgressEvent, TargetCamera, Tools, Vector3, Observer } from 'babylonjs';
 import { IModelConfiguration, IObserversConfiguration, ViewerConfiguration } from '../configuration/';
 import { processConfigurationCompatibility } from '../configuration/configurationCompatibility';
 import { ConfigurationContainer } from '../configuration/configurationContainer';
@@ -121,6 +121,19 @@ export abstract class AbstractViewer {
         return this.observablesManager.onFrameRenderedObservable;
     }
 
+    /**
+     * Observers registered here will be executed when VR more is entered.
+     */
+    public get onEnteringVRObservable(): Observable<AbstractViewer> {
+        return this.observablesManager.onEnteringVRObservable;
+    }
+    /**
+     * Observers registered here will be executed when VR mode is exited.
+     */
+    public get onExitingVRObservable(): Observable<AbstractViewer> {
+        return this.observablesManager.onExitingVRObservable;
+    }
+
     public observablesManager: ObservablesManager;
 
     /**
@@ -270,11 +283,13 @@ export abstract class AbstractViewer {
         }
 
         if (this.sceneManager.vrHelper && !this.sceneManager.vrHelper.isInVRMode) {
+
             // make sure the floor is set
             if (this.sceneManager.environmentHelper && this.sceneManager.environmentHelper.ground) {
                 this.sceneManager.vrHelper.addFloorMesh(this.sceneManager.environmentHelper.ground);
             }
 
+            this._vrToggled = true;
             this.sceneManager.vrHelper.enterVR();
 
             // position the vr camera to be in front of the object or wherever the user has configured it to be
@@ -337,29 +352,33 @@ export abstract class AbstractViewer {
     protected _initVR() {
 
         if (this.sceneManager.vrHelper) {
-            this.sceneManager.vrHelper.onExitingVR.add(() => {
-                // undo the scaling of the model
-                if (this.sceneManager.models.length) {
-                    this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(1 / this._vrScale);
-                    this.sceneManager.models[0].rootMesh.position.y -= this._vrModelRepositioning;
-                }
+            this.observablesManager.onExitingVRObservable.add(() => {
+                if (this._vrToggled) {
+                    this._vrToggled = false;
+                    
+                    // undo the scaling of the model
+                    if (this.sceneManager.models.length) {
+                        this.sceneManager.models[0].rootMesh.scaling.scaleInPlace(1 / this._vrScale);
+                        this.sceneManager.models[0].rootMesh.position.y -= this._vrModelRepositioning;
+                    }
 
-                // undo the scaling of the environment
-                if (this.sceneManager.environmentHelper) {
-                    this.sceneManager.environmentHelper.ground && this.sceneManager.environmentHelper.ground.scaling.scaleInPlace(1 / this._vrScale);
-                    this.sceneManager.environmentHelper.skybox && this.sceneManager.environmentHelper.skybox.scaling.scaleInPlace(1 / this._vrScale);
-                }
+                    // undo the scaling of the environment
+                    if (this.sceneManager.environmentHelper) {
+                        this.sceneManager.environmentHelper.ground && this.sceneManager.environmentHelper.ground.scaling.scaleInPlace(1 / this._vrScale);
+                        this.sceneManager.environmentHelper.skybox && this.sceneManager.environmentHelper.skybox.scaling.scaleInPlace(1 / this._vrScale);
+                    }
 
-                // post processing
-                if (this.sceneManager.defaultRenderingPipelineEnabled && this.sceneManager.defaultRenderingPipeline) {
-                    this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = true;
-                    this.sceneManager.defaultRenderingPipeline.prepare();
-                }
+                    // post processing
+                    if (this.sceneManager.defaultRenderingPipelineEnabled && this.sceneManager.defaultRenderingPipeline) {
+                        this.sceneManager.defaultRenderingPipeline.imageProcessingEnabled = true;
+                        this.sceneManager.defaultRenderingPipeline.prepare();
+                    }
 
-                // clear set height and eidth
-                this.canvas.removeAttribute("height");
-                this.canvas.removeAttribute("width");
-                this.engine.resize();
+                    // clear set height and eidth
+                    this.canvas.removeAttribute("height");
+                    this.canvas.removeAttribute("width");
+                    this.engine.resize();
+                }
             })
         }
 
@@ -531,7 +550,7 @@ export abstract class AbstractViewer {
     }
 
     /**
-     * Dispoe the entire viewer including the scene and the engine
+     * Dispose the entire viewer including the scene and the engine
      */
     public dispose() {
         if (this._isDisposed) {

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

@@ -152,9 +152,11 @@
 - Fixed issue where gaze trackers were appearing even after leaving VR ([atulyar](https://github.com/atulyar))
 - AdvancedDynamicTexture should not overwrite skipOnPointerObservable to false ([TrevorDev](https://github.com/TrevorDev))
 - Fixed issue where VRExperienceHelper.onExitingVR observable was being fired twice ([atulyar](https://github.com/atulyar))
+- Avoid firing onExitingVR observable multiple times when calling exitVR() and add observables to Viewer that can be used instead of the ones in VRExperienceHelper ([atulyar](https://github.com/atulyar))
 - GizmoManager should hide existing gizmos if a non-attachable mesh is selected ([TrevorDev](https://github.com/TrevorDev))
 - Ignore isPickable = false for vr ray casting if the mesh's name matches the specified floorMeshName to maintain backwards compatability ([TrevorDev](https://github.com/TrevorDev))
 - Fix File Loading if hosted from `file:`-Protocol ([ltetzlaff](https://github.com/ltetzlaff))
+- Exiting VR can result in messed up view ([TrevorDev](https://github.com/TrevorDev))
 
 ### Core Engine
 

+ 48 - 40
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -254,8 +254,10 @@ module BABYLON {
         private _webVRready = false;
         // Are we waiting for the requestPresent callback to complete?
         private _webVRrequesting = false;
-        // Are we presenting to the headset right now?
+        // Are we presenting to the headset right now? (this is the vrDevice state)
         private _webVRpresenting = false;
+        // Have we entered VR? (this is the VRExperienceHelper state)
+        private _hasEnteredVR: boolean;
 
         // Are we presenting in the fullscreen fallback?
         private _fullscreenVRpresenting = false;
@@ -566,6 +568,8 @@ module BABYLON {
                 this._defaultHeight *= webVROptions.positionScale;
             }
 
+            this._hasEnteredVR = false;
+
             // Set position
             if (this._scene.activeCamera) {
                 this._position = this._scene.activeCamera.position.clone();
@@ -773,11 +777,9 @@ module BABYLON {
             var vrDisplay = this._scene.getEngine().getVRDevice();
             if (vrDisplay) {
                 var wasPresenting = this._webVRpresenting;
-
-                // A VR display is connected
                 this._webVRpresenting = vrDisplay.isPresenting;
-
-                if (wasPresenting && !this._webVRpresenting && this.isInVRMode)
+                
+                if (wasPresenting && !this._webVRpresenting)
                     this.exitVR();
             } else {
                 Tools.Warn('Detected VRDisplayPresentChange on an unknown VRDisplay. Did you can enterVR on the vrExperienceHelper?');
@@ -869,54 +871,60 @@ module BABYLON {
             if (this._interactionsEnabled) {
                 this._scene.registerBeforeRender(this.beforeRender);
             }
+
+            this._hasEnteredVR = true;
         }
 
         /**
          * Attempt to exit VR, or fullscreen.
          */
         public exitVR() {
-            if (this.onExitingVRObservable) {
-                try {
-                    this.onExitingVRObservable.notifyObservers(this);
+            if (this._hasEnteredVR) {
+                if (this.onExitingVRObservable) {
+                    try {
+                        this.onExitingVRObservable.notifyObservers(this);
+                    }
+                    catch (err) {
+                        Tools.Warn("Error in your custom logic onExitingVR: " + err);
+                    }
                 }
-                catch (err) {
-                    Tools.Warn("Error in your custom logic onExitingVR: " + err);
+                if (this._webVRpresenting) {
+                    this._scene.getEngine().disableVR();
                 }
-            }
-            if (this._webVRpresenting) {
-                this._scene.getEngine().disableVR();
-            }
-            if (this._scene.activeCamera) {
-                this._position = this._scene.activeCamera.position.clone();
-
-            }
+                if (this._scene.activeCamera) {
+                    this._position = this._scene.activeCamera.position.clone();
 
-            if (this._deviceOrientationCamera) {
-                this._deviceOrientationCamera.position = this._position;
-                this._scene.activeCamera = this._deviceOrientationCamera;
-                if (this._canvas) {
-                    this._scene.activeCamera.attachControl(this._canvas);
                 }
-            } else if (this._existingCamera) {
-                this._existingCamera.position = this._position;
-                this._scene.activeCamera = this._existingCamera;
-            }
-
-            this.updateButtonVisibility();
-
-            if (this._interactionsEnabled) {
-                this._scene.unregisterBeforeRender(this.beforeRender);
-                this._cameraGazer._gazeTracker.isVisible = false;
-                if (this._leftController) {
-                    this._leftController._gazeTracker.isVisible = false;
+    
+                if (this._deviceOrientationCamera) {
+                    this._deviceOrientationCamera.position = this._position;
+                    this._scene.activeCamera = this._deviceOrientationCamera;
+                    if (this._canvas) {
+                        this._scene.activeCamera.attachControl(this._canvas);
+                    }
+                } else if (this._existingCamera) {
+                    this._existingCamera.position = this._position;
+                    this._scene.activeCamera = this._existingCamera;
                 }
-                if (this._rightController) {
-                    this._rightController._gazeTracker.isVisible = false;
+    
+                this.updateButtonVisibility();
+    
+                if (this._interactionsEnabled) {
+                    this._scene.unregisterBeforeRender(this.beforeRender);
+                    this._cameraGazer._gazeTracker.isVisible = false;
+                    if (this._leftController) {
+                        this._leftController._gazeTracker.isVisible = false;
+                    }
+                    if (this._rightController) {
+                        this._rightController._gazeTracker.isVisible = false;
+                    }
                 }
-            }
+    
+                // resize to update width and height when exiting vr exits fullscreen
+                this._scene.getEngine().resize();
 
-            // resize to update width and height when exiting vr exits fullscreen
-            this._scene.getEngine().resize();
+                this._hasEnteredVR = false;
+            }
         }
 
         /**

+ 12 - 0
src/Cameras/VR/babylon.webVRCamera.ts

@@ -346,6 +346,7 @@ module BABYLON {
          * Disposes the camera
          */
         public dispose(): void {
+            this._detachIfAttached();
             this.getEngine().onVRRequestPresentComplete.removeCallback(this._onVREnabled);
             super.dispose();
         }
@@ -442,6 +443,14 @@ module BABYLON {
             }
         }
 
+        private _htmlElementAttached:Nullable<HTMLElement> = null;
+        private _detachIfAttached = ()=>{
+            var vrDisplay = this.getEngine().getVRDevice();
+            if (vrDisplay && !vrDisplay.isPresenting && this._htmlElementAttached) {
+                this.detachControl(this._htmlElementAttached);
+            }
+        }
+
         /**
          * WebVR's attach control will start broadcasting frames to the device.
          * Note that in certain browsers (chrome for example) this function must be called
@@ -454,12 +463,14 @@ module BABYLON {
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
             super.attachControl(element, noPreventDefault);
             this._attached = true;
+            this._htmlElementAttached = element;
 
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
 
             if (this._vrDevice) {
                 this.getEngine().enableVR();
             }
+            window.addEventListener('vrdisplaypresentchange', this._detachIfAttached);
         }
 
         /**
@@ -474,6 +485,7 @@ module BABYLON {
             super.detachControl(element);
             this._attached = false;
             this.getEngine().disableVR();
+            window.removeEventListener('vrdisplaypresentchange', this._detachIfAttached);
         }
 
         /**