Преглед изворни кода

Merge pull request #558 from vousk/patch-stereoCameras

Refactoring stereoscopic cameras system
David Catuhe пре 10 година
родитељ
комит
5ceb530b69

+ 11 - 11
Babylon/Cameras/VR/babylon.vrDeviceOrientationCamera.ts

@@ -1,9 +1,9 @@
 module BABYLON {
     export class VRDeviceOrientationFreeCamera extends FreeCamera {
-		public _alpha = 0;
-		public _beta = 0;
-		public _gamma = 0;
-	
+        public _alpha = 0;
+        public _beta = 0;
+        public _gamma = 0;
+    
         private _offsetOrientation: { yaw: number; pitch: number; roll: number };
         private _deviceOrientationHandler;
 
@@ -12,7 +12,7 @@ module BABYLON {
 
             var metrics = VRCameraMetrics.GetDefault();
             metrics.compensateDistorsion = compensateDistorsion;
-            this.setSubCameraMode(Camera.SUB_CAMERA_MODE_VR, 0, metrics);
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
 
             this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
         }
@@ -23,16 +23,16 @@ module BABYLON {
             this._gamma = +evt.gamma|0;
 
             if (this._gamma < 0) {
-            	this._gamma = 90 + this._gamma;
+                this._gamma = 90 + this._gamma;
             }
             else {
-				// Incline it in the correct angle.
-            	this._gamma = 270 - this._gamma;
+                // Incline it in the correct angle.
+                this._gamma = 270 - this._gamma;
             }
 
             this.rotation.x = this._gamma / 180.0 * Math.PI;   
-			this.rotation.y = -this._alpha / 180.0 * Math.PI;	
-			this.rotation.z	= this._beta / 180.0 * Math.PI;		
+            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
+            this.rotation.z = this._beta / 180.0 * Math.PI;     
         }
 
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
@@ -46,5 +46,5 @@ module BABYLON {
 
             window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
         }
-	}
+    }
 }

+ 1 - 1
Babylon/Cameras/VR/babylon.webVRCamera.ts

@@ -15,7 +15,7 @@ module BABYLON {
             
             var metrics = VRCameraMetrics.GetDefault();
             metrics.compensateDistorsion = compensateDistorsion;
-            this.setSubCameraMode(Camera.SUB_CAMERA_MODE_VR, 0, metrics);
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
 
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
         }

+ 0 - 22
Babylon/Cameras/babylon.anaglyphCamera.ts

@@ -1,22 +0,0 @@
-module BABYLON {
-    export class AnaglyphFreeCamera extends FreeCamera {
-        constructor(name: string, position: Vector3, eyeSpace: number, scene: Scene) {
-            super(name, position, scene);
-            this.setSubCameraMode(Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-    }
-
-    export class AnaglyphArcRotateCamera extends ArcRotateCamera {
-        constructor(name: string, alpha: number, beta: number, radius: number, target, eyeSpace: number, scene: Scene) {
-            super(name, alpha, beta, radius, target, scene);
-            this.setSubCameraMode(Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-    }
-
-    export class AnaglyphGamepadCamera extends GamepadCamera {
-        constructor(name: string, position: Vector3, eyeSpace: number, scene: Scene) {
-            super(name, position, scene);
-            this.setSubCameraMode(Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-    }
-} 

+ 28 - 15
Babylon/Cameras/babylon.arcRotateCamera.ts

@@ -533,27 +533,40 @@
         
         /**
          * @override
-         * needs to be overridden, so sub has required properties to be copied
+         * Override Camera.createRigCamera
          */
-        public getSubCamera(name: string, isA: boolean): Camera {
-            var alphaSpace = this._subCamHalfSpace * (isA ? -1 : 1);
-            return new ArcRotateCamera(name, this.alpha + alphaSpace, this.beta, this.radius, this.target, this.getScene());
+        public createRigCamera(name: string, cameraIndex: number): Camera {
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
+                    return new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this.target, this.getScene());
+            }
         }
         
         /**
          * @override
-         * needs to be overridden, adding copy of alpha, beta & radius
+         * Override Camera._updateRigCameras
          */
-        public _updateSubCameras() {
-            var camA = <ArcRotateCamera> this.subCameras[Camera.SUB_CAMERAID_A];
-            var camB = <ArcRotateCamera> this.subCameras[Camera.SUB_CAMERAID_B];
-
-            camA.alpha = this.alpha - this._subCamHalfSpace;
-            camB.alpha = this.alpha + this._subCamHalfSpace;
-
-            camA.beta = camB.beta = this.beta;
-            camA.radius = camB.radius = this.radius;
-            super._updateSubCameras();
+        public _updateRigCameras() {
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var camLeft = <ArcRotateCamera> this._rigCameras[0];
+                    var camRight = <ArcRotateCamera> this._rigCameras[1];
+                    camLeft.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
+                    camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
+                    camLeft.beta = camRight.beta = this.beta;
+                    camLeft.radius = camRight.radius = this.radius;
+                    break;
+            }
+            super._updateRigCameras();
         }
     }
 } 

+ 119 - 101
Babylon/Cameras/babylon.camera.ts

@@ -73,14 +73,14 @@
         private static _FOVMODE_VERTICAL_FIXED = 0;
         private static _FOVMODE_HORIZONTAL_FIXED = 1;
 
-        private static _SUB_CAMERA_MODE_NONE = 0;
-        private static _SUB_CAMERA_MODE_ANAGLYPH = 1;
-        private static _SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC = 2;
-        private static _SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC = 3;
-        private static _SUB_CAMERA_MODE_VR = 4;
-
-        private static _SUB_CAMERAID_A = 0;
-        private static _SUB_CAMERAID_B = 1;
+        private static _RIG_MODE_NONE = 0;        
+        private static _RIG_MODE_STEREOSCOPIC_ANAGLYPH = 10;
+        private static _RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL = 11;
+        private static _RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED = 12;
+        private static _RIG_MODE_STEREOSCOPIC_OVERUNDER = 13;
+        private static _STEREOSCOPY_CONVERGENCE_MODE = 0;
+        private static _STEREOSCOPY_PARALLEL_MODE = 1;
+        private static _RIG_MODE_VR = 20;
 
         public static get PERSPECTIVE_CAMERA(): number {
             return Camera._PERSPECTIVE_CAMERA;
@@ -98,32 +98,36 @@
             return Camera._FOVMODE_HORIZONTAL_FIXED;
         }
 
-        public static get SUB_CAMERA_MODE_NONE(): number {
-            return Camera._SUB_CAMERA_MODE_NONE;
+        public static get RIG_MODE_NONE(): number {
+            return Camera._RIG_MODE_NONE;
         }
 
-        public static get SUB_CAMERA_MODE_ANAGLYPH(): number {
-            return Camera._SUB_CAMERA_MODE_ANAGLYPH;
+        public static get RIG_MODE_STEREOSCOPIC_ANAGLYPH(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_ANAGLYPH;
         }
 
-        public static get SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC(): number {
-            return Camera._SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC;
+        public static get RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL;
         }
-
-        public static get SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC(): number {
-            return Camera._SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC;
+        
+        public static get RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
         }
 
-        public static get SUB_CAMERA_MODE_VR(): number {
-            return Camera._SUB_CAMERA_MODE_VR;
+        public static get RIG_MODE_STEREOSCOPIC_OVERUNDER(): number {
+            return Camera._RIG_MODE_STEREOSCOPIC_OVERUNDER;
         }
-
-        public static get SUB_CAMERAID_A(): number {
-            return Camera._SUB_CAMERAID_A;
+        
+        public static get STEREOSCOPY_CONVERGENCE_MODE(): number {
+            return Camera._STEREOSCOPY_CONVERGENCE_MODE;
+        }
+        
+        public static get STEREOSCOPY_PARALLEL_MODE(): number {
+            return Camera._STEREOSCOPY_PARALLEL_MODE;
         }
 
-        public static get SUB_CAMERAID_B(): number {
-            return Camera._SUB_CAMERAID_B;
+        public static get RIG_MODE_VR(): number {
+            return Camera._RIG_MODE_VR;
         }
         
         // Members
@@ -142,17 +146,10 @@
         public layerMask: number = 0x0FFFFFFF;
         public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
    
-        // Subcamera members
-        public subCameras = new Array<Camera>();
-        public _subCameraMode = Camera.SUB_CAMERA_MODE_NONE;
-        public _subCamHalfSpace: number;
-
-        // VR related
-        private _vrMetrics: VRCameraMetrics;
-        private _vrHMatrix: Matrix;
-        public _vrPreViewMatrix: Matrix;
-        public _vrWorkMatrix: Matrix;
-        public _vrActualUp: Vector3;
+        // Camera rig members
+        public cameraRigMode = Camera.RIG_MODE_NONE;
+        public _cameraRigParams: any;
+        public _rigCameras = new Array<Camera>();
 
         // Cache
         private _computedViewMatrix = Matrix.Identity();
@@ -289,8 +286,8 @@
 
         public _update(): void {
             this._checkInputs();
-            if (this._subCameraMode !== Camera.SUB_CAMERA_MODE_NONE) {
-                this._updateSubCameras();
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
+                this._updateRigCameras();
             }
         }
 
@@ -467,9 +464,9 @@
         public dispose(): void {
             // Remove from scene
             this.getScene().removeCamera(this);
-            while (this.subCameras.length > 0) {
-                this.subCameras.pop().dispose();
-            }                    
+            while (this._rigCameras.length > 0) {
+                this._rigCameras.pop().dispose();
+            }
 
             // Postprocesses
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
@@ -477,102 +474,123 @@
             }
         }
         
-        // ---- 3D cameras section ----
-        public setSubCameraMode(mode: number, halfSpace = 0, metrics?: VRCameraMetrics): void {
-            while (this.subCameras.length > 0) {
-                this.subCameras.pop().dispose();
+        // ---- Camera rigs section ----
+        public setCameraRigMode(mode: number, rigParams: any): void {
+            while (this._rigCameras.length > 0) {
+                this._rigCameras.pop().dispose();
+            }
+            this.cameraRigMode = mode;
+            this._cameraRigParams = {};
+        
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    this._cameraRigParams.stereoMode = Camera.STEREOSCOPY_CONVERGENCE_MODE; //by default, for now
+                    
+                    this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
+                    //we have to implement stereo camera calcultating left and right viewpoints from interaxialDistance and target, 
+                    //not from a given angle as it is now, but until that complete code rewriting provisional stereoHalfAngle value is introduced
+                    this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
+                    
+                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                break;
             }
-            this._subCameraMode = mode;
-            this._subCamHalfSpace = Tools.ToRadians(halfSpace);
-
-            var camA = this.getSubCamera(this.name + "_A", true);
-            var camB = this.getSubCamera(this.name + "_B", false);
-            var postProcessA: PostProcess;
-            var postProcessB: PostProcess;
-
-            switch (this._subCameraMode) {
-                case Camera.SUB_CAMERA_MODE_ANAGLYPH:
-                    postProcessA = new PassPostProcess(this.name + "_leftTexture", 1.0, camA);
-                    camA.isIntermediate = true;
-
-                    postProcessB = new AnaglyphPostProcess(this.name + "_anaglyph", 1.0, camB);
-                    postProcessB.onApply = effect => {
-                        effect.setTextureFromPostProcess("leftSampler", postProcessA);
+            
+            var postProcesses = new Array<PostProcess>();
+            
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                    postProcesses.push(new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]));
+                    this._rigCameras[0].isIntermediate = true;
+
+                    postProcesses.push(new AnaglyphPostProcess(this.name + "_anaglyph", 1.0, this._rigCameras[1]));
+                    postProcesses[1].onApply = effect => {
+                        effect.setTextureFromPostProcess("leftSampler", postProcesses[0]);
                     };
                     break;
 
-                case Camera.SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC:
-                case Camera.SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC:
-                    var isStereoscopicHoriz = this._subCameraMode === Camera.SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC;
-                    postProcessA = new PassPostProcess("passthru", 1.0, camA);
-                    camA.isIntermediate = true;
-
-                    postProcessB = new StereoscopicInterlacePostProcess("st_interlace", camB, postProcessA, isStereoscopicHoriz);
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    var isStereoscopicHoriz = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED);
+                    var firstCamIndex = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED)? 1 : 0;
+                    var secondCamIndex = 1 - firstCamIndex;
+                    
+                    postProcesses.push(new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[firstCamIndex]));
+                    this._rigCameras[firstCamIndex].isIntermediate = true;
+
+                    postProcesses.push(new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras[secondCamIndex], postProcesses[0], isStereoscopicHoriz));
                     break;
 
-                case Camera.SUB_CAMERA_MODE_VR:
-                    metrics = metrics || VRCameraMetrics.GetDefault();
-                    camA._vrMetrics = metrics;
-                    camA.viewport = new Viewport(0, 0, 0.5, 1.0);
-                    camA._vrWorkMatrix = new Matrix();
+                case Camera.RIG_MODE_VR:
+                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                    
+                    var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
+                    this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
+                    this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
+                    this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
 
-                    camA._vrHMatrix = metrics.leftHMatrix;
-                    camA._vrPreViewMatrix = metrics.leftPreViewMatrix;
-                    camA.getProjectionMatrix = camA._getVRProjectionMatrix;
+                    this._rigCameras[0]._cameraRigParams.vrHMatrix = metrics.leftHMatrix;
+                    this._rigCameras[0]._cameraRigParams.vrPreViewMatrix = metrics.leftPreViewMatrix;
+                    this._rigCameras[0].getProjectionMatrix = this._rigCameras[0]._getVRProjectionMatrix;
 
                     if (metrics.compensateDistorsion) {
-                        postProcessA = new VRDistortionCorrectionPostProcess("Distortion Compensation Left", camA, false, metrics);
+                        postProcesses.push(new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics));
                     }
 
-                    camB._vrMetrics = camA._vrMetrics;
-                    camB.viewport = new Viewport(0.5, 0, 0.5, 1.0);
-                    camB._vrWorkMatrix = new Matrix();
-                    camB._vrHMatrix = metrics.rightHMatrix;
-                    camB._vrPreViewMatrix = metrics.rightPreViewMatrix;
+                    this._rigCameras[1]._cameraRigParams.vrMetrics = this._rigCameras[0]._cameraRigParams.vrMetrics;
+                    this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
+                    this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
+                    this._rigCameras[1]._cameraRigParams.vrHMatrix = metrics.rightHMatrix;
+                    this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
 
-                    camB.getProjectionMatrix = camB._getVRProjectionMatrix;
+                    this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
 
                     if (metrics.compensateDistorsion) {
-                        postProcessB = new VRDistortionCorrectionPostProcess("Distortion Compensation Right", camB, true, metrics);
+                        postProcesses.push(new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics));
                     }
+                    break;
             }
-            if (this._subCameraMode !== Camera.SUB_CAMERA_MODE_NONE) {
-                this.subCameras.push(camA);
-                this.subCameras.push(camB);
-            }
+            
             this._update();
         }
 
         private _getVRProjectionMatrix(): Matrix {
-            Matrix.PerspectiveFovLHToRef(this._vrMetrics.aspectRatioFov, this._vrMetrics.aspectRatio, this.minZ, this.maxZ, this._vrWorkMatrix);
-            this._vrWorkMatrix.multiplyToRef(this._vrHMatrix, this._projectionMatrix);
+            Matrix.PerspectiveFovLHToRef(this._cameraRigParams.vrMetrics.aspectRatioFov, this._cameraRigParams.vrMetrics.aspectRatio, this.minZ, this.maxZ, this._cameraRigParams.vrWorkMatrix);
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
             return this._projectionMatrix;
         }
 
-        public setSubCamHalfSpace(halfSpace: number) {
-            this._subCamHalfSpace = Tools.ToRadians(halfSpace);
+        public setCameraRigParameter(name: string, value: any) {
+            this._cameraRigParams[name] = value;
+            //provisionnally:
+            if (name === "interaxialDistance") { this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(value); }
         }
         
         /**
          * May needs to be overridden by children so sub has required properties to be copied
          */
-        public getSubCamera(name: string, isA: boolean): Camera {
+        public createRigCamera(name: string, cameraIndex: number): Camera {
             return null;
         }
         
         /**
          * May needs to be overridden by children
          */
-        public _updateSubCameras() {
-            var camA = this.subCameras[Camera.SUB_CAMERAID_A];
-            var camB = this.subCameras[Camera.SUB_CAMERAID_B];
-            camA.minZ = camB.minZ = this.minZ;
-            camA.maxZ = camB.maxZ = this.maxZ;
-            camA.fov = camB.fov = this.fov;
+        public _updateRigCameras() {
+            for (var i=0 ; i<this._rigCameras.length ; i++) {
+                this._rigCameras[i].minZ = this.minZ;
+                this._rigCameras[i].maxZ = this.maxZ;
+                this._rigCameras[i].fov = this.fov;
+            }
             
-            // only update viewport, when ANAGLYPH
-            if (this._subCameraMode === Camera.SUB_CAMERA_MODE_ANAGLYPH) {
-                camA.viewport = camB.viewport = this.viewport;
+            // only update viewport when ANAGLYPH
+            if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
+                this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
             }
         }
     }

+ 0 - 23
Babylon/Cameras/babylon.stereoscopicCamera.ts

@@ -1,23 +0,0 @@
-module BABYLON {
-    export class StereoscopicFreeCamera extends FreeCamera {
-        constructor(name: string, position: Vector3, eyeSpace: number, isVertical: boolean, scene: Scene) {
-            super(name, position, scene);
-
-            this.setSubCameraMode(isVertical ? Camera.SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC : Camera.SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC, eyeSpace);
-        }
-    }
-
-    export class StereoscopicArcRotateCamera extends ArcRotateCamera {
-        constructor(name: string, alpha: number, beta: number, radius: number, target, eyeSpace: number, isVertical: boolean, scene:Scene) {
-            super(name, alpha, beta, radius, target, scene);
-            this.setSubCameraMode(isVertical ? Camera.SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC : Camera.SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC, eyeSpace);
-        }
-    }
-
-    export class StereoscopicGamepadCamera extends GamepadCamera {
-        constructor(name: string, position: Vector3, eyeSpace: number, isVertical: boolean, scene: Scene) {
-            super(name, position, scene);
-            this.setSubCameraMode(isVertical ? Camera.SUB_CAMERA_MODE_OVERUNDER_STEREOSCOPIC : Camera.SUB_CAMERA_MODE_CROSSEDSIDEBYSIDE_STEREOSCOPIC, eyeSpace);
-        }
-    }
-} 

+ 44 - 0
Babylon/Cameras/babylon.stereoscopicCameras.ts

@@ -0,0 +1,44 @@
+module BABYLON {
+    export class AnaglyphFreeCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class AnaglyphArcRotateCamera extends ArcRotateCamera {
+        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, scene: Scene) {
+            super(name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class AnaglyphGamepadCamera extends GamepadCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+    
+    export class StereoscopicFreeCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
+            super(name, position, scene);
+
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class StereoscopicArcRotateCamera extends ArcRotateCamera {
+        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, isSideBySide: boolean, scene:Scene) {
+            super(name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class StereoscopicGamepadCamera extends GamepadCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+} 

+ 49 - 37
Babylon/Cameras/babylon.targetCamera.ts

@@ -14,7 +14,7 @@
         public _camMatrix = Matrix.Zero();
         public _cameraTransformMatrix = Matrix.Zero();
         public _cameraRotationMatrix = Matrix.Zero();
-        private _subCamTransformMatrix: Matrix;
+        private _rigCamTransformMatrix: Matrix;
 
         public _referencePoint = new Vector3(0, 0, 1);
         public _transformedReferencePoint = Vector3.Zero();
@@ -215,66 +215,78 @@
             Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
 
             Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._vrActualUp);
+            Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
 
             // Computing target and final matrix
             this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
 
-            Matrix.LookAtLHToRef(this.position, this._currentTarget, this._vrActualUp, this._vrWorkMatrix);
+            Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
 
-            this._vrWorkMatrix.multiplyToRef(this._vrPreViewMatrix, this._viewMatrix);
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
             return this._viewMatrix;
         }
         
         /**
          * @override
-         * needs to be overridden, so sub has required properties to be copied
+         * Override Camera.createRigCamera
          */
-        public getSubCamera(name : string, isA : boolean) : Camera{
-            var subCamera = new TargetCamera(name, this.position.clone(), this.getScene());
-            if (this._subCameraMode === Camera.SUB_CAMERA_MODE_VR){
-                subCamera._vrActualUp = new Vector3(0, 0, 0);
-                subCamera._getViewMatrix = subCamera._getVRViewMatrix;
+        public createRigCamera(name: string, cameraIndex: number): Camera {
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
+                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
+                if (this.cameraRigMode === Camera.RIG_MODE_VR) {
+                    rigCamera._cameraRigParams.vrActualUp = new Vector3(0, 0, 0);
+                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
+                }
+                return rigCamera;
             }
-            return subCamera;
+            return null;
         }
         
         /**
          * @override
-         * needs to be overridden, adding copy of position, and rotation for VR, or target for rest
+         * Override Camera._updateRigCameras
          */
-        public _updateSubCameras(){
-            var camA = <TargetCamera> this.subCameras[Camera.SUB_CAMERAID_A];
-            var camB = <TargetCamera> this.subCameras[Camera.SUB_CAMERAID_B];
-
-            if (this._subCameraMode === Camera.SUB_CAMERA_MODE_VR){
-                camA.rotation.x = camB.rotation.x = this.rotation.x;
-                camA.rotation.y = camB.rotation.y = this.rotation.y;
-                camA.rotation.z = camB.rotation.z = this.rotation.z;
-                
-                camA.position.copyFrom(this.position);
-                camB.position.copyFrom(this.position);
-                
-            }else{
-                camA.setTarget(this.getTarget());
-                camB.setTarget(this.getTarget());
-                
-                this._getSubCamPosition(-this._subCamHalfSpace, camA.position);
-                this._getSubCamPosition( this._subCamHalfSpace, camB.position);
+        public _updateRigCameras(){
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var camLeft = <TargetCamera> this._rigCameras[0];
+                    var camRight = <TargetCamera> this._rigCameras[1];
+
+                    if (this.cameraRigMode === Camera.RIG_MODE_VR) {
+                        camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
+                        camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
+                        camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
+                        
+                        camLeft.position.copyFrom(this.position);
+                        camRight.position.copyFrom(this.position);
+                        
+                    } else {
+                        camLeft.setTarget(this.getTarget());
+                        camRight.setTarget(this.getTarget());
+                        
+                        //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
+                        this._getRigCamPosition(-this._cameraRigParams.stereoHalfAngle, camLeft.position);
+                        this._getRigCamPosition( this._cameraRigParams.stereoHalfAngle, camRight.position);
+                    }
+                    break;
             }
-            super._updateSubCameras();
+            super._updateRigCameras();
         }
         
-        private _getSubCamPosition(halfSpace: number, result: Vector3) {
-            if (!this._subCamTransformMatrix){
-                this._subCamTransformMatrix = new Matrix();
+        private _getRigCamPosition(halfSpace: number, result: Vector3) {
+            if (!this._rigCamTransformMatrix){
+                this._rigCamTransformMatrix = new Matrix();
             }
             var target = this.getTarget();
-            Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(Matrix.RotationY(halfSpace), this._subCamTransformMatrix);
+            Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
 
-            this._subCamTransformMatrix = this._subCamTransformMatrix.multiply(Matrix.Translation(target.x, target.y, target.z));
+            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(Matrix.Translation(target.x, target.y, target.z));
 
-            Vector3.TransformCoordinatesToRef(this.position, this._subCamTransformMatrix, result);
+            Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
         }
     }
 } 

+ 4 - 4
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -399,15 +399,15 @@
             var beta = parsedCamera.beta;
             var radius = parsedCamera.radius;
             if (parsedCamera.type === "AnaglyphArcRotateCamera") {
-                var eye_space = parsedCamera.eye_space;
-                camera = new AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, eye_space, scene);
+                var interaxial_distance = parsedCamera.interaxial_distance;
+                camera = new AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, interaxial_distance, scene);
             } else {
                 camera = new ArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, scene);
             }
 
         } else if (parsedCamera.type === "AnaglyphFreeCamera") {
-            eye_space = parsedCamera.eye_space;
-            camera = new AnaglyphFreeCamera(parsedCamera.name, position, eye_space, scene);
+            interaxial_distance = parsedCamera.interaxial_distance;
+            camera = new AnaglyphFreeCamera(parsedCamera.name, position, interaxial_distance, scene);
 
         } else if (parsedCamera.type === "DeviceOrientationCamera") {
             camera = new DeviceOrientationCamera(parsedCamera.name, position, scene);

+ 2 - 2
Babylon/Tools/babylon.sceneSerializer.ts

@@ -122,8 +122,8 @@
             serializationObject.rotationOffset = followCam.rotationOffset;
         } else if (camera instanceof AnaglyphFreeCamera || camera instanceof AnaglyphArcRotateCamera) {
             //eye space is a private member and can only be access like this. Without changing the implementation this is the best way to get it.
-            if (camera['_eyeSpace'] !== undefined) {
-                serializationObject.eye_space = Tools.ToDegrees(camera['_eyeSpace']);
+            if (camera['_interaxialDistance'] !== undefined) {
+                serializationObject.interaxial_distance = Tools.ToDegrees(camera['_interaxialDistance']);
             }
         }
 

+ 4 - 4
Babylon/babylon.scene.ts

@@ -1482,14 +1482,14 @@
         }
 
         private _processSubCameras(camera: Camera): void {
-            if (camera.subCameras.length === 0) {
+            if (camera.cameraRigMode === Camera.RIG_MODE_NONE) {
                 this._renderForCamera(camera);
                 return;
             }
 
-            // Sub-cameras
-            for (var index = 0; index < camera.subCameras.length; index++) {
-                this._renderForCamera(camera.subCameras[index]);
+            // rig cameras
+            for (var index = 0; index < camera._rigCameras.length; index++) {
+                this._renderForCamera(camera._rigCameras[index]);
             }
 
             this.activeCamera = camera;

+ 1 - 2
Tools/Gulp/config.json

@@ -103,7 +103,6 @@
       "../../Babylon/Cameras/babylon.virtualJoysticksCamera.js",
       "../../Babylon/Materials/babylon.shaderMaterial.js",
       "../../Babylon/Mesh/babylon.mesh.vertexData.js",
-      "../../Babylon/Cameras/babylon.anaglyphCamera.js",
       "../../Babylon/PostProcess/babylon.anaglyphPostProcess.js",
       "../../Babylon/Tools/babylon.tags.js",
       "../../Babylon/Tools/babylon.andOrNotEvaluator.js",
@@ -141,7 +140,7 @@
       "../../Babylon/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
       "../../Babylon/PostProcess/babylon.lensRenderingPipeline.js",
       "../../Babylon/PostProcess/babylon.colorCorrectionPostProcess.js",
-      "../../Babylon/Cameras/babylon.stereoscopicCamera.js"
+      "../../Babylon/Cameras/babylon.stereoscopicCameras.js"
     ]
   },
   "shadersDirectories": [