Commit 0c93d51c authored by Robert Menzel's avatar Robert Menzel

worked on camera, parallel shift mode should work (untested)

parent 6d8697b6
/***********************************************************************
* Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#ifndef ACGL_SCENE_CAMERA_HH
#define ACGL_SCENE_CAMERA_HH
#ifdef ACGL_INCLUDE_DEPRECATED_FUNCTIONALITY
/*
* A generic camera class.
*/
#include <ACGL/ACGL.hh>
#include <ACGL/Math/Math.hh>
namespace ACGL{
namespace Scene{
class Camera
{
public:
Camera(void)
: mRight (),
mUp (),
mForward (),
mWidth (800),
mHeight (600),
mFOV (75.0f),
mNear (0.1f),
mFar (10000.0f),
mPitch (0.0f),
mYaw (0.0f),
mRoll (0.0f),
mPosition (3.0f, 2.0f, 3.0f),
mTarget (0.0f, 0.0f, 0.0f)
{
updateLocalCoordinateSystemByTarget();
updateOrientationByLocalCoordinateSystem();
}
Camera(
int_t _width,
int_t _height,
float _fov,
float _near,
float _far,
const glm::vec3& _position,
const glm::vec3& _target)
: mRight (),
mUp (),
mForward (),
mWidth (_width),
mHeight (_height),
mFOV (_fov),
mNear (_near),
mFar (_far),
mPitch (0.0f),
mYaw (0.0f),
mRoll (0.0f),
mPosition (_position),
mTarget (_target)
{
updateLocalCoordinateSystemByTarget();
updateOrientationByLocalCoordinateSystem();
}
Camera(const Camera& other)
: mRight (other.mRight),
mUp (other.mUp),
mForward (other.mForward),
mWidth (other.mWidth),
mHeight (other.mHeight),
mFOV (other.mFOV),
mNear (other.mNear),
mFar (other.mFar),
mPitch (other.mPitch),
mYaw (other.mYaw),
mRoll (other.mRoll),
mPosition (other.mPosition),
mTarget (other.mTarget)
{
}
~Camera(void) {}
inline float getAspectRatio (void) const { return (float)mWidth / (float)mHeight; }
inline const glm::vec3& getUpDirection (void) const { return mUp; }
inline const glm::vec3& getRightDirection (void) const { return mRight; }
inline const glm::vec3& getForwardDirection (void) const { return mForward; }
inline int_t getWidth (void) const { return mWidth; }
inline int_t getHeight (void) const { return mHeight; }
inline float getFOV (void) const { return mFOV; }
inline float getNear (void) const { return mNear; }
inline float getFar (void) const { return mFar; }
inline float getPitch (void) const { return mPitch; }
inline float getYaw (void) const { return mYaw; }
inline float getRoll (void) const { return mRoll; }
inline const glm::vec3& getPosition (void) const { return mPosition; }
inline const glm::vec3& getTarget (void) const { return mTarget; }
inline void setWidth (int_t _width) { mWidth = _width; }
inline void setHeight (int_t _height) { mHeight = _height; }
inline void setFOV (float _fov) { mFOV = _fov; }
inline void setNear (float _near) { mNear = _near; }
inline void setFar (float _far) { mFar = _far; }
inline void setPosition(const glm::vec3& _position, bool _moveTarget = true)
{
if(_moveTarget)
mTarget += _position - mPosition;
mPosition = _position;
if(!_moveTarget)
updateLocalCoordinateSystemByTarget(mUp);
}
inline void setPosition(const glm::vec3& _position, const glm::vec3& _up, bool _moveTarget = true)
{
if(_moveTarget)
mTarget += _position - mPosition;
mPosition = _position;
updateLocalCoordinateSystemByTarget(_up);
}
inline void setTarget(const glm::vec3& _target, bool _movePosition = true)
{
if(_movePosition)
mPosition += _target - mTarget;
mTarget = _target;
if(!_movePosition)
updateLocalCoordinateSystemByTarget(mUp);
}
inline void setPitch(float _pitch)
{
mPitch = _pitch;
updateLocalCoordinateSystemByOrientation();
mTarget = mPosition + glm::length(mTarget - mPosition) * mForward;
}
inline void setYaw(float _yaw)
{
mYaw = _yaw;
updateLocalCoordinateSystemByOrientation();
mTarget = mPosition + glm::length(mTarget - mPosition) * mForward;
}
inline void setRoll(float _roll)
{
mRoll = _roll;
}
inline void setPitchAroundTarget(float pitch)
{
mPitch = pitch;
updateLocalCoordinateSystemByOrientation();
mPosition = mTarget - glm::length(mTarget - mPosition) * mForward;
}
inline void setYawAroundTarget(float yaw)
{
mYaw = yaw;
updateLocalCoordinateSystemByOrientation();
mPosition = mTarget - glm::length(mTarget - mPosition) * mForward;
}
inline void setOrientation(float _pitch, float _yaw, float _roll)
{
mPitch = _pitch;
mYaw = _yaw;
mRoll = _roll;
updateLocalCoordinateSystemByOrientation();
}
glm::mat4 getProjectionMatrix() const;
glm::mat4 getViewMatrix() const;
glm::mat4 getInverseViewMatrix() const;
private:
void updateLocalCoordinateSystemByTarget(const glm::vec3& _up = glm::vec3(0.0f, 1.0f, 0.0f));
void updateLocalCoordinateSystemByOrientation(void);
void updateOrientationByLocalCoordinateSystem(void);
glm::vec3 mRight;
glm::vec3 mUp;
glm::vec3 mForward;
int_t mWidth;
int_t mHeight;
float mFOV;
float mNear;
float mFar;
float mPitch;
float mYaw;
float mRoll;
glm::vec3 mPosition;
glm::vec3 mTarget;
};
} // Scene
} // ACGL
#endif
#endif // ACGL_SCENE_CAMERA_HH
This diff is collapsed.
/***********************************************************************
* Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#include <ACGL/Scene/Camera.hh>
#ifdef ACGL_INCLUDE_DEPRECATED_FUNCTIONALITY
using namespace ACGL;
using namespace ACGL::Scene;
glm::mat4 Camera::getProjectionMatrix(void) const
{
// returns a projection matrix as gluPerspective would do
return glm::perspective( mFOV, getAspectRatio(), mNear, mFar );
}
glm::mat4 Camera::getViewMatrix(void) const
{
glm::mat4 mView;
mView[0][0] = mRight.x;
mView[0][1] = mUp.x;
mView[0][2] = -mForward.x;
mView[1][0] = mRight.y;
mView[1][1] = mUp.y;
mView[1][2] = -mForward.y;
mView[2][0] = mRight.z;
mView[2][1] = mUp.z;
mView[2][2] = -mForward.z;
mView[3][0] = -(mRight.x * mPosition.x + mRight.y * mPosition.y + mRight.z * mPosition.z);
mView[3][1] = -(mUp.x * mPosition.x + mUp.y * mPosition.y + mUp.z * mPosition.z);
mView[3][2] = (mForward.x * mPosition.x + mForward.y * mPosition.y + mForward.z * mPosition.z);
return mView;
}
glm::mat4 Camera::getInverseViewMatrix(void) const
{
glm::mat4 mView;
mView[0][0] = mRight.x;
mView[0][1] = mRight.y;
mView[0][2] = mRight.z;
mView[1][0] = mUp.x;
mView[1][1] = mUp.y;
mView[1][2] = mUp.z;
mView[2][0] = -mForward.x;
mView[2][1] = -mForward.y;
mView[2][2] = -mForward.z;
mView[3][0] = mPosition.x;
mView[3][1] = mPosition.y;
mView[3][2] = mPosition.z;
return mView;
}
void Camera::updateLocalCoordinateSystemByTarget(const glm::vec3& _up)
{
mForward = glm::normalize( mTarget - mPosition );
mRight = glm::normalize( glm::cross( mForward, _up) );
mUp = glm::normalize( glm::cross( mRight, mForward) );
updateOrientationByLocalCoordinateSystem();
}
void Camera::updateLocalCoordinateSystemByOrientation(void)
{
//Calculate the full rotation in the right order:
//rot => 1. mYaw (y) -> 2. mPitch (x) -> 3. mRoll (z)
glm::mat3 rx = Math::Functions::rotationMatrixX(mPitch);
glm::mat3 ry = Math::Functions::rotationMatrixY(mYaw);
glm::mat3 rz = Math::Functions::rotationMatrixZ(mRoll);
glm::mat3 rotation = ry * rx * rz;
mRight = rotation * glm::vec3(1.0f, 0.0f, 0.0f);
mUp = rotation * glm::vec3(0.0f, 1.0f, 0.0f);
mForward = rotation * glm::vec3(0.0f, 0.0f, -1.0f);
}
void Camera::updateOrientationByLocalCoordinateSystem(void)
{
if (mUp.x > 1.0f - Math::Constants::EPSILON_FLOAT)
{
mYaw = Math::Functions::atan2Deg(mForward.x, -mForward.z);
mPitch = 90.0f;
mRoll = 0.0f;
return;
}
if (mUp.x < Math::Constants::EPSILON_FLOAT - 1.0f)
{
mYaw = Math::Functions::atan2Deg(mForward.x, -mForward.z);
mPitch = -90.0f;
mRoll = 0.0f;
return;
}
mYaw = Math::Functions::atan2Deg(-mRight.z, mRight.x);
mPitch = Math::Functions::atan2Deg( mForward.y, mUp.y);
mRoll = Math::Functions::asinDeg( mRight.y);
}
#endif
......@@ -35,6 +35,11 @@ GenericCamera::GenericCamera() :
setRotationMatrix( glm::mat3(1.0f) );
}
GenericCamera::GenericCamera( const std::string &_state )
{
setStateFromString( _state );
}
void GenericCamera::FPSstyleLookAround( float _deltaX, float _deltaY )
{
float yaw = 0.0f;
......@@ -184,80 +189,73 @@ void GenericCamera::setLookAtDistance(float _distance)
mLookAtDistance = _distance;
}
//glm::mat4 FrescoCamera::getCameraMatrix( double _eyeShift, double _toeInValue )
//{
// cout << " TODO: getCameraMatrix" << endl;
/*
// we have to move to the left (eyeShift in meter) and tilt to the left (toeInValue)
// left of course is defined by the current rotation!
Rotation camRotation = rotation * Rotation( 0.0, 1.0, 0.0, toeInValue );
Vector3 camPosition = position + rotation * Vector3(eyeShift, 0.0, 0.0);
return HomogenousMatrix(camRotation, camPosition, Vector3(1.0,1.0,1.0));
*/
// glm::mat4 projectionMatrix; // all values are 0
// return projectionMatrix;
//}
//glm::mat4 FrescoCamera::getPerspectiveProjectionMatrix( double _eyeShift )
//{
// cout << " TODO: getPerspectiveProjectionMatrix" << endl;
//glm::mat4 projectionMatrix; // all values are 0
/*
double right = tan( degToRad(getHorizontalFieldOfView() * 0.5f) ) * nearClippingPlane;
double left = -right;
// we want the images to match on the screen == at the focalDistance
// not at the near clipping plane.
left += eyeShift * (nearClippingPlane/focalDistance);
right += eyeShift * (nearClippingPlane/focalDistance);
double top = tan( degToRad(getVerticalFieldOfView() * 0.5f) ) * nearClippingPlane;
double bottom = -top;
*/
/*
// we do the same here as a glFrustum call would do.
projectionMatrix[ 0][0] = 2.0*nearClippingPlane / (right - left);
projectionMatrix[ 1][1] = 2.0*nearClippingPlane / (top - bottom);
projectionMatrix[ 0][2] = (right + left) / (right - left);
projectionMatrix[ 1][2] = (top + bottom) / (top - bottom);
projectionMatrix[ 2][2] = -1.0*(farClippingPlane+nearClippingPlane) / (farClippingPlane - nearClippingPlane);
projectionMatrix[ 3][2] = -1.0;
projectionMatrix[ 2][3] = -2.0*farClippingPlane*nearClippingPlane / (farClippingPlane - nearClippingPlane);
glm::mat4 GenericCamera::getViewMatrix() const
{
if (mStereoMode == MONO) {
return getMonoViewMatrix();
} else {
// all kinds of stereo
bool eyeIsLeftEye = (getEye() == EYE_LEFT);
return getStereoViewMatrix( eyeIsLeftEye, mStereoMode );
}
}
return projectionMatrix;
*/
//return G3D::Matrix4::perspectiveProjection( left, right, bottom, top, nearClippingPlane, farClippingPlane );
//return glm::gtx::transform::perspective( (float)getHorizontalFieldOfView(), (float)getAspectRatio(), (float)mNearClippingPlane, (float)mFarClippingPlane );
//}
glm::mat4 GenericCamera::getStereoViewMatrix( bool _leftEye, StereoMode _stereoMode ) const
{
// The view matrix is independent of the projection mode (isometric or perspective)
// so only the stereo mode has to be checked.
assert( _stereoMode != MONO && "mono is not a stereo mode!" );
float cameraPositionShiftValue = (mEyeDistance*0.5f); // shift to the right
if (_leftEye) cameraPositionShiftValue *= -1.0f; // if left eye shift to the left
glm::mat4 GenericCamera::getProjectionMatrix() const
{
switch (this->mStereoMode)
{
case MONO: return getMonoProjectionMatrix();
default: assert( 0 && "unsupported stereo mode" );
return glm::mat4();
if ( (_stereoMode == PARALLEL_SHIFT) || (_stereoMode == OFF_AXIS) ) {
//
// parallel shift and off-axis have the same view matrices:
// just shift the camera position to the left/right by half the eye-distance
//
ACGL::Utils::debug() << "WARNING: getStereoViewMatrix() is not tested yet" << std::endl; // remove after testing
glm::mat3 inverseRotation = getInverseRotationMatrix3();
glm::vec3 eyePosition = mPosition + (inverseRotation * glm::vec3(cameraPositionShiftValue,0.0f,0.0f) );
glm::mat4 m(mRotationMatrix);
m[3][0] = -(m[0][0] * eyePosition.x + m[1][0] * eyePosition.y + m[2][0] * eyePosition.z);
m[3][1] = -(m[0][1] * eyePosition.x + m[1][1] * eyePosition.y + m[2][1] * eyePosition.z);
m[3][2] = -(m[0][2] * eyePosition.x + m[1][2] * eyePosition.y + m[2][2] * eyePosition.z);
return m;
}
// else it has to be toe-in:
assert( _stereoMode == TOE_IN && "unsupported stereo mode!" );
//
// Toe-in: shift the camera position to the left/right by half the eye-distance and
// rotate a bit inwards so that the two cameras focus the same point
// at the look-at distance (focal point)
assert(0 && "getStereoViewMatrix() for TOE_IN is not implemented yet!");
return glm::mat4();
}
glm::mat4 GenericCamera::getViewMatrix() const
glm::mat4 GenericCamera::getInverseViewMatrix() const
{
switch (this->mStereoMode)
{
case MONO: return getMonoViewMatrix();
default: assert( 0 && "unsupported stereo mode" );
return glm::mat4();
if (mStereoMode == MONO) {
return getMonoInverseViewMatrix();
}
glm::mat4 viewMatrix = getViewMatrix();
return glm::inverse( viewMatrix );
}
glm::mat4 GenericCamera::getInverseViewMatrix() const
glm::mat4 GenericCamera::getProjectionMatrix() const
{
switch (this->mStereoMode)
{
case MONO: return getMonoInverseViewMatrix();
default: assert( 0 && "unsupported stereo mode" );
return glm::mat4();
if (mStereoMode == MONO) {
return getMonoProjectionMatrix();
} else {
// all kinds of stereo
bool eyeIsLeftEye = (getEye() == EYE_LEFT);
return getStereoProjectionMatrix( eyeIsLeftEye, mStereoMode );
}
}
......@@ -317,61 +315,52 @@ glm::mat4 GenericCamera::getMonoInverseViewMatrix() const
assert( isApproxEqual( glm::inverse(getViewMatrix()), m ) );
return m;
}
/*
glm::mat4 GenericCamera::getStereoProjectionMatrix( bool _leftEye, StereoMode _stereoMode )
enum ProjectionMode
{
// ToeIn with parallel projection could work, but all the other modes wouldn't.
// But even this cambination would be very unusual, so it's not implemented.
assert( getProjectionMode() == PERSPECTIVE_PROJECTION );
ISOMETRIC_PROJECTION = 0,
PERSPECTIVE_PROJECTION
};
glm::mat4 cameraMatrix;
glm::mat4 projectionMatrix; // all values are 0
enum StereoMode
{
MONO = 0,
PARALLEL_SHIFT,
OFF_AXIS,
TOE_IN
};
double camRotation;
glm::mat4 GenericCamera::getStereoProjectionMatrix( bool _leftEye, StereoMode _stereoMode ) const
{
assert( _stereoMode != MONO && "mono is not a stereo mode!" );
// set the rotation of the camera to the right/left and get the projection matrix
if (_stereoMode == PARALLEL_SHIFT)
{
camRotation = 0.0f;
projectionMatrix = getPerspectiveProjectionMatrix();
}
else if (_stereoMode == OFF_AXIS)
{
camRotation = 0.0f;
if (_leftEye == true)
{
projectionMatrix = getPerspectiveProjectionMatrix( mEyeDistance * -0.5f );
}
else
{
projectionMatrix = getPerspectiveProjectionMatrix( mEyeDistance * 0.5f );
}
}
else if (_stereoMode == TOE_IN)
if ( getProjectionMode() == ISOMETRIC_PROJECTION )
{
camRotation = asin( mLookAtDistance * ACGL::Math::Functions::sqrt( mEyeDistance*mEyeDistance / 4.0 + mLookAtDistance*mLookAtDistance) );
projectionMatrix = getPerspectiveProjectionMatrix();
// very unusual, prepare for headaches!
return getMonoProjectionMatrix();
}
// get the camera matrix
if (_leftEye == true)
if ((_stereoMode == PARALLEL_SHIFT) || (_stereoMode == TOE_IN))
{
cameraMatrix = getCameraMatrix( mEyeDistance * -0.5f, camRotation );
}
else
{
cameraMatrix = getCameraMatrix( mEyeDistance * 0.5f, -1.0f * camRotation );
// the view matrix changes but the projection matrix stays the same
return getMonoProjectionMatrix();
}
return projectionMatrix;
}
// so off-axis it is!
assert( _stereoMode == OFF_AXIS && "unknown projection mode!" );
//
// In this mode the camera positions (view matrix) is shifted to the left/right still looking
// straight ahead. The projection is also looking ahead but the projection center is
// off (hence off-axis).
// There is one plane in front of the cameras where the view-frusta match.
// This should be the distance to the physical screen from the users position.
glm::mat4 GenericCamera::getStereoViewMatrix( bool _leftEye, StereoMode _stereoMode )
{
assert(0 && "getStereoViewMatrix() is not implemented for OFF_AXIS yet!");
return glm::mat4();
}
*/
/// Writes all internal state to one string
/// Elements are seperated by pipes ('|'), spaces can get ignored.
......@@ -454,19 +443,6 @@ void GenericCamera::setFocalLengthInPixel( float _focalLengthInPixel )
setHorizontalFieldOfView( calcRadToDeg( hFoVrad ) );
}
float GenericCamera::getFocalLenghtInMM() const
{
glm::vec2 sensorSize = glm::vec2( 36.0f/mAspectRatio, 24.0f ); // in mm
return ( sensorSize.x ) / ( 2.0f * tan( calcDegToRad(0.5f * mHorizontalFieldOfView) ) );
}
void GenericCamera::setFocalLengthInMM( float _focalLengthInMM )
{
glm::vec2 sensorSize = glm::vec2( 36.0f/mAspectRatio, 24.0f ); // in mm
float hFoVrad = 2.0f * atan( ( 0.5f * sensorSize.x ) * (1.0f / _focalLengthInMM ) );
setHorizontalFieldOfView( calcRadToDeg( hFoVrad ) );
}
/////////////// TESTS /////////////
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment