00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "domUtils.h"
00024 #include "camera.h"
00025 #include "qglviewer.h"
00026
00027 using namespace std;
00028 using namespace qglviewer;
00029
00037 Camera::Camera()
00038 : fieldOfView_(M_PI/4.0f)
00039 {
00040
00041 interpolationKfi_ = new KeyFrameInterpolator;
00042
00043 setFrame(new ManipulatedCameraFrame());
00044
00045
00046
00047
00048 setSceneRadius(1.0);
00049
00050
00051 orthoCoef_ = tan(fieldOfView()/2.0);
00052
00053
00054 setSceneCenter(Vec(0.0, 0.0, 0.0));
00055
00056
00057 setType(PERSPECTIVE);
00058
00059
00060 setZNearCoefficient(0.005f);
00061 setZClippingCoefficient(sqrt(3.0));
00062
00063
00064 setScreenWidthAndHeight(600, 400);
00065
00066
00067 setIODistance(0.062f);
00068 setPhysicalDistanceToScreen(0.5f);
00069 setPhysicalScreenWidth(0.4f);
00070
00071
00072
00073 for (unsigned short j=0; j<16; ++j)
00074 {
00075 modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0);
00076
00077 projectionMatrix_[j] = 0.0;
00078 }
00079 computeProjectionMatrix();
00080 }
00081
00086 Camera::~Camera()
00087 {
00088 delete frame_;
00089 delete interpolationKfi_;
00090 }
00091
00092
00094 Camera::Camera(const Camera& camera)
00095 : QObject()
00096 {
00097
00098 interpolationKfi_ = new KeyFrameInterpolator;
00099
00100 setFrame(new ManipulatedCameraFrame());
00101
00102 for (unsigned short j=0; j<16; ++j)
00103 {
00104 modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0);
00105
00106 projectionMatrix_[j] = 0.0;
00107 }
00108
00109 (*this)=camera;
00110 }
00111
00124 Camera& Camera::operator=(const Camera& camera)
00125 {
00126 setScreenWidthAndHeight(camera.screenWidth(), camera.screenHeight());
00127 setFieldOfView(camera.fieldOfView());
00128 setSceneRadius(camera.sceneRadius());
00129 setSceneCenter(camera.sceneCenter());
00130 setZNearCoefficient(camera.zNearCoefficient());
00131 setZClippingCoefficient(camera.zClippingCoefficient());
00132 setType(camera.type());
00133
00134
00135 setIODistance(camera.IODistance());
00136 setFocusDistance(camera.focusDistance());
00137 setPhysicalScreenWidth(camera.physicalScreenWidth());
00138 setPhysicalDistanceToScreen(camera.physicalDistanceToScreen());
00139
00140 orthoCoef_ = camera.orthoCoef_;
00141
00142
00143 frame_->setReferenceFrame(NULL);
00144 frame_->setPosition(camera.position());
00145 frame_->setOrientation(camera.orientation());
00146
00147 interpolationKfi_->resetInterpolation();
00148
00149 kfi_ = camera.kfi_;
00150
00151 computeProjectionMatrix();
00152 computeModelViewMatrix();
00153
00154 return *this;
00155 }
00156
00166 void Camera::setScreenWidthAndHeight(int width, int height)
00167 {
00168
00169 screenWidth_ = width > 0 ? width : 1;
00170 screenHeight_ = height > 0 ? height : 1;
00171 }
00172
00210 float Camera::zNear() const
00211 {
00212 float z = distanceToSceneCenter() - zClippingCoefficient()*sceneRadius();
00213
00214
00215 const float zMin = zNearCoefficient() * zClippingCoefficient() * sceneRadius();
00216 if (z < zMin)
00217 switch (type())
00218 {
00219 case Camera::PERSPECTIVE : z = zMin; break;
00220 case Camera::ORTHOGRAPHIC : z = 0.0; break;
00221 }
00222 return z;
00223 }
00224
00234 float Camera::zFar() const
00235 {
00236 return distanceToSceneCenter() + zClippingCoefficient()*sceneRadius();
00237 }
00238
00248 void Camera::setType(Type type)
00249 {
00250
00251
00252
00253 if ( (type == Camera::ORTHOGRAPHIC) && (type_ == Camera::PERSPECTIVE) )
00254 orthoCoef_ = tan(fieldOfView()/2.0);
00255 type_ = type;
00256 }
00257
00271 void Camera::setFrame(ManipulatedCameraFrame* const mcf)
00272 {
00273 if (!mcf)
00274 return;
00275
00276 frame_ = mcf;
00277 interpolationKfi_->setFrame(frame());
00278 }
00279
00282 float Camera::distanceToSceneCenter() const
00283 {
00284 return fabs((frame()->coordinatesOf(sceneCenter())).z);
00285 }
00286
00287
00303 void Camera::getOrthoWidthHeight(GLdouble& halfWidth, GLdouble& halfHeight) const
00304 {
00305 const float dist = orthoCoef_ * fabs(cameraCoordinatesOf(revolveAroundPoint()).z);
00306
00307 halfWidth = dist * ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
00308 halfHeight = dist * ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0);
00309 }
00310
00311
00329 void Camera::computeProjectionMatrix() const
00330 {
00331 const float ZNear = zNear();
00332 const float ZFar = zFar();
00333
00334 switch (type())
00335 {
00336 case Camera::PERSPECTIVE:
00337 {
00338
00339 const float f = 1.0/tan(fieldOfView()/2.0);
00340 projectionMatrix_[0] = f/aspectRatio();
00341 projectionMatrix_[5] = f;
00342 projectionMatrix_[10] = (ZNear + ZFar) / (ZNear - ZFar);
00343 projectionMatrix_[11] = -1.0;
00344 projectionMatrix_[14] = 2.0 * ZNear * ZFar / (ZNear - ZFar);
00345 projectionMatrix_[15] = 0.0;
00346
00347 break;
00348 }
00349 case Camera::ORTHOGRAPHIC:
00350 {
00351 GLdouble w, h;
00352 getOrthoWidthHeight(w,h);
00353 projectionMatrix_[0] = 1.0/w;
00354 projectionMatrix_[5] = 1.0/h;
00355 projectionMatrix_[10] = -2.0/(ZFar - ZNear);
00356 projectionMatrix_[11] = 0.0;
00357 projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear);
00358 projectionMatrix_[15] = 1.0;
00359
00360 break;
00361 }
00362 }
00363 }
00364
00375 void Camera::computeModelViewMatrix() const
00376 {
00377 const Quaternion q = frame()->orientation();
00378
00379 const double q00 = 2.0l * q[0] * q[0];
00380 const double q11 = 2.0l * q[1] * q[1];
00381 const double q22 = 2.0l * q[2] * q[2];
00382
00383 const double q01 = 2.0l * q[0] * q[1];
00384 const double q02 = 2.0l * q[0] * q[2];
00385 const double q03 = 2.0l * q[0] * q[3];
00386
00387 const double q12 = 2.0l * q[1] * q[2];
00388 const double q13 = 2.0l * q[1] * q[3];
00389
00390 const double q23 = 2.0l * q[2] * q[3];
00391
00392 modelViewMatrix_[0] = 1.0l - q11 - q22;
00393 modelViewMatrix_[1] = q01 - q23;
00394 modelViewMatrix_[2] = q02 + q13;
00395 modelViewMatrix_[3] = 0.0l;
00396
00397 modelViewMatrix_[4] = q01 + q23;
00398 modelViewMatrix_[5] = 1.0l - q22 - q00;
00399 modelViewMatrix_[6] = q12 - q03;
00400 modelViewMatrix_[7] = 0.0l;
00401
00402 modelViewMatrix_[8] = q02 - q13;
00403 modelViewMatrix_[9] = q12 + q03;
00404 modelViewMatrix_[10] = 1.0l - q11 - q00;
00405 modelViewMatrix_[11] = 0.0l;
00406
00407 const Vec t = q.inverseRotate(frame()->position());
00408
00409 modelViewMatrix_[12] = -t.x;
00410 modelViewMatrix_[13] = -t.y;
00411 modelViewMatrix_[14] = -t.z;
00412 modelViewMatrix_[15] = 1.0l;
00413 }
00414
00415
00434 void Camera::loadProjectionMatrix(bool reset) const
00435 {
00436
00437 glMatrixMode(GL_PROJECTION);
00438
00439 if (reset)
00440 glLoadIdentity();
00441
00442 computeProjectionMatrix();
00443
00444 glMultMatrixd(projectionMatrix_);
00445 }
00446
00471 void Camera::loadModelViewMatrix(bool reset) const
00472 {
00473
00474 glMatrixMode(GL_MODELVIEW);
00475 computeModelViewMatrix();
00476 if (reset)
00477 glLoadMatrixd(modelViewMatrix_);
00478 else
00479 glMultMatrixd(modelViewMatrix_);
00480 }
00481
00507 void Camera::loadProjectionMatrixStereo(bool leftBuffer) const
00508 {
00509 float left, right, bottom, top;
00510 float screenHalfWidth, halfWidth, side, shift, delta;
00511
00512 glMatrixMode(GL_PROJECTION);
00513 glLoadIdentity();
00514
00515 switch (type())
00516 {
00517 case Camera::PERSPECTIVE:
00518
00519
00520 screenHalfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0);
00521 shift = screenHalfWidth * IODistance() / physicalScreenWidth();
00522
00523
00524
00525
00526
00527 halfWidth = zNear() * tan(horizontalFieldOfView() / 2.0);
00528 delta = shift * zNear() / focusDistance();
00529 side = leftBuffer ? -1.0 : 1.0;
00530
00531 left = -halfWidth + side * delta;
00532 right = halfWidth + side * delta;
00533 top = halfWidth / aspectRatio();
00534 bottom = -top;
00535 glFrustum(left, right, bottom, top, zNear(), zFar() );
00536 break;
00537
00538 case Camera::ORTHOGRAPHIC:
00539 qWarning("Camera::setProjectionMatrixStereo: Stereo not available with Ortho mode");
00540 break;
00541 }
00542 }
00543
00562 void Camera::loadModelViewMatrixStereo(bool leftBuffer) const
00563 {
00564
00565 glMatrixMode(GL_MODELVIEW);
00566
00567 float halfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0);
00568 float shift = halfWidth * IODistance() / physicalScreenWidth();
00569
00570 computeModelViewMatrix();
00571 if (leftBuffer)
00572 modelViewMatrix_[12] -= shift;
00573 else
00574 modelViewMatrix_[12] += shift;
00575 glLoadMatrixd(modelViewMatrix_);
00576 }
00577
00592 void Camera::getProjectionMatrix(GLdouble m[16]) const
00593 {
00594
00595 computeProjectionMatrix();
00596 for (unsigned short i=0; i<16; ++i)
00597 m[i] = projectionMatrix_[i];
00598 }
00599
00614 void Camera::getModelViewMatrix(GLdouble m[16]) const
00615 {
00616
00617
00618 computeModelViewMatrix();
00619 for (unsigned short i=0; i<16; ++i)
00620 m[i] = modelViewMatrix_[i];
00621 }
00622
00626 void Camera::getModelViewProjectionMatrix(GLdouble m[16]) const
00627 {
00628 GLdouble mv[16];
00629 GLdouble proj[16];
00630 getModelViewMatrix(mv);
00631 getProjectionMatrix(proj);
00632
00633 for (unsigned short i=0; i<4; ++i)
00634 {
00635 for (unsigned short j=0; j<4; ++j)
00636 {
00637 double sum = 0.0;
00638 for (unsigned short k=0; k<4; ++k)
00639 sum += proj[i+4*k]*mv[k+4*j];
00640 m[i+4*j] = sum;
00641 }
00642 }
00643 }
00644
00645 #ifndef DOXYGEN
00646 void Camera::getProjectionMatrix(GLfloat m[16]) const
00647 {
00648 qWarning("Warning : Camera::getProjectionMatrix requires a GLdouble matrix array");
00649 static GLdouble mat[16];
00650 getProjectionMatrix(mat);
00651 for (int i=0; i<16; ++i)
00652 m[i] = float(mat[i]);
00653 }
00654
00655 void Camera::getModelViewMatrix(GLfloat m[16]) const
00656 {
00657 qWarning("Warning : Camera::getModelViewMatrix requires a GLdouble matrix array");
00658 static GLdouble mat[16];
00659 getModelViewMatrix(mat);
00660 for (int i=0; i<16; ++i)
00661 m[i] = float(mat[i]);
00662 }
00663 #endif
00664
00669 void Camera::setSceneRadius(float radius)
00670 {
00671 if (radius <= 0.0)
00672 {
00673 qWarning("Scene radius must be positive - Ignoring value");
00674 return;
00675 }
00676
00677 sceneRadius_ = radius;
00678
00679 setFocusDistance(sceneRadius() / tan(fieldOfView()/2.0));
00680
00681 frame()->setFlySpeed(0.01*sceneRadius());
00682 }
00683
00686 void Camera::setSceneBoundingBox(const Vec& min, const Vec& max)
00687 {
00688 setSceneCenter((min+max)/2.0);
00689 setSceneRadius(0.5*(max-min).norm());
00690 }
00691
00692
00696 void Camera::setSceneCenter(const Vec& center)
00697 {
00698 sceneCenter_ = center;
00699 setRevolveAroundPoint(sceneCenter());
00700 }
00701
00707 bool Camera::setSceneCenterFromPixel(const QPoint& pixel)
00708 {
00709 bool found;
00710 Vec point = pointUnderPixel(pixel, found);
00711 if (found)
00712 setSceneCenter(point);
00713 return found;
00714 }
00715
00717 void Camera::setRevolveAroundPoint(const Vec& rap)
00718 {
00719 const float prevDist = fabs(cameraCoordinatesOf(revolveAroundPoint()).z);
00720
00721 frame()->setRevolveAroundPoint(rap);
00722
00723
00724
00725 const float newDist = fabs(cameraCoordinatesOf(revolveAroundPoint()).z);
00726
00727 if ((prevDist > 1E-9) && (newDist > 1E-9))
00728 orthoCoef_ *= prevDist / newDist;
00729 }
00730
00740 bool Camera::setRevolveAroundPointFromPixel(const QPoint& pixel)
00741 {
00742 bool found;
00743 Vec point = pointUnderPixel(pixel, found);
00744 if (found)
00745 setRevolveAroundPoint(point);
00746 return found;
00747 }
00748
00763 float Camera::pixelGLRatio(const Vec& position) const
00764 {
00765 switch (type())
00766 {
00767 case Camera::PERSPECTIVE :
00768 return 2.0 * fabs((frame()->coordinatesOf(position)).z) * tan(fieldOfView()/2.0) / screenHeight();
00769 case Camera::ORTHOGRAPHIC :
00770 {
00771 GLdouble w, h;
00772 getOrthoWidthHeight(w,h);
00773 return 2.0 * h / screenHeight();
00774 }
00775 }
00776
00777 return 1.0;
00778 }
00779
00805 void Camera::setFOVToFitScene()
00806 {
00807 if (distanceToSceneCenter() > sqrt(2.0)*sceneRadius())
00808 setFieldOfView(2.0 * asin(sceneRadius() / distanceToSceneCenter()));
00809 else
00810 setFieldOfView(M_PI / 2.0f);
00811 }
00812
00819 void Camera::interpolateToZoomOnPixel(const QPoint& pixel)
00820 {
00821 const float coef = 0.1f;
00822
00823 bool found;
00824 Vec target = pointUnderPixel(pixel, found);
00825
00826 if (!found)
00827 return;
00828
00829 if (interpolationKfi_->interpolationIsStarted())
00830 interpolationKfi_->stopInterpolation();
00831
00832 interpolationKfi_->deletePath();
00833 interpolationKfi_->addKeyFrame(*(frame()));
00834
00835 interpolationKfi_->addKeyFrame(Frame(0.3f*frame()->position() + 0.7f*target, frame()->orientation()), 0.4f);
00836
00837
00838 static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame();
00839 ManipulatedCameraFrame* const originalFrame = frame();
00840 tempFrame->setPosition(coef*frame()->position() + (1.0-coef)*target);
00841 tempFrame->setOrientation(frame()->orientation());
00842 setFrame(tempFrame);
00843 lookAt(target);
00844 setFrame(originalFrame);
00845
00846 interpolationKfi_->addKeyFrame(*(tempFrame), 1.0);
00847
00848 interpolationKfi_->startInterpolation();
00849 }
00850
00857 void Camera::interpolateToFitScene()
00858 {
00859 if (interpolationKfi_->interpolationIsStarted())
00860 interpolationKfi_->stopInterpolation();
00861
00862 interpolationKfi_->deletePath();
00863 interpolationKfi_->addKeyFrame(*(frame()));
00864
00865
00866 static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame();
00867 ManipulatedCameraFrame* const originalFrame = frame();
00868 tempFrame->setPosition(frame()->position());
00869 tempFrame->setOrientation(frame()->orientation());
00870 setFrame(tempFrame);
00871 showEntireScene();
00872 setFrame(originalFrame);
00873
00874 interpolationKfi_->addKeyFrame(*(tempFrame));
00875
00876 interpolationKfi_->startInterpolation();
00877 }
00878
00879
00886 void Camera::interpolateTo(const Frame& fr, float duration)
00887 {
00888 if (interpolationKfi_->interpolationIsStarted())
00889 interpolationKfi_->stopInterpolation();
00890
00891 interpolationKfi_->deletePath();
00892 interpolationKfi_->addKeyFrame(*(frame()));
00893 interpolationKfi_->addKeyFrame(fr, duration);
00894
00895 interpolationKfi_->startInterpolation();
00896 }
00897
00898
00915 Vec Camera::pointUnderPixel(const QPoint& pixel, bool& found) const
00916 {
00917 float depth;
00918
00919 glReadPixels(pixel.x(), screenHeight()-1-pixel.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
00920 found = depth < 1.0;
00921 Vec point(pixel.x(), pixel.y(), depth);
00922 point = unprojectedCoordinatesOf(point);
00923 return point;
00924 }
00925
00931 void Camera::showEntireScene()
00932 {
00933 fitSphere(sceneCenter(), sceneRadius());
00934 }
00935
00941 void Camera::centerScene()
00942 {
00943 frame()->projectOnLine(sceneCenter(), viewDirection());
00944 }
00945
00952 void Camera::lookAt(const Vec& target)
00953 {
00954 setViewDirection(target - position());
00955 }
00956
00964 void Camera::fitSphere(const Vec& center, float radius)
00965 {
00966 float distance = 0.0f;
00967 switch (type())
00968 {
00969 case Camera::PERSPECTIVE :
00970 {
00971 const float yview = radius / sin(fieldOfView()/2.0);
00972 const float xview = radius / sin(horizontalFieldOfView()/2.0);
00973 distance = qMax(xview,yview);
00974 break;
00975 }
00976 case Camera::ORTHOGRAPHIC :
00977 {
00978 distance = ((center-revolveAroundPoint()) * viewDirection()) + (radius / orthoCoef_);
00979 break;
00980 }
00981 }
00982 Vec newPos(center - distance * viewDirection());
00983 frame()->setPositionWithConstraint(newPos);
00984 }
00985
00988 void Camera::fitBoundingBox(const Vec& min, const Vec& max)
00989 {
00990 float diameter = qMax(fabs(max[1]-min[1]), fabs(max[0]-min[0]));
00991 diameter = qMax(fabsf(max[2]-min[2]), diameter);
00992 fitSphere(0.5*(min+max), 0.5*diameter);
00993 }
00994
01002 void Camera::fitScreenRegion(const QRect& rectangle)
01003 {
01004 const Vec vd = viewDirection();
01005 const float distToPlane = distanceToSceneCenter();
01006 const QPoint center = rectangle.center();
01007
01008 Vec orig, dir;
01009 convertClickToLine( center, orig, dir );
01010 Vec newCenter = orig + distToPlane / (dir*vd) * dir;
01011
01012 convertClickToLine( QPoint(rectangle.x(), center.y()), orig, dir );
01013 const Vec pointX = orig + distToPlane / (dir*vd) * dir;
01014
01015 convertClickToLine( QPoint(center.x(), rectangle.y()), orig, dir );
01016 const Vec pointY = orig + distToPlane / (dir*vd) * dir;
01017
01018 float distance = 0.0f;
01019 switch (type())
01020 {
01021 case Camera::PERSPECTIVE :
01022 {
01023 const float distX = (pointX-newCenter).norm() / sin(horizontalFieldOfView()/2.0);
01024 const float distY = (pointY-newCenter).norm() / sin(fieldOfView()/2.0);
01025 distance = qMax(distX, distY);
01026 break;
01027 }
01028 case Camera::ORTHOGRAPHIC :
01029 {
01030 const float dist = ((newCenter-revolveAroundPoint()) * vd);
01031
01032 const float distX = (pointX-newCenter).norm() / orthoCoef_ / ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
01033 const float distY = (pointY-newCenter).norm() / orthoCoef_ / ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0);
01034 distance = dist + qMax(distX, distY);
01035 break;
01036 }
01037 }
01038
01039 Vec newPos(newCenter - distance * vd);
01040 frame()->setPositionWithConstraint(newPos);
01041 }
01042
01058 void Camera::setUpVector(const Vec& up, bool noMove)
01059 {
01060 Quaternion q(Vec(0.0, 1.0, 0.0), frame()->transformOf(up));
01061
01062 if (!noMove)
01063 frame()->setPosition(revolveAroundPoint() - (frame()->orientation()*q).rotate(frame()->coordinatesOf(revolveAroundPoint())));
01064
01065 frame()->rotate(q);
01066
01067
01068 frame()->updateFlyUpVector();
01069 }
01070
01082 void Camera::setOrientation(float theta, float phi)
01083 {
01084 Vec axis(0.0, 1.0, 0.0);
01085 const Quaternion rot1(axis, theta);
01086 axis = Vec(-cos(theta), 0., sin(theta));
01087 const Quaternion rot2(axis, phi);
01088 setOrientation(rot1 * rot2);
01089 }
01090
01092 void Camera::setOrientation(const Quaternion& q)
01093 {
01094 frame()->setOrientation(q);
01095 frame()->updateFlyUpVector();
01096 }
01097
01103 void Camera::setViewDirection(const Vec& direction)
01104 {
01105 if (direction.squaredNorm() < 1E-10)
01106 return;
01107
01108 Vec xAxis = direction ^ upVector();
01109 if (xAxis.squaredNorm() < 1E-10)
01110 {
01111
01112
01113 xAxis = frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
01114 }
01115
01116 Quaternion q;
01117 q.setFromRotatedBasis(xAxis, xAxis^direction, -direction);
01118 frame()->setOrientationWithConstraint(q);
01119 }
01120
01121
01122 static float det(float m00,float m01,float m02,
01123 float m10,float m11,float m12,
01124 float m20,float m21,float m22)
01125 {
01126 return m00*m11*m22 + m01*m12*m20 + m02*m10*m21 - m20*m11*m02 - m10*m01*m22 - m00*m21*m12;
01127 }
01128
01129
01130 static inline unsigned int ind(unsigned int i, unsigned int j)
01131 {
01132 return (i*4+j);
01133 }
01134
01135
01153 void Camera::setFromModelViewMatrix(const GLdouble* const modelViewMatrix)
01154 {
01155
01156 double upperLeft[3][3];
01157 for (int i=0; i<3; ++i)
01158 for (int j=0; j<3; ++j)
01159 upperLeft[i][j] = modelViewMatrix[i*4+j];
01160
01161
01162 Quaternion q;
01163 q.setFromRotationMatrix(upperLeft);
01164
01165 setOrientation(q);
01166 setPosition(-q.rotate(Vec(modelViewMatrix[12], modelViewMatrix[13], modelViewMatrix[14])));
01167 }
01168
01191 void Camera::setFromProjectionMatrix(const float matrix[12])
01192 {
01193
01194
01195 Vec line_0(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)]);
01196 Vec line_1(matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)]);
01197 Vec line_2(matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]);
01198
01199 line_0.normalize();
01200 line_1.normalize();
01201 line_2.normalize();
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212 const Vec cam_pos = Vec(det(matrix[ind(0,1)],matrix[ind(0,2)],matrix[ind(0,3)],
01213 matrix[ind(1,1)],matrix[ind(1,2)],matrix[ind(1,3)],
01214 matrix[ind(2,1)],matrix[ind(2,2)],matrix[ind(2,3)]),
01215
01216 -det(matrix[ind(0,0)],matrix[ind(0,2)],matrix[ind(0,3)],
01217 matrix[ind(1,0)],matrix[ind(1,2)],matrix[ind(1,3)],
01218 matrix[ind(2,0)],matrix[ind(2,2)],matrix[ind(2,3)]),
01219
01220 det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,3)],
01221 matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,3)],
01222 matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,3)])) /
01223
01224 (-det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)],
01225 matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)],
01226 matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]));
01227
01228
01229
01230
01231 Vec column_2 = -line_2;
01232
01233
01234 Vec column_0 = ((column_2^line_0)^column_2);
01235 column_0.normalize();
01236
01237
01238
01239 Vec column_1 = -((column_2^line_1)^column_2);
01240 column_1.normalize();
01241
01242 double rot[3][3];
01243 rot[0][0] = column_0[0];
01244 rot[1][0] = column_0[1];
01245 rot[2][0] = column_0[2];
01246
01247 rot[0][1] = column_1[0];
01248 rot[1][1] = column_1[1];
01249 rot[2][1] = column_1[2];
01250
01251 rot[0][2] = column_2[0];
01252 rot[1][2] = column_2[1];
01253 rot[2][2] = column_2[2];
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263 Vec dummy = line_1^column_0;
01264 dummy.normalize();
01265 float fov = acos(column_2*dummy) * 2.0;
01266
01267
01268 Quaternion q;
01269 q.setFromRotationMatrix(rot);
01270 setOrientation(q);
01271 setPosition(cam_pos);
01272 setFieldOfView(fov);
01273 }
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01339
01341 void Camera::getCameraCoordinatesOf(const float src[3], float res[3]) const
01342 {
01343 Vec r = cameraCoordinatesOf(Vec(src));
01344 for (int i=0; i<3; ++i)
01345 res[i] = r[i];
01346 }
01347
01349 void Camera::getWorldCoordinatesOf(const float src[3], float res[3]) const
01350 {
01351 Vec r = worldCoordinatesOf(Vec(src));
01352 for (int i=0; i<3; ++i)
01353 res[i] = r[i];
01354 }
01355
01361 void Camera::getViewport(GLint viewport[4]) const
01362 {
01363 viewport[0] = 0;
01364 viewport[1] = screenHeight();
01365 viewport[2] = screenWidth();
01366 viewport[3] = -screenHeight();
01367 }
01368
01443 Vec Camera::projectedCoordinatesOf(const Vec& src, const Frame* frame) const
01444 {
01445 GLdouble x,y,z;
01446 static GLint viewport[4];
01447 getViewport(viewport);
01448
01449 if (frame)
01450 {
01451 const Vec tmp = frame->inverseCoordinatesOf(src);
01452 gluProject(tmp.x,tmp.y,tmp.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
01453 }
01454 else
01455 gluProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
01456
01457 return Vec(x,y,z);
01458 }
01459
01485 Vec Camera::unprojectedCoordinatesOf(const Vec& src, const Frame* frame) const
01486 {
01487 GLdouble x,y,z;
01488 static GLint viewport[4];
01489 getViewport(viewport);
01490 gluUnProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
01491 if (frame)
01492 return frame->coordinatesOf(Vec(x,y,z));
01493 else
01494 return Vec(x,y,z);
01495 }
01496
01498 void Camera::getProjectedCoordinatesOf(const float src[3], float res[3], const Frame* frame) const
01499 {
01500 Vec r = projectedCoordinatesOf(Vec(src), frame);
01501 for (int i=0; i<3; ++i)
01502 res[i] = r[i];
01503 }
01504
01506 void Camera::getUnprojectedCoordinatesOf(const float src[3], float res[3], const Frame* frame) const
01507 {
01508 Vec r = unprojectedCoordinatesOf(Vec(src), frame);
01509 for (int i=0; i<3; ++i)
01510 res[i] = r[i];
01511 }
01512
01514
01518 KeyFrameInterpolator* Camera::keyFrameInterpolator(int i) const
01519 {
01520 if (kfi_.contains(i))
01521 return kfi_[i];
01522 else
01523 return NULL;
01524 }
01525
01544 void Camera::setKeyFrameInterpolator(int i, KeyFrameInterpolator* const kfi)
01545 {
01546 if (kfi)
01547 kfi_[i] = kfi;
01548 else
01549 kfi_.remove(i);
01550 }
01551
01564 void Camera::addKeyFrameToPath(int i)
01565 {
01566 if (!kfi_.contains(i))
01567 setKeyFrameInterpolator(i, new KeyFrameInterpolator(frame()));
01568
01569 kfi_[i]->addKeyFrame(*(frame()));
01570 }
01571
01580 void Camera::playPath(int i)
01581 {
01582 if (kfi_.contains(i)) {
01583 if (kfi_[i]->interpolationIsStarted())
01584 kfi_[i]->stopInterpolation();
01585 else
01586 kfi_[i]->startInterpolation();
01587 }
01588 }
01589
01595 void Camera::resetPath(int i)
01596 {
01597 if (kfi_.contains(i)) {
01598 if ((kfi_[i]->interpolationIsStarted()))
01599 kfi_[i]->stopInterpolation();
01600 else
01601 {
01602 kfi_[i]->resetInterpolation();
01603 kfi_[i]->interpolateAtTime(kfi_[i]->interpolationTime());
01604 }
01605 }
01606 }
01607
01616 void Camera::deletePath(int i)
01617 {
01618 if (kfi_.contains(i))
01619 {
01620 kfi_[i]->stopInterpolation();
01621 delete kfi_[i];
01622 kfi_.remove(i);
01623 }
01624 }
01625
01632 void Camera::drawAllPaths()
01633 {
01634 for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it)
01635 #if QT_VERSION >= 0x040000
01636 (it.value())->drawPath(3, 5, sceneRadius());
01637 #else
01638 (it.data())->drawPath(3, 5, sceneRadius());
01639 #endif
01640 }
01641
01643
01669 QDomElement Camera::domElement(const QString& name, QDomDocument& document) const
01670 {
01671 QDomElement de = document.createElement(name);
01672 QDomElement paramNode = document.createElement("Parameters");
01673 paramNode.setAttribute("fieldOfView", QString::number(fieldOfView()));
01674 paramNode.setAttribute("zNearCoefficient", QString::number(zNearCoefficient()));
01675 paramNode.setAttribute("zClippingCoefficient", QString::number(zClippingCoefficient()));
01676 paramNode.setAttribute("orthoCoef", QString::number(orthoCoef_));
01677 paramNode.setAttribute("sceneRadius", QString::number(sceneRadius()));
01678 paramNode.appendChild(sceneCenter().domElement("SceneCenter", document));
01679
01680 switch (type())
01681 {
01682 case Camera::PERSPECTIVE : paramNode.setAttribute("Type", "PERSPECTIVE"); break;
01683 case Camera::ORTHOGRAPHIC : paramNode.setAttribute("Type", "ORTHOGRAPHIC"); break;
01684 }
01685 de.appendChild(paramNode);
01686
01687 QDomElement stereoNode = document.createElement("Stereo");
01688 stereoNode.setAttribute("IODist", QString::number(IODistance()));
01689 stereoNode.setAttribute("distToScreen", QString::number(physicalDistanceToScreen()));
01690 stereoNode.setAttribute("focusDistance", QString::number(focusDistance()));
01691 stereoNode.setAttribute("physScreenWidth", QString::number(physicalScreenWidth()));
01692 de.appendChild(stereoNode);
01693
01694 de.appendChild(frame()->domElement("ManipulatedCameraFrame", document));
01695
01696
01697 for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it)
01698 {
01699 #if QT_VERSION >= 0x040000
01700 QDomElement kfNode = (it.value())->domElement("KeyFrameInterpolator", document);
01701 #else
01702 QDomElement kfNode = (it.data())->domElement("KeyFrameInterpolator", document);
01703 #endif
01704 kfNode.setAttribute("index", QString::number(it.key()));
01705 de.appendChild(kfNode);
01706 }
01707
01708 return de;
01709 }
01710
01732 void Camera::initFromDOMElement(const QDomElement& element)
01733 {
01734 QDomElement child=element.firstChild().toElement();
01735
01736 #if QT_VERSION >= 0x040000
01737 QMutableMapIterator<int, KeyFrameInterpolator*> it(kfi_);
01738 while (it.hasNext()) {
01739 it.next();
01740 #else
01741 for (QMap<int, KeyFrameInterpolator*>::Iterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it) {
01742 #endif
01743 deletePath(it.key());
01744 }
01745
01746 while (!child.isNull())
01747 {
01748 if (child.tagName() == "Parameters")
01749 {
01750
01751 setFieldOfView(DomUtils::floatFromDom(child, "fieldOfView", M_PI/4.0f));
01752 setZNearCoefficient(DomUtils::floatFromDom(child, "zNearCoefficient", 0.005f));
01753 setZClippingCoefficient(DomUtils::floatFromDom(child, "zClippingCoefficient", sqrt(3.0)));
01754 orthoCoef_ = DomUtils::floatFromDom(child, "orthoCoef", tan(fieldOfView()/2.0));
01755 setSceneRadius(DomUtils::floatFromDom(child, "sceneRadius", sceneRadius()));
01756
01757 setType(PERSPECTIVE);
01758 QString type = child.attribute("Type", "PERSPECTIVE");
01759 if (type == "PERSPECTIVE") setType(Camera::PERSPECTIVE);
01760 if (type == "ORTHOGRAPHIC") setType(Camera::ORTHOGRAPHIC);
01761
01762 QDomElement child2=child.firstChild().toElement();
01763 while (!child2.isNull())
01764 {
01765
01766
01767 if (child2.tagName() == "SceneCenter")
01768 setSceneCenter(Vec(child2));
01769
01770 child2 = child2.nextSibling().toElement();
01771 }
01772 }
01773
01774 if (child.tagName() == "ManipulatedCameraFrame")
01775 frame()->initFromDOMElement(child);
01776
01777 if (child.tagName() == "Stereo")
01778 {
01779 setIODistance(DomUtils::floatFromDom(child, "IODist", 0.062f));
01780 setPhysicalDistanceToScreen(DomUtils::floatFromDom(child, "distToScreen", 0.5f));
01781 setFocusDistance(DomUtils::floatFromDom(child, "focusDistance", focusDistance()));
01782 setPhysicalScreenWidth(DomUtils::floatFromDom(child, "physScreenWidth", 0.4f));
01783 }
01784
01785 if (child.tagName() == "KeyFrameInterpolator")
01786 {
01787 int index = DomUtils::intFromDom(child, "index", 0);
01788 setKeyFrameInterpolator(index, new KeyFrameInterpolator(frame()));
01789 if (keyFrameInterpolator(index))
01790 keyFrameInterpolator(index)->initFromDOMElement(child);
01791 }
01792
01793 child = child.nextSibling().toElement();
01794 }
01795 }
01796
01808 void Camera::convertClickToLine(const QPoint& pixel, Vec& orig, Vec& dir) const
01809 {
01810 switch (type())
01811 {
01812 case Camera::PERSPECTIVE:
01813 orig = position();
01814 dir = Vec( ((2.0 * pixel.x() / screenWidth()) - 1.0) * tan(fieldOfView()/2.0) * aspectRatio(),
01815 ((2.0 * (screenHeight()-pixel.y()) / screenHeight()) - 1.0) * tan(fieldOfView()/2.0),
01816 -1.0 );
01817 dir = worldCoordinatesOf(dir) - orig;
01818 dir.normalize();
01819 break;
01820
01821 case Camera::ORTHOGRAPHIC:
01822 {
01823 GLdouble w,h;
01824 getOrthoWidthHeight(w,h);
01825 orig = Vec((2.0 * pixel.x() / screenWidth() - 1.0)*w, -(2.0 * pixel.y() / screenHeight() - 1.0)*h, 0.0);
01826 orig = worldCoordinatesOf(orig);
01827 dir = viewDirection();
01828 break;
01829 }
01830 }
01831 }
01832
01833 #ifndef DOXYGEN
01834
01835 void Camera::drawCamera(float, float, float)
01836 {
01837 qWarning("drawCamera is deprecated. Use Camera::draw() instead.");
01838 }
01839 #endif
01840
01861 void Camera::draw(bool drawFarPlane, float scale) const
01862 {
01863 glPushMatrix();
01864 glMultMatrixd(frame()->worldMatrix());
01865
01866
01867 Vec points[2];
01868
01869 points[0].z = scale * zNear();
01870 points[1].z = scale * zFar();
01871
01872 switch (type())
01873 {
01874 case Camera::PERSPECTIVE:
01875 {
01876 points[0].y = points[0].z * tan(fieldOfView()/2.0);
01877 points[0].x = points[0].y * aspectRatio();
01878
01879 const float ratio = points[1].z / points[0].z;
01880
01881 points[1].y = ratio * points[0].y;
01882 points[1].x = ratio * points[0].x;
01883 break;
01884 }
01885 case Camera::ORTHOGRAPHIC:
01886 {
01887 GLdouble hw, hh;
01888 getOrthoWidthHeight(hw, hh);
01889 points[0].x = points[1].x = scale * float(hw);
01890 points[0].y = points[1].y = scale * float(hh);
01891 break;
01892 }
01893 }
01894
01895 const int farIndex = drawFarPlane?1:0;
01896
01897
01898 glBegin(GL_QUADS);
01899 for (int i=farIndex; i>=0; --i)
01900 {
01901 glNormal3f(0.0, 0.0, (i==0)?1.0:-1.0);
01902 glVertex3f( points[i].x, points[i].y, -points[i].z);
01903 glVertex3f(-points[i].x, points[i].y, -points[i].z);
01904 glVertex3f(-points[i].x, -points[i].y, -points[i].z);
01905 glVertex3f( points[i].x, -points[i].y, -points[i].z);
01906 }
01907 glEnd();
01908
01909
01910 const float arrowHeight = 1.5f * points[0].y;
01911 const float baseHeight = 1.2f * points[0].y;
01912 const float arrowHalfWidth = 0.5f * points[0].x;
01913 const float baseHalfWidth = 0.3f * points[0].x;
01914
01915 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
01916
01917 glBegin(GL_QUADS);
01918 glVertex3f(-baseHalfWidth, points[0].y, -points[0].z);
01919 glVertex3f( baseHalfWidth, points[0].y, -points[0].z);
01920 glVertex3f( baseHalfWidth, baseHeight, -points[0].z);
01921 glVertex3f(-baseHalfWidth, baseHeight, -points[0].z);
01922 glEnd();
01923
01924
01925 glBegin(GL_TRIANGLES);
01926 glVertex3f( 0.0f, arrowHeight, -points[0].z);
01927 glVertex3f(-arrowHalfWidth, baseHeight, -points[0].z);
01928 glVertex3f( arrowHalfWidth, baseHeight, -points[0].z);
01929 glEnd();
01930
01931
01932 switch (type())
01933 {
01934 case Camera::PERSPECTIVE :
01935 glBegin(GL_LINES);
01936 glVertex3f(0.0f, 0.0f, 0.0f);
01937 glVertex3f( points[farIndex].x, points[farIndex].y, -points[farIndex].z);
01938 glVertex3f(0.0f, 0.0f, 0.0f);
01939 glVertex3f(-points[farIndex].x, points[farIndex].y, -points[farIndex].z);
01940 glVertex3f(0.0f, 0.0f, 0.0f);
01941 glVertex3f(-points[farIndex].x, -points[farIndex].y, -points[farIndex].z);
01942 glVertex3f(0.0f, 0.0f, 0.0f);
01943 glVertex3f( points[farIndex].x, -points[farIndex].y, -points[farIndex].z);
01944 glEnd();
01945 break;
01946 case Camera::ORTHOGRAPHIC :
01947 if (drawFarPlane)
01948 {
01949 glBegin(GL_LINES);
01950 glVertex3f( points[0].x, points[0].y, -points[0].z);
01951 glVertex3f( points[1].x, points[1].y, -points[1].z);
01952 glVertex3f(-points[0].x, points[0].y, -points[0].z);
01953 glVertex3f(-points[1].x, points[1].y, -points[1].z);
01954 glVertex3f(-points[0].x, -points[0].y, -points[0].z);
01955 glVertex3f(-points[1].x, -points[1].y, -points[1].z);
01956 glVertex3f( points[0].x, -points[0].y, -points[0].z);
01957 glVertex3f( points[1].x, -points[1].y, -points[1].z);
01958 glEnd();
01959 }
01960 }
01961
01962 glPopMatrix();
01963 }
01964
01965
01989 void Camera::getFrustumPlanesCoefficients(GLdouble coef[6][4]) const
01990 {
01991
01992 const Vec pos = position();
01993 const Vec viewDir = viewDirection();
01994 const Vec up = upVector();
01995 const Vec right = rightVector();
01996 const float posViewDir = pos * viewDir;
01997
01998 static Vec normal[6];
01999 static GLdouble dist[6];
02000
02001 switch (type())
02002 {
02003 case Camera::PERSPECTIVE :
02004 {
02005 const float hhfov = horizontalFieldOfView() / 2.0;
02006 const float chhfov = cos(hhfov);
02007 const float shhfov = sin(hhfov);
02008 normal[0] = - shhfov * viewDir;
02009 normal[1] = normal[0] + chhfov * right;
02010 normal[0] = normal[0] - chhfov * right;
02011
02012 normal[2] = -viewDir;
02013 normal[3] = viewDir;
02014
02015 const float hfov = fieldOfView() / 2.0;
02016 const float chfov = cos(hfov);
02017 const float shfov = sin(hfov);
02018 normal[4] = - shfov * viewDir;
02019 normal[5] = normal[4] - chfov * up;
02020 normal[4] = normal[4] + chfov * up;
02021
02022 for (int i=0; i<2; ++i)
02023 dist[i] = pos * normal[i];
02024 for (int j=4; j<6; ++j)
02025 dist[j] = pos * normal[j];
02026
02027
02028
02029
02030
02031
02032
02033 const float posRightCosHH = chhfov * pos * right;
02034 dist[0] = -shhfov * posViewDir;
02035 dist[1] = dist[0] + posRightCosHH;
02036 dist[0] = dist[0] - posRightCosHH;
02037 const float posUpCosH = chfov * pos * up;
02038 dist[4] = - shfov * posViewDir;
02039 dist[5] = dist[4] - posUpCosH;
02040 dist[4] = dist[4] + posUpCosH;
02041
02042 break;
02043 }
02044 case Camera::ORTHOGRAPHIC :
02045 normal[0] = -right;
02046 normal[1] = right;
02047 normal[4] = up;
02048 normal[5] = -up;
02049
02050 GLdouble hw, hh;
02051 getOrthoWidthHeight(hw, hh);
02052 dist[0] = (pos - hw * right) * normal[0];
02053 dist[1] = (pos + hw * right) * normal[1];
02054 dist[4] = (pos + hh * up) * normal[4];
02055 dist[5] = (pos - hh * up) * normal[5];
02056 break;
02057 }
02058
02059
02060 normal[2] = -viewDir;
02061 normal[3] = viewDir;
02062 dist[2] = -posViewDir - zNear();
02063 dist[3] = posViewDir + zFar();
02064
02065 for (int i=0; i<6; ++i)
02066 {
02067 coef[i][0] = GLdouble(normal[i].x);
02068 coef[i][1] = GLdouble(normal[i].y);
02069 coef[i][2] = GLdouble(normal[i].z);
02070 coef[i][3] = dist[i];
02071 }
02072 }