diff --git a/doomsday/client/src/gl/gl_main.cpp b/doomsday/client/src/gl/gl_main.cpp index a741129014..e4dcb46917 100644 --- a/doomsday/client/src/gl/gl_main.cpp +++ b/doomsday/client/src/gl/gl_main.cpp @@ -589,13 +589,6 @@ void GL_ProjectionMatrix() // We're assuming pixels are squares. float aspect = viewpw / (float) viewph; - - DENG_ASSERT_IN_MAIN_THREAD(); - DENG_ASSERT_GL_CONTEXT_ACTIVE(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (VR::mode() == VR::MODE_OCULUS_RIFT) { aspect = VR::riftAspect(); @@ -608,27 +601,34 @@ void GL_ProjectionMatrix() yfov = Rend_FieldOfView() / aspect; } - // Replaced gluPerspective() with glFrustum() so we can do stereo 3D - // gluPerspective(yfov, aspect, glNearClip, glFarClip); // Replaced with lower-level glFrustum() float fH = tan(0.5 * de::degreeToRadian(yfov)) * glNearClip; float fW = fH*aspect; - // Asymmetric frustum shift is computed to realign screen-depth items after view point has shifted. - // Asymmetric frustum shift method is probably superior to competing toe-in stereo 3D method: - // * AFS preserves identical near and far clipping planes in both views - // * AFS shows items at/near infinity better - // * AFS conforms to what stereo 3D photographers call "ortho stereo" - // Asymmetric frustum shift is used for all stereo 3D modes except Oculus Rift mode, which only applies the viewpoint shift. + /* + * Asymmetric frustum shift is computed to realign screen-depth items after view point has shifted. + * Asymmetric frustum shift method is probably superior to competing toe-in stereo 3D method: + * - AFS preserves identical near and far clipping planes in both views + * - AFS shows items at/near infinity better + * - AFS conforms to what stereo 3D photographers call "ortho stereo" + * Asymmetric frustum shift is used for all stereo 3D modes except Oculus Rift mode, which only + * applies the viewpoint shift. + */ float frustumShift = 0; if (VR::applyFrustumShift) + { frustumShift = VR::eyeShift * glNearClip / VR::hudDistance; - glFrustum(-fW - frustumShift, fW - frustumShift, - -fH, fH, - glNearClip, glFarClip); - // Actually shift the player viewpoint - glTranslatef(-VR::eyeShift, 0, 0); + } + + DENG_ASSERT_IN_MAIN_THREAD(); + DENG_ASSERT_GL_CONTEXT_ACTIVE(); + // Actually shift the player viewpoint // We'd like to have a left-handed coordinate system. - glScalef(1, 1, -1); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf((Matrix4f::frustum(-fW - frustumShift, fW - frustumShift, + -fH, fH, + glNearClip, glFarClip) * + Matrix4f::translate(Vector3f(-VR::eyeShift, 0, 0)) * + Matrix4f::scale(Vector3f(1, 1, -1))).values()); } #undef GL_UseFog diff --git a/doomsday/libdeng2/include/de/core/matrix.h b/doomsday/libdeng2/include/de/core/matrix.h index b93b4e6e2d..935c446204 100644 --- a/doomsday/libdeng2/include/de/core/matrix.h +++ b/doomsday/libdeng2/include/de/core/matrix.h @@ -330,6 +330,22 @@ class Matrix4 m[14] = -(farDistance + nearDistance) / (farDistance - nearDistance); return m; } + static Matrix4 frustum(Type left, Type right, Type bottom, Type top, Type zNear, Type zFar) { + // This is identical to glFrustum. + Type const A = (right + left) / (right - left); + Type const B = (top + bottom) / (top - bottom); + Type const C = - (zFar + zNear) / (zFar - zNear); + Type const D = - (Type(2) * zFar * zNear) / (zFar - zNear); + Matrix4 m(Zero); + m.at(0, 0) = (Type(2) * zNear) / (right - left); + m.at(1, 1) = (Type(2) * zNear) / (top - bottom); + m.at(0, 2) = A; + m.at(1, 2) = B; + m.at(2, 2) = C; + m.at(3, 2) = -Type(1); + m.at(2, 3) = D; + return m; + } static Matrix4 perspective(Type fov, Type aspectRatio, Type nearDistance = 1.f, Type farDistance = 1000.f) { Type const halfWidth = std::tan(Type(.5) * degreeToRadian(fov)); Type const halfHeight = halfWidth / aspectRatio;