source: nanovis/branches/1.1/Camera.cpp @ 6307

Last change on this file since 6307 was 4904, checked in by ldelgass, 9 years ago

Merge serveral changes from trunk. Does not include threading, world space
changes, etc.

  • Property svn:eol-style set to native
File size: 7.7 KB
RevLine 
[2798]1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
[953]2/*
[3611]3 * Copyright (c) 2004-2013  HUBzero Foundation, LLC
[953]4 *
[3611]5 *  Authors:
6 *    Wei Qiao <qiaow@purdue.edu>
[953]7 */
[2836]8#include <stdio.h>
[2854]9#include <math.h>
[3362]10#include <float.h>
[953]11
[2836]12#include <GL/glew.h>
[953]13#include <GL/glu.h>
[2836]14
[3467]15#include <vrmath/Quaternion.h>
16#include <vrmath/Rotation.h>
[3492]17#include <vrmath/Matrix4x4d.h>
18#include <vrmath/Vector3f.h>
19#include <vrmath/Vector4f.h>
[4904]20#include <vrmath/BBox.h>
[2877]21
[3492]22#include "nanovis.h"
[3611]23#include "Camera.h"
[2836]24#include "Trace.h"
[953]25
[3611]26using namespace nv;
[3492]27using namespace vrmath;
28
29static inline double deg2rad(double deg)
[2854]30{
31    return ((deg * M_PI) / 180.);
32}
33
[3492]34static inline double rad2deg(double rad)
[2854]35{
36    return ((rad * 180.) / M_PI);
37}
38
[4904]39Camera::Camera(int x, int y, int width, int height) :
40    _updir(Y_POS),
41    _position(0, 0, 2.5),
[3362]42    _fov(30.0),
43    _near(0.1),
[4904]44    _far(50.0)
[2836]45{
[4904]46    _viewport[0] = x;
47    _viewport[1] = y;
48    _viewport[2] = width;
49    _viewport[3] = height;
[953]50}
51
[4904]52const Matrix4x4d&
53Camera::getUpDirMatrix() const
54{
55    return _updirMatrix;
56}
57
[3362]58void
[4904]59Camera::setUpDirMatrix(AxisDirection dir)
[3362]60{
[4904]61    _updir = dir;
62
63    switch (_updir) {
64    case X_POS: {
65        _updirMatrix.makeRotation(0, 0, 1, deg2rad(90));
[3492]66        Matrix4x4d tmp;
67        tmp.makeRotation(1, 0, 0, deg2rad(90));
[4904]68        _updirMatrix.multiply(tmp);
[3492]69    }
70        break;
[4904]71    case Y_POS:
72        _updirMatrix.makeIdentity();
[3492]73        break;
[4904]74    case Z_POS: {
75        _updirMatrix.makeRotation(1, 0, 0, deg2rad(-90));
[3492]76        Matrix4x4d tmp;
77        tmp.makeRotation(0, 0, 1, deg2rad(-90));
[4904]78        _updirMatrix.multiply(tmp);
[3492]79    }
80        break;
[4904]81    case X_NEG:
82        _updirMatrix.makeRotation(0, 0, 1, deg2rad(-90));
[3492]83        break;
[4904]84    case Y_NEG: {
85        _updirMatrix.makeRotation(0, 0, 1, deg2rad(180));
[3492]86        Matrix4x4d tmp;
87        tmp.makeRotation(0, 1, 0, deg2rad(-90));
[4904]88        _updirMatrix.multiply(tmp);
[3492]89    }
90        break;
[4904]91    case Z_NEG:
92        _updirMatrix.makeRotation(1, 0, 0, deg2rad(90));
[3492]93        break;
94    }
95}
96
97/**
98 * \brief Reset zoom to include extents
99 */
100void
[3611]101Camera::reset(const Vector3f& bboxMin,
102              const Vector3f& bboxMax,
103              bool resetOrientation)
[3492]104{
105    TRACE("Enter");
106
107    if (resetOrientation) {
[4904]108        _rotationMatrix.makeIdentity();
[3492]109    }
110
111    Vector3f center(bboxMin + bboxMax);
112    center.scale(0.5);
113
114    Matrix4x4d mat, upMat;
[4904]115    upMat = getUpDirMatrix();
[3492]116    mat.makeTranslation(-center);
[4904]117    mat.multiply(_rotationMatrix, mat);
[3492]118    mat.multiply(upMat);
119
120    Vector3f emin(FLT_MAX, FLT_MAX, FLT_MAX), emax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
121
122    // Transform bounds by camera matrix
123    Vector4f bboxEye[8];
124    bboxEye[0] = Vector4f(bboxMin.x, bboxMin.y, bboxMin.z, 1);
125    bboxEye[1] = Vector4f(bboxMax.x, bboxMin.y, bboxMin.z, 1);
126    bboxEye[2] = Vector4f(bboxMin.x, bboxMax.y, bboxMin.z, 1);
127    bboxEye[3] = Vector4f(bboxMin.x, bboxMin.y, bboxMax.z, 1);
128    bboxEye[4] = Vector4f(bboxMax.x, bboxMax.y, bboxMin.z, 1);
129    bboxEye[5] = Vector4f(bboxMax.x, bboxMin.y, bboxMax.z, 1);
130    bboxEye[6] = Vector4f(bboxMin.x, bboxMax.y, bboxMax.z, 1);
131    bboxEye[7] = Vector4f(bboxMax.x, bboxMax.y, bboxMax.z, 1);
132
[3362]133    for (int i = 0; i < 8; i++) {
[3492]134        Vector4f eyeVert = mat.transform(bboxEye[i]);
135        if (eyeVert.x < emin.x) emin.x = eyeVert.x;
136        if (eyeVert.x > emax.x) emax.x = eyeVert.x;
137        if (eyeVert.y < emin.y) emin.y = eyeVert.y;
138        if (eyeVert.y > emax.y) emax.y = eyeVert.y;
139        if (eyeVert.z < emin.z) emin.z = eyeVert.z;
140        if (eyeVert.z > emax.z) emax.z = eyeVert.z;
[3362]141    }
[3492]142
143    TRACE("Eye bounds: (%g,%g,%g) - (%g,%g,%g)",
144          emin.x, emin.y, emin.z,
145          emax.x, emax.y, emax.z);
146
147    double bwidth = emax.x - emin.x;
148    double bheight = emax.y - emin.y;
149    double bdepth = emax.z - emin.z;
150
151    TRACE("bwidth: %g, bheight: %g, bdepth: %g", bwidth, bheight, bdepth);
152
153    double angle = deg2rad(_fov);
154    double distance;
155
156    // Deal with vertical aspect window
[4904]157    double winAspect = (double)_viewport[2]/(double)_viewport[3];
[3492]158    double sceneAspect = 1.0;;
159    if (bheight > 0.0)
160        sceneAspect = bwidth / bheight;
161
162    if (sceneAspect >= winAspect) {
163        angle = 2.0 * atan(tan(angle*0.5)*winAspect);
164        _near = bwidth / (2.0 * tan(angle*0.5));
165    } else {
166        _near = bheight / (2.0 * tan(angle*0.5));
[3362]167    }
[3492]168
169    distance = _near + bdepth * 0.5;
170    _far = _near + bdepth;
171
[4904]172    _position.set(center.x, center.y, center.z + distance);
[3492]173
174    TRACE("win aspect: %g scene aspect: %g", winAspect, sceneAspect);
175    TRACE("c: %g,%g,%g, d: %g", center.x, center.y, center.z, distance);
[4904]176    TRACE("pos: %g, %g, %g", _position.x, _position.y, _position.z);
[3492]177    TRACE("near: %g, far: %g", _near, _far);
178
179    initialize();
180    resetClippingRange(bboxMin, bboxMax);
181}
182
[4904]183/**
184 * \brief Reset near and far planes based on given world space
185 * bounding box
186 */
[3492]187void
[3611]188Camera::resetClippingRange(const Vector3f& bboxMin, const Vector3f& bboxMax)
[3492]189{
190    Vector3f emin(bboxMin.x, bboxMin.y, bboxMin.z), emax(bboxMax.x, bboxMax.y, bboxMax.z);
191
192    Vector3f center(emin + emax);
193    center.scale(0.5);
194
195    // Compute the radius of the enclosing sphere,
196    // which is half the bounding box diagonal
197    Vector3f diagonal(emax - emin);
198    double radius = diagonal.length() * 0.5;
199
200    // If we have just a single point, pick a radius of 1.0
201    radius = (radius == 0) ? 1.0 : radius;
202
[4904]203    TRACE("c: %g,%g,%g, r: %g cam z: %g", center.x, center.y, center.z, radius, _position.z);
[3492]204
[4904]205    _near = _position.z - radius;
206    _far = _position.z + radius;
[3492]207
208    if (_near < 0.0) {
209        _near = 0.001;
[3362]210    }
[3492]211    if (_far < 0.0) {
212        _far = 1.0;
213    }
[3362]214
[3452]215    TRACE("Resetting camera clipping range to: near: %g, far: %g", _near, _far);
[3362]216
217    glMatrixMode(GL_PROJECTION);
218    glLoadIdentity();
219    gluPerspective(_fov,
[4904]220                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3],
[3362]221                   _near, _far);
222    glMatrixMode(GL_MODELVIEW);
[3492]223
224    print();
[3362]225}
226
[953]227void
[3611]228Camera::initialize()
[953]229{
[3492]230    TRACE("Enter");
231    print();
232
[4904]233    glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]);
[953]234    glMatrixMode(GL_PROJECTION);
235    glLoadIdentity();
[3362]236    gluPerspective(_fov,
[4904]237                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3],
[3362]238                   _near, _far);
[953]239
240    glMatrixMode(GL_MODELVIEW);
241    glLoadIdentity();
242
[4904]243    glTranslatef(-_position.x, -_position.y, -_position.z);
244    glMultMatrixd((const GLdouble *)_rotationMatrix.get());
[953]245}
[2877]246
[4904]247void Camera::getProjectionMatrix(Matrix4x4d& mat)
[2877]248{
[4904]249    glMatrixMode(GL_PROJECTION);
250    glPushMatrix();
251    glLoadIdentity();
252    gluPerspective(_fov,
253                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3],
254                   _near, _far);
255    glGetDoublev(GL_PROJECTION_MATRIX, (GLdouble *)mat.get());
256    glPopMatrix();
257    glMatrixMode(GL_MODELVIEW);
258}
259
260void Camera::orient(double *quat)
261{
[3492]262    Quaternion q(quat[0], quat[1], quat[2], quat[3]);
263    Rotation rot;
[2877]264    rot.set(q);
[4904]265    _rotationMatrix.makeRotation(rot);
266    _rotationMatrix.transpose();
267
[3452]268    TRACE("Set rotation to quat: %g %g %g %g",
[2877]269          quat[0], quat[1], quat[2], quat[3]);
270}
271
[4904]272void Camera::orient(float angleX, float angleY, float angleZ)
[2877]273{
[3362]274    angleX = -angleX;
275    angleY = angleY - 180.;
[2877]276
[4904]277    _rotationMatrix.makeRotation(1, 0, 0, deg2rad(angleX));
[3492]278    Matrix4x4d mat;
[3362]279    mat.makeRotation(0, 1, 0, deg2rad(angleY));
[4904]280    _rotationMatrix.multiply(mat);
[3362]281    mat.makeRotation(0, 0, 1, deg2rad(angleZ));
[4904]282    _rotationMatrix.multiply(mat);
[2877]283
[3452]284    TRACE("Set rotation to angles: %g %g %g",
[3362]285          angleX, angleY, angleZ);
[2877]286}
[3492]287
[3611]288void Camera::print() const
[3492]289{
[4904]290    TRACE("x: %d y: %d w: %d h: %d",
291          _viewport[0], _viewport[1], _viewport[2], _viewport[3]);
[3492]292    TRACE("fov: %g near: %g far: %g", _fov, _near, _far);
[4904]293    TRACE("pos: %g %g %g",
294          _position.x, _position.y, _position.z);
295    TRACE("Rotation matrix: ");
296    _rotationMatrix.print();
[3492]297}
Note: See TracBrowser for help on using the repository browser.