From 26d2c589f50f443dc70eac6466fae7515c0e564d Mon Sep 17 00:00:00 2001 From: Robert Menzel <menzel@informatik.rwth-aachen.de> Date: Mon, 23 Nov 2015 18:07:20 +0100 Subject: [PATCH] added more projection matrix types --- include/ACGL/Scene/CameraBase.hh | 11 +++++ include/ACGL/Scene/FixedCamera.hh | 14 ++++++- include/ACGL/Scene/GenericCamera.hh | 21 ++++++++-- src/ACGL/Scene/FixedCamera.cc | 65 ++++++++++++++++++++++++++++- src/ACGL/Scene/GenericCamera.cc | 42 ++++++++++++++++--- 5 files changed, 141 insertions(+), 12 deletions(-) diff --git a/include/ACGL/Scene/CameraBase.hh b/include/ACGL/Scene/CameraBase.hh index dc5af02b..52c69756 100644 --- a/include/ACGL/Scene/CameraBase.hh +++ b/include/ACGL/Scene/CameraBase.hh @@ -45,6 +45,17 @@ public: * @return the 2-dimensional size of the viewport */ virtual glm::uvec2 getViewportSize() const = 0; + /** + * @brief Gets the near clipping plane as a distance from the camera. + * @return the near clipping plane + */ + virtual float getNearClippingPlane() const = 0; + /** + * @brief Gets the far clipping plane as a distance from the camera. Note that it could be inf! + * Not all projection matrices have a real far plane but some are unlimited! + * @return the near clipping plane + */ + virtual float getFarClippingPlane() const = 0; }; } diff --git a/include/ACGL/Scene/FixedCamera.hh b/include/ACGL/Scene/FixedCamera.hh index 7140e40e..f1ca79b7 100644 --- a/include/ACGL/Scene/FixedCamera.hh +++ b/include/ACGL/Scene/FixedCamera.hh @@ -6,7 +6,8 @@ namespace ACGL{ namespace Scene{ /** - * @brief A fixed camera + * @brief A fixed camera where all attributes are set explicitly except for the near/far plane + * which are derrived from the projection matrix. */ class FixedCamera : public CameraBase { @@ -17,6 +18,11 @@ private: glm::mat4 mProjectionMatrix; glm::uvec2 mViewportSize; + // will get calculated based on the projection matrix + // so there are no explicit setters for this! + float mNearPlane; + float mFarPlane; + public: /// CAUTION: default ctor with zero values FixedCamera(); @@ -32,11 +38,15 @@ public: // Getter, Setter for Camera ProjectionMatrix virtual glm::mat4 getProjectionMatrix() const { return mProjectionMatrix; } - virtual void setProjectionMatrix(glm::mat4 const& _val) { mProjectionMatrix = _val; } + virtual void setProjectionMatrix(glm::mat4 const& _val); // Getter, Setter for Camera ViewportSize virtual glm::uvec2 getViewportSize() const { return mViewportSize; } virtual void setViewportSize(glm::uvec2 const& _val) { mViewportSize = _val; } + + // getters for near/far plane (far can be inf!) + virtual float getNearClippingPlane() const { return mNearPlane; } + virtual float getFarClippingPlane() const { return mFarPlane; } }; } diff --git a/include/ACGL/Scene/GenericCamera.hh b/include/ACGL/Scene/GenericCamera.hh index 23db9586..c26662f4 100644 --- a/include/ACGL/Scene/GenericCamera.hh +++ b/include/ACGL/Scene/GenericCamera.hh @@ -57,10 +57,23 @@ class GenericCamera : public CameraBase, public MoveableObject // Helping enums: // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /// use the DX reverse mode with: + /// * an infinite far plane + /// * a float z-buffer + /// * glClearDepth(0.0) + /// * glDepthFunc(GL_GREATER) + /// * either: + /// * glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE) (DX style mapping of the Z values) + /// or: + /// * glDepthRangedNV(-1.0, 1.0) + /// + /// this way near will get mapped to 1.0 and infinite to 0.0 enum ProjectionMode { ISOMETRIC_PROJECTION = 0, - PERSPECTIVE_PROJECTION + PERSPECTIVE_PROJECTION_OPENGL, // maps to -1..1 + PERSPECTIVE_PROJECTION_DX_REVERSE // maps to 1..0 }; enum StereoMode @@ -172,16 +185,17 @@ class GenericCamera : public CameraBase, public MoveableObject */ void setNearClippingPlane( float _plane ); /// Gets the near clip distance - float getNearClippingPlane() const { return mNearClippingPlane; } + virtual float getNearClippingPlane() const { return mNearClippingPlane; } /** * Set the far clipping plane of the camera. * The plane is defined only by a distance from the camera. + * This distance might be inf! * @param _plane New far clipping plane of the camera. */ void setFarClippingPlane( float _plane ); /// Gets the far clip distance - float getFarClippingPlane() const { return mFarClippingPlane; } + virtual float getFarClippingPlane() const { return mFarClippingPlane; } /// Gets size of the viewport virtual glm::uvec2 getViewportSize() const { return mViewportSize; } @@ -237,7 +251,6 @@ class GenericCamera : public CameraBase, public MoveableObject /// Gets the currently active projection matrix (depends on stereo mode and current eye) virtual glm::mat4 getProjectionMatrix() const; - /////////////////////////////////////////////////////////////////////////////////////////// // // Explicit view and projection matrices. These DON'T obey the set stereo/eye settings. diff --git a/src/ACGL/Scene/FixedCamera.cc b/src/ACGL/Scene/FixedCamera.cc index 2dbf9ae3..f2bc2291 100644 --- a/src/ACGL/Scene/FixedCamera.cc +++ b/src/ACGL/Scene/FixedCamera.cc @@ -16,9 +16,72 @@ FixedCamera::FixedCamera() FixedCamera::FixedCamera(const glm::vec3 &_pos, const glm::mat4 &_view, const glm::mat4 &_proj, const glm::uvec2 &_viewport) : mPosition(_pos), mViewMatrix(_view), - mProjectionMatrix(_proj), mViewportSize(_viewport) { + setProjectionMatrix( _proj ); +} + +void FixedCamera::setProjectionMatrix(glm::mat4 const& _val) +{ + mProjectionMatrix = _val; + + // + // Calculate near and far plane from the matrix + // As the matrix does not have to be a standard OpenGL + // projection matrix, we can't derrive the values from + // the matrix entries directly but we have to reproject + // points from the NDC cube... ...but as some matrices + // project to -1..1 and others to 0..1 we have to figure + // this out first... ...keeping in mind, that some also + // invert the range inside of the Z buffer, so Z=1 might + // be the near plane while Z=0 is the far plane... + // ...oh, and the far plane might be at infinity... + // + + // + // First step, figure out which values project to + // -1, 0 and 1: + // + glm::mat4 invProj = glm::inverse(mProjectionMatrix); + glm::vec4 tmp = invProj * glm::vec4( 0.0f, 0.0f, -1.0f, 1.0f); + float reproj_minusOne = tmp.z / tmp.w; + tmp = invProj * glm::vec4( 0.0f, 0.0f, 0.0f, 1.0f); + float reproj_Zero = tmp.z / tmp.w; + tmp = invProj * glm::vec4( 0.0f, 0.0f, 1.0f, 1.0f); + float reproj_One = tmp.z / tmp.w; + + // + // Next step, figure out which value is the near plane and which is the far plane. + // + // right handed coordinate system -> the camera was looking along the negative Z axis + // if it was an OpenGL matrix, the projections will result in -near, -something, -far + // if it was an OpenGL matrix with infinit far plane, the projections will result in -near, -something, -inf + // if it was a reverse DX style matrix it will result in +near, -inf, -near + + if (reproj_minusOne > 0.0f) { + // near,far mapped to 1,0 or 0,1 as -1 was mapped to a positive value which is behind the camera + // if we assume we are looking along the negative Z axis! + if (-reproj_Zero > -reproj_One) { + // the far plane is mapped to 0 -> inverse DX style + mFarPlane = -reproj_Zero; + mNearPlane = -reproj_One; + } else { + // the near plane is mapped to zero -> DX style + mFarPlane = -reproj_One; + mNearPlane = -reproj_Zero; + } + } else { + // OpenGL style, mapping to -1..1 or 1..-1 + if (-reproj_minusOne > -reproj_One) { + // the far plane is mapped to -1 -> inverse GL style + mFarPlane = -reproj_minusOne; + mNearPlane = -reproj_One; + } else { + // the near plane is mapped to -1 -> GL style + mFarPlane = -reproj_One; + mNearPlane = -reproj_minusOne; + } + } } } diff --git a/src/ACGL/Scene/GenericCamera.cc b/src/ACGL/Scene/GenericCamera.cc index 08d93e62..dfa3d9cc 100644 --- a/src/ACGL/Scene/GenericCamera.cc +++ b/src/ACGL/Scene/GenericCamera.cc @@ -21,7 +21,7 @@ using namespace ACGL::Utils::StringHelpers; using namespace std; GenericCamera::GenericCamera() : - mProjectionMode(PERSPECTIVE_PROJECTION), + mProjectionMode(PERSPECTIVE_PROJECTION_OPENGL), mStereoMode(MONO), mCurrentEye(EYE_LEFT), mHorizontalFieldOfView(75.0), @@ -247,10 +247,42 @@ glm::mat4 GenericCamera::getMonoProjectionMatrix() const projectionMatrix[ 2][3] = -(mFarClippingPlane+mNearClippingPlane)/(mFarClippingPlane-mNearClippingPlane); projectionMatrix[ 3][3] = 1.0; } - else if ( mProjectionMode == PERSPECTIVE_PROJECTION ) + else if ( mProjectionMode == PERSPECTIVE_PROJECTION_OPENGL ) { - projectionMatrix = glm::perspective( glm::radians( (float)getHorizontalFieldOfView()), (float)getAspectRatio(), (float)mNearClippingPlane, (float)mFarClippingPlane ); + if (std::isinf(mFarClippingPlane)) { + + float e = 1.0f / tan(ACGL::Math::Functions::calcDegToRad( getVerticalFieldOfView()*0.5f )); + const float a = getAspectRatio(); + + // infinite Perspective matrix reversed mapping to 1..-1 + projectionMatrix = { + e/a, 0.0f, 0.0f, 0.0f, + 0.0f, e, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, -1.0f, + 0.0f, 0.0f, -2.0*mNearClippingPlane, 0.0f + }; + } else { + projectionMatrix = glm::perspective( glm::radians( (float)getHorizontalFieldOfView()), (float)getAspectRatio(), (float)mNearClippingPlane, (float)mFarClippingPlane ); + } + } else if ( mProjectionMode == PERSPECTIVE_PROJECTION_DX_REVERSE ) + { + if (std::isinf(mFarClippingPlane)) { + + float e = 1.0f / tan(ACGL::Math::Functions::calcDegToRad( getVerticalFieldOfView()*0.5f )); + const float a = getAspectRatio(); + + // infinite Perspective matrix reversed mapping to 1..0 + projectionMatrix = { + e/a, 0.0f, 0.0f, 0.0f, + 0.0f, e, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, mNearClippingPlane, 0.0f + }; + } else { + assert(0 && "unsupported projection mode"); + } } + else assert(0 && "unsupported projection mode"); return projectionMatrix; @@ -320,7 +352,7 @@ std::string GenericCamera::storeStateToString() const state += toString( mPosition ) + " | "; state += toString( mRotationMatrix ) + " | "; if ( mProjectionMode == ISOMETRIC_PROJECTION ) state += "ISOMETRIC_PROJECTION | "; - if ( mProjectionMode == PERSPECTIVE_PROJECTION ) state += "PERSPECTIVE_PROJECTION | "; + if ( mProjectionMode == PERSPECTIVE_PROJECTION_OPENGL ) state += "PERSPECTIVE_PROJECTION | "; if ( mStereoMode == MONO) state += "MONO | "; if ( mStereoMode == PARALLEL_SHIFT) state += "PARALLEL_SHIFT | "; if ( mStereoMode == OFF_AXIS) state += "OFF_AXIS | "; @@ -358,7 +390,7 @@ void GenericCamera::setStateFromString( const std::string &_state ) mPosition = toVec3( token[pos++] ); mRotationMatrix = toMat3( token[pos++] ); if ( token[pos] == "ISOMETRIC_PROJECTION" ) mProjectionMode = ISOMETRIC_PROJECTION; - if ( token[pos] == "PERSPECTIVE_PROJECTION" ) mProjectionMode = PERSPECTIVE_PROJECTION; + if ( token[pos] == "PERSPECTIVE_PROJECTION" ) mProjectionMode = PERSPECTIVE_PROJECTION_OPENGL; pos++; if ( token[pos] == "MONO") mStereoMode = MONO; if ( token[pos] == "PARALLEL_SHIFT") mStereoMode = PARALLEL_SHIFT; -- GitLab