#include #include #include #include #include using namespace osg; Camera::Camera(DisplaySettings* ds) { _adjustAspectRatioMode = ADJUST_HORIZONTAL; // projection details. float fovy = 45.0f; if (ds) { fovy = 2.0f*RadiansToDegrees(atan(ds->getScreenHeight()*0.5/ds->getScreenDistance())); } setPerspective(fovy,1.0,1.0,1000.0); // look at details. _lookAtType =USE_HOME_POSITON; _eye.set(0.0f,0.0f,0.0f); _center.set(0.0f,0.0f,-1.0f); _up.set(0.0f,1.0f,0.0f); _useNearClippingPlane = false; _useFarClippingPlane = false; _useEyeOffset = false; _eyeOffset.set(0.0f,0.0f,0.0f); _attachedTransformMode = NO_ATTACHED_TRANSFORM; if (ds) _screenDistance = ds->getScreenDistance(); else _screenDistance = 0.33f; _fusionDistanceMode = PROPORTIONAL_TO_LOOK_DISTANCE; _fusionDistanceRatio = 1.0f; } Camera::Camera(const Camera& camera):Referenced() { copy(camera); } Camera& Camera::operator=(const Camera& camera) { if (&camera==this) return *this; copy(camera); return *this; } void Camera::copy(const Camera& camera) { _projectionType = camera._projectionType; // how the window dimensions should be altered during a window resize. _adjustAspectRatioMode = camera._adjustAspectRatioMode; // note, in Frustum/Perspective mode these values are scaled // by the zNear from when they were initialised to ensure that // subsequent changes in zNear do not affect them. _left = camera._left; _right = camera._right; _bottom = camera._bottom; _top = camera._top; _zNear = camera._zNear; _zFar = camera._zFar; // look at details. _lookAtType = camera._lookAtType; _eye = camera._eye; _center = camera._center; _up = camera._up; _attachedTransformMode = camera._attachedTransformMode; _eyeToModelTransform = camera._eyeToModelTransform; _modelToEyeTransform = camera._modelToEyeTransform; // flags to determine if near and far clipping planes are required. _useNearClippingPlane = camera._useNearClippingPlane; _useFarClippingPlane = camera._useFarClippingPlane; // cached matrix and clipping volume derived from above settings. _dirty = camera._dirty; _projectionMatrix = camera._projectionMatrix; _modelViewMatrix = camera._modelViewMatrix; _clippingVolume = camera._clippingVolume; _mp = camera._mp; _inversemp = camera._inversemp; _useEyeOffset = camera._useEyeOffset; _eyeOffset = camera._eyeOffset; _screenDistance = camera._screenDistance; _fusionDistanceMode = camera._fusionDistanceMode; _fusionDistanceRatio = camera._fusionDistanceRatio; } Camera::~Camera() { } /** Set a orthographics projection. See glOrtho for further details.*/ void Camera::setOrtho(const double left, const double right, const double bottom, const double top, const double zNear, const double zFar) { _projectionType = ORTHO; _left = left; _right = right; _bottom = bottom; _top = top; _zNear = zNear; _zFar = zFar; _dirty = true; } /** Set a 2D orthographics projection. See gluOrtho2D for further details.*/ void Camera::setOrtho2D(const double left, const double right, const double bottom, const double top) { _projectionType = ORTHO2D; _left = left; _right = right; _bottom = bottom; _top = top; _zNear = -1.0; _zFar = 1.0; _dirty = true; } /** Set a perspective projection. See glFrustum for further details.*/ void Camera::setFrustum(const double left, const double right, const double bottom, const double top, const double zNear, const double zFar) { _projectionType = FRUSTUM; // note, in Frustum/Perspective mode these values are scaled // by the zNear from when they were initialised to ensure that // subsequent changes in zNear do not affect them. _left = left/zNear; _right = right/zNear; _bottom = bottom/zNear; _top = top/zNear; _zNear = zNear; _zFar = zFar; _dirty = true; } /** Set a sysmetical perspective projection, See gluPerspective for further details.*/ void Camera::setPerspective(const double fovy,const double aspectRatio, const double zNear, const double zFar) { _projectionType = PERSPECTIVE; // note, in Frustum/Perspective mode these values are scaled // by the zNear from when they were initialised to ensure that // subsequent changes in zNear do not affect them. // calculate the appropriate left, right etc. double tan_fovy = tan(DegreesToRadians(fovy*0.5)); _right = tan_fovy * aspectRatio; _left = -_right; _top = tan_fovy; _bottom = -_top; _zNear = zNear; _zFar = zFar; _dirty = true; } /** Set a sysmetical perspective projection using field of view.*/ void Camera::setFOV(const double fovx,const double fovy, const double zNear, const double zFar) { _projectionType = PERSPECTIVE; // note, in Frustum/Perspective mode these values are scaled // by the zNear from when they were initialised to ensure that // subsequent changes in zNear do not affect them. // calculate the appropriate left, right etc. double tan_fovx = tan(DegreesToRadians(fovx*0.5)); double tan_fovy = tan(DegreesToRadians(fovy*0.5)); _right = tan_fovx; _left = -_right; _top = tan_fovy; _bottom = -_top; _zNear = zNear; _zFar = zFar; _dirty = true; } /** Set the near and far clipping planes.*/ void Camera::setNearFar(const double zNear, const double zFar) { _zNear = zNear; _zFar = zFar; _dirty = true; if (_projectionType==ORTHO2D) { if (_zNear!=-1.0 || _zFar!=1.0) _projectionType = ORTHO; } _dirty = true; } /** Adjust the clipping planes to account for a new window aspcect ratio. * Typicall used after resizeing a window.*/ void Camera::adjustAspectRatio(const double newAspectRatio, const AdjustAspectRatioMode aa) { if (newAspectRatio<0.01f || newAspectRatio>100.0f) { notify(NOTICE)<<"Warning: aspect ratio out of range (0.01..100) in Camera::adjustAspectRatio("<invert(*_eyeToModelTransform)) { notify(WARN)<<"Warning: Camera::attachTransform() failed to invert _modelToEyeTransform"<invert(*_modelToEyeTransform)) { notify(WARN)<<"Warning: Camera::attachTransform() failed to invert _modelToEyeTransform"<invert(*_eyeToModelTransform)) { notify(WARN)<<"Warning: Camera::dirtyTransform() failed to invert _modelToEyeTransform"<invert(*_modelToEyeTransform)) { notify(WARN)<<"Warning: Camera::dirtyTransform() failed to invert _eyeToModelTransform"<makeIdentity(); } break; case(USE_EYE_AND_QUATERNION): // not implemented yet, default to eye,center,up. case(USE_EYE_CENTER_AND_UP): default: { Vec3 f(_center-_eye); f.normalize(); Vec3 s(f^_up); s.normalize(); Vec3 u(s^f); u.normalize(); ref_ptr matrix = new Matrix( s[0], u[0], -f[0], 0.0f, s[1], u[1], -f[1], 0.0f, s[2], u[2], -f[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); (*matrix) = Matrix::translate(-_eye[0], -_eye[1], -_eye[2]) * (*matrix); if (_modelToEyeTransform.valid()) { _modelViewMatrix = new Matrix; (*_modelViewMatrix) = (*matrix) * (*_modelToEyeTransform); } else { _modelViewMatrix = matrix; } } break; } if (_useEyeOffset) { (*_modelViewMatrix) = (*_modelViewMatrix) * Matrix::translate(-_eyeOffset*(getFusionDistance()/_screenDistance)); } _clippingVolume.clear(); // set the clipping volume. switch(_projectionType) { case(ORTHO): case(ORTHO2D): { } break; case(FRUSTUM): case(PERSPECTIVE): { // calculate the frustum normals, postive pointing inwards. // left clipping plane // note, _left,_right,_top and _bottom are already devided // by _zNear so no need to take into account for normal // calculations. Vec3 leftNormal (1.0f,0.0f,_left); leftNormal.normalize(); _clippingVolume.add(Plane(leftNormal,0.0f)); Vec3 rightNormal (-1.0f,0.0f,-_right); rightNormal.normalize(); _clippingVolume.add(Plane(rightNormal,0.0f)); Vec3 bottomNormal(0.0f,1.0f,_bottom); bottomNormal.normalize(); _clippingVolume.add(Plane(bottomNormal,0.0f)); Vec3 topNormal(0.0f,-1.0f,-_top); topNormal.normalize(); _clippingVolume.add(Plane(topNormal,0.0f)); if (_useNearClippingPlane) { _clippingVolume.add(Plane(0.0f,0.0f,-1.0f,-_zNear)); } if (_useFarClippingPlane) { _clippingVolume.add(Plane(0.0f,0.0f,1.0f,_zFar)); } } break; } _clippingVolume.transformProvidingInverse(*_modelViewMatrix); if (!_mp.valid()) _mp = new Matrix; _mp->mult(*_modelViewMatrix,*_projectionMatrix); if (!_inversemp.valid()) _inversemp = new Matrix; if (!_inversemp->invert(*_mp)) { notify(WARN)<<"Warning: Camera::calculateMatricesAndClippingVolume() failed to invert _mp"<