diff --git a/examples/files.js b/examples/files.js
index 5df19e5e179a69a012bf2455288d4d2863c9536f..d68b7eeef9865cb5aa807a3c6004a1547c82a2a2 100644
--- a/examples/files.js
+++ b/examples/files.js
@@ -325,6 +325,7 @@ var files = {
"webvr_ballshooter",
"webvr_cubes",
"webvr_dragging",
+ "webvr_frustum",
"webvr_lorenzattractor",
"webvr_panorama",
"webvr_paint",
diff --git a/examples/webvr_frustum.html b/examples/webvr_frustum.html
new file mode 100644
index 0000000000000000000000000000000000000000..6960b76e50168e09e178252f5cf79dfb47cd875a
--- /dev/null
+++ b/examples/webvr_frustum.html
@@ -0,0 +1,129 @@
+
+
+
+ three.js webvr - frustum
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cameras/ArrayCamera.js b/src/cameras/ArrayCamera.js
index fc98224bf79fd89c9956dccc5e084d4008aef669..0de9131c194b736d0230c2fa1c69fe3986de66db 100644
--- a/src/cameras/ArrayCamera.js
+++ b/src/cameras/ArrayCamera.js
@@ -3,6 +3,7 @@
*/
import { PerspectiveCamera } from './PerspectiveCamera.js';
+import { Vector3 } from '../math/Vector3.js';
function ArrayCamera( array ) {
@@ -16,7 +17,66 @@ ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototyp
constructor: ArrayCamera,
- isArrayCamera: true
+ isArrayCamera: true,
+
+ /**
+ * Assumes 2 cameras that are perpendicular and share an X-axis, and that
+ * the cameras' projection and world matrices have already been set.
+ * And that near and far planes are identical for both cameras.
+ */
+ setProjectionFromUnion: function () {
+ var cameraLPos = new Vector3();
+ var cameraRPos = new Vector3();
+
+ return function () {
+ cameraLPos.setFromMatrixPosition( this.cameras[ 0 ].matrixWorld );
+ cameraRPos.setFromMatrixPosition( this.cameras[ 1 ].matrixWorld );
+
+ var ipd = cameraLPos.distanceTo( cameraRPos );
+
+ var projL = this.cameras[ 0 ].projectionMatrix;
+ var projR = this.cameras[ 1 ].projectionMatrix;
+
+ // VR systems will have identical far and near planes, and
+ // most likely identical top and bottom frustum extents.
+ // via: https://computergraphics.stackexchange.com/a/4765
+ var near = projL[ 14 ] / ( projL[ 10 ] - 1 );
+ var far = projL[ 14 ] / ( projL[ 10 ] + 1 );
+
+ var leftFovL = ( projL[ 8 ] - 1 ) / projL[ 0 ];
+ var rightFovR = ( projR[ 8 ] + 1 ) / projR[ 0 ];
+ var leftL = leftFovL * near;
+ var rightR = rightFovR * near;
+ var topL = near * ( projL[ 9 ] + 1 ) / projL[ 5 ];
+ var topR = near * ( projR[ 9 ] + 1 ) / projR[ 5 ];
+ var bottomL = near * ( projL[ 9 ] - 1 ) / projL[ 5 ];
+ var bottomR = near * ( projR[ 9 ] - 1 ) / projR[ 5 ];
+
+ // Calculate the new camera's position offset from the
+ // left camera.
+ var zOffset = ipd / (leftFovL + rightFovR);
+ var xOffset = zOffset * leftFovL;
+
+ // TODO: Better way to apply this offset?
+ this.cameras[ 0 ].matrixWorld.decompose( this.position, this.quaternion, this.scale );
+ this.translateX(xOffset);
+ this.translateZ(-zOffset);
+ this.matrixWorld.compose( this.position, this.quaternion, this.scale );
+ this.matrixWorldInverse.getInverse(this.matrixWorld);
+
+ // Find the union of the frustum values of the cameras and scale
+ // the values so that the near plane's position does not change in world space,
+ // although must now be relative to the new union camera.
+ var near2 = near + zOffset;
+ var far2 = far + zOffset;
+ var left = leftL - xOffset;
+ var right = rightR + (ipd - xOffset)
+ var top = Math.max( topL, topR );
+ var bottom = Math.min( bottomL, bottomR );
+
+ this.projectionMatrix.makePerspective( left, right, top, bottom, near2, far2 );
+ }
+ }(),
} );
diff --git a/src/renderers/webvr/WebVRManager.js b/src/renderers/webvr/WebVRManager.js
index bbf9d31554e1139f8039f67b305e10de4208520d..d978dc4cc93273a0a270c0d06a0dcbee4750ddfd 100644
--- a/src/renderers/webvr/WebVRManager.js
+++ b/src/renderers/webvr/WebVRManager.js
@@ -290,9 +290,6 @@ function WebVRManager( renderer ) {
cameraL.far = camera.far;
cameraR.far = camera.far;
- cameraVR.matrixWorld.copy( camera.matrixWorld );
- cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
-
cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );
@@ -326,10 +323,7 @@ function WebVRManager( renderer ) {
cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );
- // HACK (mrdoob)
- // https://github.com/w3c/webvr/issues/203
-
- cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
+ cameraVR.setProjectionFromUnion();
//
diff --git a/src/renderers/webvr/WebXRManager.js b/src/renderers/webvr/WebXRManager.js
index 0adc0e7751e47c2dd364686e428d5cf6b3184166..1d8f6242dd22b5dcd3392516edc38f972f1bc4e5 100644
--- a/src/renderers/webvr/WebXRManager.js
+++ b/src/renderers/webvr/WebXRManager.js
@@ -161,8 +161,6 @@ function WebXRManager( renderer ) {
var parent = camera.parent;
var cameras = cameraVR.cameras;
- // apply camera.parent to cameraVR
-
updateCamera( cameraVR, parent );
for ( var i = 0; i < cameras.length; i ++ ) {
@@ -183,6 +181,8 @@ function WebXRManager( renderer ) {
}
+ cameraVR.setProjectionFromUnion();
+
return cameraVR;
}
@@ -221,11 +221,6 @@ function WebXRManager( renderer ) {
cameraVR.matrix.copy( camera.matrix );
- // HACK (mrdoob)
- // https://github.com/w3c/webvr/issues/203
-
- cameraVR.projectionMatrix.copy( camera.projectionMatrix );
-
}
}