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

Last change on this file since 4906 was 4904, checked in by ldelgass, 5 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
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (c) 2004-2013  HUBzero Foundation, LLC
4 *
5 *  Authors:
6 *    Wei Qiao <qiaow@purdue.edu>
7 */
8#include <stdio.h>
9#include <math.h>
10#include <float.h>
11
12#include <GL/glew.h>
13#include <GL/glu.h>
14
15#include <vrmath/Quaternion.h>
16#include <vrmath/Rotation.h>
17#include <vrmath/Matrix4x4d.h>
18#include <vrmath/Vector3f.h>
19#include <vrmath/Vector4f.h>
20#include <vrmath/BBox.h>
21
22#include "nanovis.h"
23#include "Camera.h"
24#include "Trace.h"
25
26using namespace nv;
27using namespace vrmath;
28
29static inline double deg2rad(double deg)
30{
31    return ((deg * M_PI) / 180.);
32}
33
34static inline double rad2deg(double rad)
35{
36    return ((rad * 180.) / M_PI);
37}
38
39Camera::Camera(int x, int y, int width, int height) :
40    _updir(Y_POS),
41    _position(0, 0, 2.5),
42    _fov(30.0),
43    _near(0.1),
44    _far(50.0)
45{
46    _viewport[0] = x;
47    _viewport[1] = y;
48    _viewport[2] = width;
49    _viewport[3] = height;
50}
51
52const Matrix4x4d&
53Camera::getUpDirMatrix() const
54{
55    return _updirMatrix;
56}
57
58void
59Camera::setUpDirMatrix(AxisDirection dir)
60{
61    _updir = dir;
62
63    switch (_updir) {
64    case X_POS: {
65        _updirMatrix.makeRotation(0, 0, 1, deg2rad(90));
66        Matrix4x4d tmp;
67        tmp.makeRotation(1, 0, 0, deg2rad(90));
68        _updirMatrix.multiply(tmp);
69    }
70        break;
71    case Y_POS:
72        _updirMatrix.makeIdentity();
73        break;
74    case Z_POS: {
75        _updirMatrix.makeRotation(1, 0, 0, deg2rad(-90));
76        Matrix4x4d tmp;
77        tmp.makeRotation(0, 0, 1, deg2rad(-90));
78        _updirMatrix.multiply(tmp);
79    }
80        break;
81    case X_NEG:
82        _updirMatrix.makeRotation(0, 0, 1, deg2rad(-90));
83        break;
84    case Y_NEG: {
85        _updirMatrix.makeRotation(0, 0, 1, deg2rad(180));
86        Matrix4x4d tmp;
87        tmp.makeRotation(0, 1, 0, deg2rad(-90));
88        _updirMatrix.multiply(tmp);
89    }
90        break;
91    case Z_NEG:
92        _updirMatrix.makeRotation(1, 0, 0, deg2rad(90));
93        break;
94    }
95}
96
97/**
98 * \brief Reset zoom to include extents
99 */
100void
101Camera::reset(const Vector3f& bboxMin,
102              const Vector3f& bboxMax,
103              bool resetOrientation)
104{
105    TRACE("Enter");
106
107    if (resetOrientation) {
108        _rotationMatrix.makeIdentity();
109    }
110
111    Vector3f center(bboxMin + bboxMax);
112    center.scale(0.5);
113
114    Matrix4x4d mat, upMat;
115    upMat = getUpDirMatrix();
116    mat.makeTranslation(-center);
117    mat.multiply(_rotationMatrix, mat);
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
133    for (int i = 0; i < 8; i++) {
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;
141    }
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
157    double winAspect = (double)_viewport[2]/(double)_viewport[3];
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));
167    }
168
169    distance = _near + bdepth * 0.5;
170    _far = _near + bdepth;
171
172    _position.set(center.x, center.y, center.z + distance);
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);
176    TRACE("pos: %g, %g, %g", _position.x, _position.y, _position.z);
177    TRACE("near: %g, far: %g", _near, _far);
178
179    initialize();
180    resetClippingRange(bboxMin, bboxMax);
181}
182
183/**
184 * \brief Reset near and far planes based on given world space
185 * bounding box
186 */
187void
188Camera::resetClippingRange(const Vector3f& bboxMin, const Vector3f& bboxMax)
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
203    TRACE("c: %g,%g,%g, r: %g cam z: %g", center.x, center.y, center.z, radius, _position.z);
204
205    _near = _position.z - radius;
206    _far = _position.z + radius;
207
208    if (_near < 0.0) {
209        _near = 0.001;
210    }
211    if (_far < 0.0) {
212        _far = 1.0;
213    }
214
215    TRACE("Resetting camera clipping range to: near: %g, far: %g", _near, _far);
216
217    glMatrixMode(GL_PROJECTION);
218    glLoadIdentity();
219    gluPerspective(_fov, 
220                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3], 
221                   _near, _far);
222    glMatrixMode(GL_MODELVIEW);
223
224    print();
225}
226
227void 
228Camera::initialize()
229{
230    TRACE("Enter");
231    print();
232
233    glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]);
234    glMatrixMode(GL_PROJECTION);
235    glLoadIdentity();
236    gluPerspective(_fov, 
237                   (GLdouble)_viewport[2]/(GLdouble)_viewport[3], 
238                   _near, _far);
239
240    glMatrixMode(GL_MODELVIEW);
241    glLoadIdentity();
242
243    glTranslatef(-_position.x, -_position.y, -_position.z);
244    glMultMatrixd((const GLdouble *)_rotationMatrix.get());
245}
246
247void Camera::getProjectionMatrix(Matrix4x4d& mat)
248{
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{
262    Quaternion q(quat[0], quat[1], quat[2], quat[3]);
263    Rotation rot;
264    rot.set(q);
265    _rotationMatrix.makeRotation(rot);
266    _rotationMatrix.transpose();
267
268    TRACE("Set rotation to quat: %g %g %g %g",
269          quat[0], quat[1], quat[2], quat[3]);
270}
271
272void Camera::orient(float angleX, float angleY, float angleZ)
273{
274    angleX = -angleX;
275    angleY = angleY - 180.;
276
277    _rotationMatrix.makeRotation(1, 0, 0, deg2rad(angleX));
278    Matrix4x4d mat;
279    mat.makeRotation(0, 1, 0, deg2rad(angleY));
280    _rotationMatrix.multiply(mat);
281    mat.makeRotation(0, 0, 1, deg2rad(angleZ));
282    _rotationMatrix.multiply(mat);
283
284    TRACE("Set rotation to angles: %g %g %g",
285          angleX, angleY, angleZ);
286}
287
288void Camera::print() const
289{
290    TRACE("x: %d y: %d w: %d h: %d",
291          _viewport[0], _viewport[1], _viewport[2], _viewport[3]);
292    TRACE("fov: %g near: %g far: %g", _fov, _near, _far);
293    TRACE("pos: %g %g %g",
294          _position.x, _position.y, _position.z);
295    TRACE("Rotation matrix: ");
296    _rotationMatrix.print();
297}
Note: See TracBrowser for help on using the repository browser.