Skip to content

Commit

Permalink
Refactor|Client|libappfw: Calculate projection matrix in VRConfig
Browse files Browse the repository at this point in the history
The function for calculating a projection matrix suitable for the
current VR configuration was moved to libappfw. It was also broken
down to calculate vertical FOV and view aspect as separate methods.
  • Loading branch information
skyjake committed Feb 24, 2014
1 parent cb7e364 commit aec179a
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
8 changes: 8 additions & 0 deletions doomsday/client/src/gl/gl_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,13 @@ void GL_Restore2DState(int step, viewport_t const *port, viewdata_t const *viewD

Matrix4f GL_GetProjectionMatrix()
{
float const fov = Rend_FieldOfView();
Vector2f const size(viewpw, viewph);
yfov = vrCfg().verticalFieldOfView(fov, size);
return vrCfg().projectionMatrix(Rend_FieldOfView(), size, glNearClip, glFarClip);
}

#if 0
// We're assuming pixels are squares.
float aspect = viewpw / (float) viewph;

Expand Down Expand Up @@ -594,6 +601,7 @@ Matrix4f GL_GetProjectionMatrix()
Matrix4f::translate(Vector3f(-vrCfg().eyeShift(), 0, 0)) *
Matrix4f::scale(Vector3f(1, 1, -1));
}
#endif

void GL_ProjectionMatrix()
{
Expand Down
28 changes: 28 additions & 0 deletions doomsday/libappfw/include/de/vr/vrconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define LIBAPPFW_VRCONFIG_H

#include <de/OculusRift>
#include <de/Matrix>

namespace de {

Expand Down Expand Up @@ -172,6 +173,33 @@ class LIBAPPFW_PUBLIC VRConfig
/// Multisampling used in unwarped Rift framebuffer.
int riftFramebufferSampleCount() const;

float viewAspect(Vector2f const &viewPortSize) const;

/**
* Calculates a vertical field of view angle based on a horizontal FOV angle,
* view port size, and the current VR configuration.
*
* @param horizFovDegrees Field of view horizontally, in degrees.
* @param viewPortSize Size of the viewport in pixels.
*
* @return Vertical field of view, in degrees.
*/
float verticalFieldOfView(float horizFovDegrees, Vector2f const &viewPortSize) const;

/**
* Produces a projection matrix suitable for the current VR configuration.
*
* @param fovDegrees Horizontal field of view angle.
* @param viewPortSize Size of the viewport in pixels.
* @param nearClip Distance of the near clipping plane.
* @param farClip Distance of the far clipping plane.
*
* @return Projection matrix.
*/
Matrix4f projectionMatrix(float fovDegrees,
Vector2f const &viewPortSize,
float nearClip, float farClip) const;

de::OculusRift &oculusRift();
de::OculusRift const &oculusRift() const;

Expand Down
58 changes: 58 additions & 0 deletions doomsday/libappfw/src/vr/vrconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include "de/VRConfig"
#include "de/math.h"

namespace de {

Expand Down Expand Up @@ -174,6 +175,63 @@ int VRConfig::riftFramebufferSampleCount() const
return d->riftFramebufferSamples;
}

float VRConfig::viewAspect(Vector2f const &viewPortSize) const
{
if(mode() == OculusRift)
{
// Override with the Oculus Rift's aspect ratio.
return oculusRift().aspect();
}

// We're assuming pixels are squares.
return viewPortSize.x / viewPortSize.y;
}

float VRConfig::verticalFieldOfView(float horizFovDegrees, Vector2f const &viewPortSize) const
{
// We're assuming pixels are squares.
float const aspect = viewAspect(viewPortSize);

if(mode() == OculusRift)
{
// A little trigonometry to apply aspect ratio to angles
float x = std::tan(.5f * degreeToRadian(horizFovDegrees));
return radianToDegree(2.f * std::atan2(x / aspect, 1.f));
}

return horizFovDegrees / aspect;
}

Matrix4f VRConfig::projectionMatrix(float fovDegrees,
Vector2f const &viewPortSize,
float nearClip, float farClip) const
{
float const yfov = verticalFieldOfView(fovDegrees, viewPortSize);
float const fH = std::tan(.5f * degreeToRadian(yfov)) * nearClip;
float const fW = fH * viewAspect(viewPortSize);

/*
* 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 shift = 0;
if(frustumShift())
{
shift = eyeShift() * nearClip / screenDistance();
}

return Matrix4f::frustum(-fW - shift, fW - shift,
-fH, fH,
nearClip, farClip) *
Matrix4f::translate(Vector3f(-eyeShift(), 0, 0)) *
Matrix4f::scale(Vector3f(1, 1, -1));
}

OculusRift &VRConfig::oculusRift()
{
return d->ovr;
Expand Down

0 comments on commit aec179a

Please sign in to comment.