Browse Source

Merge pull request #1919 from RaananW/webvr-parenting-corrected

Webvr parenting
David Catuhe 8 years ago
parent
commit
ab342803a8

+ 56 - 29
src/Cameras/VR/babylon.webVRCamera.ts

@@ -52,6 +52,8 @@ module BABYLON {
 
         private _positionOffset: Vector3 = Vector3.Zero();
 
+        protected _descendants: Array<Node> = [];
+
         public devicePosition = Vector3.Zero();
         public deviceRotationQuaternion;
         public deviceScaleFactor: number = 1;
@@ -59,6 +61,8 @@ module BABYLON {
         public controllers: Array<WebVRController> = [];
         public onControllersAttached: (controllers: Array<WebVRController>) => void;
 
+        public rigParenting: boolean = true; // should the rig cameras be used as parent instead of this camera.
+
         constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
 
@@ -124,6 +128,39 @@ module BABYLON {
 
             // try to attach the controllers, if found.
             this.initControllers();
+
+            /**
+             * The idea behind the following lines:
+             * objects that have the camera as parent should actually have the rig cameras as a parent.
+             * BUT, each of those cameras has a different view matrix, which means that if we set the parent to the first rig camera,
+             * the second will not show it correctly.
+             * 
+             * To solve this - each object that has the camera as parent will be added to a protected array.
+             * When the rig camera renders, it will take this array and set all of those to be its children.
+             * This way, the right camera will be used as a parent, and the mesh will be rendered correctly.
+             * Amazing!
+             */
+            scene.onBeforeCameraRenderObservable.add((camera) => {
+                if (camera.parent === this && this.rigParenting) {
+                    this._descendants = this.getDescendants(true, (n) => {
+                        // don't take the cameras or the controllers!
+                        let isController = this.controllers.some(controller => { return controller._mesh === n });
+                        let isRigCamera = this._rigCameras.indexOf(<Camera>n) !== -1
+                        return !isController && !isRigCamera;
+                    });
+                    this._descendants.forEach(node => {
+                        node.parent = camera;
+                    });
+                }
+            });
+
+            scene.onAfterCameraRenderObservable.add((camera) => {
+                if (camera.parent === this && this.rigParenting) {
+                    this._descendants.forEach(node => {
+                        node.parent = this;
+                    });
+                }
+            });
         }
 
         public _checkInputs(): void {
@@ -193,6 +230,16 @@ module BABYLON {
             this._vrDevice.resetPose();
         }
 
+        public _updateRigCameras() {
+            var camLeft = <TargetCamera>this._rigCameras[0];
+            var camRight = <TargetCamera>this._rigCameras[1];
+            camLeft.rotationQuaternion.copyFrom(this.deviceRotationQuaternion);
+            camRight.rotationQuaternion.copyFrom(this.deviceRotationQuaternion);
+
+            camLeft.position.copyFrom(this.devicePosition);
+            camRight.position.copyFrom(this.devicePosition);
+        }
+
         /**
          * This function is called by the two RIG cameras.
          * 'this' is the left or right camera (and NOT (!!!) the WebVRFreeCamera instance)
@@ -200,17 +247,18 @@ module BABYLON {
         protected _getWebVRViewMatrix(): Matrix {
             var viewArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
 
+            Matrix.FromArrayToRef(viewArray, 0, this._webvrViewMatrix);
+
             if (!this.getScene().useRightHandedSystem) {
-                [2, 6, 8, 9, 14].forEach(function (num) {
-                    viewArray[num] *= -1;
+                [2, 6, 8, 9, 14].forEach((num) => {
+                    this._webvrViewMatrix.m[num] *= -1;
                 });
             }
-            Matrix.FromArrayToRef(viewArray, 0, this._webvrViewMatrix);
 
             let parentCamera: WebVRFreeCamera = this._cameraRigParams["parentCamera"];
 
             // should the view matrix be updated with scale and position offset?
-            if (parentCamera.position.lengthSquared() || parentCamera.deviceScaleFactor !== 1) {
+            if (parentCamera.deviceScaleFactor !== 1) {
                 this._webvrViewMatrix.invert();
                 // scale the position, if set
                 if (parentCamera.deviceScaleFactor) {
@@ -218,40 +266,19 @@ module BABYLON {
                     this._webvrViewMatrix.m[13] *= parentCamera.deviceScaleFactor;
                     this._webvrViewMatrix.m[14] *= parentCamera.deviceScaleFactor;
                 }
-                // change the position (for "teleporting");
-                this._webvrViewMatrix.m[12] += parentCamera.position.x;
-                this._webvrViewMatrix.m[13] += parentCamera.position.y;
-                this._webvrViewMatrix.m[14] += parentCamera.position.z;
-
-                // is rotation offset set? 
-                if (!Quaternion.IsIdentity(this.rotationQuaternion)) {
-                    this._webvrViewMatrix.decompose(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1]);
-                    this.rotationQuaternion.multiplyToRef(Tmp.Quaternion[0], Tmp.Quaternion[0]);
-                    Matrix.ComposeToRef(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1], this._webvrViewMatrix);
-                }
 
                 this._webvrViewMatrix.invert();
             }
 
-            this._updateCameraRotationMatrix();
+            // update the camera rotation matrix
+            this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
             Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
 
-            // Computing target for getTarget()
-            this._positionOffset = this._positionOffset || Vector3.Zero();
-            this._webvrViewMatrix.getTranslationToRef(this._positionOffset);
-            this._positionOffset.addToRef(this._transformedReferencePoint, this._currentTarget);
-
+            // Computing target and final matrix
+            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
             return this._webvrViewMatrix;
         }
 
-        public _updateWebVRCameraRotationMatrix() {
-            this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
-        }
-
-        public _isSynchronizedViewMatrix() {
-            return false;
-        }
-
         protected _getWebVRProjectionMatrix(): Matrix {
             var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
             //babylon compatible matrix

+ 3 - 4
src/Cameras/babylon.camera.ts

@@ -618,20 +618,19 @@
                         this._rigCameras[0].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        this._rigCameras[0].parent = this;
                         this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
-                        this._rigCameras[0]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
-                        this._rigCameras[0]._updateCameraRotationMatrix = this._updateWebVRCameraRotationMatrix;
 
                         //Right eye
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
+                        this._rigCameras[0].setCameraRigParameter("left", false);
                         this._rigCameras[1].setCameraRigParameter('eyeParameters', rightEye);
                         this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[1].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        this._rigCameras[1].parent = this;
                         this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
-                        this._rigCameras[1]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
-                        this._rigCameras[1]._updateCameraRotationMatrix = this._updateWebVRCameraRotationMatrix;
                     }
                     break;
 

+ 1 - 2
src/Cameras/babylon.targetCamera.ts

@@ -179,7 +179,7 @@ module BABYLON {
 
                 //rotate, if quaternion is set and rotation was used
                 if (this.rotationQuaternion) {
-                    var len = this.rotation.length();
+                    var len = this.rotation.lengthSquared();
                     if (len) {
                         Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this.rotationQuaternion);
                     }
@@ -302,7 +302,6 @@ module BABYLON {
                     break;
 
                 case Camera.RIG_MODE_VR:
-                case Camera.RIG_MODE_WEBVR:
                     if (camLeft.rotationQuaternion) {
                         camLeft.rotationQuaternion.copyFrom(this.rotationQuaternion);
                         camRight.rotationQuaternion.copyFrom(this.rotationQuaternion);