source: trunk/packages/vizservers/nanovis/NvCamera.cpp @ 3492

Last change on this file since 3492 was 3492, checked in by ldelgass, 7 years ago

Fix camera reset for nanovis. Includes refactoring of vector/matrix classes
in nanovis to consolidate into vrmath library. Also add preliminary canonical
view control to clients for testing.

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