TGLPerspectiveCamera.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLPerspectiveCamera.cxx 33864 2010-06-14 09:47:19Z matevz $
00002 // Author:  Richard Maunder  25/05/2005
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TGLPerspectiveCamera.h"
00013 #include "TGLUtil.h"
00014 #include "TGLIncludes.h"
00015 
00016 #include "TMath.h"
00017 #include "TError.h"
00018 
00019 //////////////////////////////////////////////////////////////////////////
00020 //                                                                      //
00021 // TGLPerspectiveCamera                                                 //
00022 //                                                                      //
00023 // Perspective projection camera - with characteristic foreshortening.  //
00024 //                                                                      //
00025 // TODO: Currently constrains YOZ plane to be floor - this is never     //
00026 // 'tipped'. While useful we really need to extend so can:              //
00027 // i) Pick any one of the three natural planes of the world to be floor.//
00028 // ii) Can use a free arcball style camera with no contraint - integrate//
00029 // TArcBall.                                                            //
00030 //////////////////////////////////////////////////////////////////////////
00031 
00032 ClassImp(TGLPerspectiveCamera)
00033 
00034 Double_t TGLPerspectiveCamera::fgFOVMin = 0.01;
00035 Double_t TGLPerspectiveCamera::fgFOVDefault = 30;
00036 Double_t TGLPerspectiveCamera::fgFOVMax = 120.0;
00037 UInt_t   TGLPerspectiveCamera::fgFOVDeltaSens = 500;
00038 
00039 //______________________________________________________________________________
00040 TGLPerspectiveCamera::TGLPerspectiveCamera(const TGLVector3 & hAxes, const TGLVector3 & vAxes) :
00041    TGLCamera(hAxes, vAxes),
00042    fFOV(fgFOVDefault)
00043 {
00044    // Construct perspective camera
00045    Setup(TGLBoundingBox(TGLVertex3(-100,-100,-100), TGLVertex3(100,100,100)));
00046    fCamTrans.MoveLF(1, fDollyDefault);
00047 }
00048 
00049 //______________________________________________________________________________
00050 TGLPerspectiveCamera::~TGLPerspectiveCamera()
00051 {
00052    // Destroy perspective camera
00053 }
00054 
00055 //______________________________________________________________________________
00056 void TGLPerspectiveCamera::Setup(const TGLBoundingBox & box, Bool_t reset)
00057 {
00058    // Setup camera limits suitible to view the world volume defined by 'box'
00059    // and call Reset() to initialise camera.
00060 
00061    if (fExternalCenter == kFALSE)
00062    {
00063       if (fFixDefCenter)
00064       {
00065          SetCenterVec(fFDCenter.X(), fFDCenter.Y(), fFDCenter.Z());
00066       }
00067       else
00068       {
00069          TGLVertex3 center = box.Center();
00070          SetCenterVec(center.X(), center.Y(), center.Z());
00071       }
00072    }
00073 
00074    // At default FOV, the dolly should be set so as to encapsulate the scene.
00075    TGLVector3 extents = box.Extents();
00076    Int_t sortInd[3];
00077    TMath::Sort(3, extents.CArr(), sortInd);
00078    Double_t size = TMath::Hypot(extents[sortInd[0]], extents[sortInd[1]]);
00079    Double_t fov  = TMath::Min(fgFOVDefault, fgFOVDefault*fViewport.Aspect());
00080 
00081    fDollyDefault  = size / (2.0*TMath::Tan(fov*TMath::Pi()/360));
00082    fDollyDistance = 0.002 * fDollyDefault;
00083 
00084    if (reset)
00085    {
00086       Reset();
00087    }
00088 }
00089 
00090 //______________________________________________________________________________
00091 void TGLPerspectiveCamera::Reset()
00092 {
00093    // Reset the camera to defaults - reframe the world volume established in Setup()
00094    // in default state. Note: limits defined in Setup() are not adjusted.
00095 
00096    fFOV = fgFOVDefault;
00097 
00098    fCamTrans.SetIdentity();
00099    fCamTrans.MoveLF(1, fDollyDefault);
00100 
00101    IncTimeStamp();
00102 }
00103 
00104 //______________________________________________________________________________
00105 Bool_t TGLPerspectiveCamera::Zoom(Int_t delta, Bool_t mod1, Bool_t mod2)
00106 {
00107    // Zoom the camera - 'adjust lens focal length, retaining camera position'.
00108    // Arguments are:
00109    //
00110    // 'delta' - mouse viewport delta (pixels) - +ive zoom in, -ive zoom out
00111    // 'mod1' / 'mod2' - sensitivity modifiers - see TGLCamera::AdjustAndClampVal()
00112    //
00113    // Returns kTRUE is redraw required (camera change), kFALSE otherwise.
00114 
00115    // TODO: Bring all mouse handling into camera classes - would simplify interface and
00116    // remove these non-generic cases.
00117    if (AdjustAndClampVal(fFOV, fgFOVMin, fgFOVMax, delta, fgFOVDeltaSens, mod1, mod2)) {
00118       IncTimeStamp();
00119       return kTRUE;
00120    } else {
00121       return kFALSE;
00122    }
00123 }
00124 
00125 //______________________________________________________________________________
00126 Bool_t TGLPerspectiveCamera::Truck(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
00127 {
00128    // Truck the camera - 'move camera parallel to film plane'.
00129    // Returns kTRUE is redraw required (camera change), kFALSE otherwise.
00130 
00131    Double_t lenMidClip = 0.5 * (fFarClip + fNearClip) * TMath::Tan(0.5*fFOV*TMath::DegToRad());
00132 
00133    Double_t xstep = xDelta * lenMidClip / fViewport.Height();
00134    Double_t ystep = yDelta * lenMidClip / fViewport.Height();
00135 
00136    xstep = AdjustDelta(xstep, 1.0, mod1, mod2);
00137    ystep = AdjustDelta(ystep, 1.0, mod1, mod2);
00138 
00139    return Truck(-xstep, -ystep);
00140 }
00141 
00142 //______________________________________________________________________________
00143 void TGLPerspectiveCamera::Apply(const TGLBoundingBox & sceneBox,
00144                                  const TGLRect        * pickRect) const
00145 {
00146    // Apply the camera to the current GL context, setting the viewport, projection
00147    // and modelview matricies. After this verticies etc can be directly entered
00148    // in the world frame. This also updates the cached frustum values, enabling
00149    // all the projection, overlap tests etc defined in TGLCamera to be used.
00150    //
00151    // Arguments are:
00152    // 'box' - view volume box - used to adjust near/far clipping
00153    // 'pickRect' - optional picking rect. If non-null, restrict drawing to this
00154    // viewport rect.
00155 
00156    // TODO: If we retained the box from Setup first argument could be dropped?
00157 
00158    // MT This whole thing is convoluted. We can calculate camera postion
00159    // and look-at direction without calling unproject and seeking clipping
00160    // plane intersection.
00161    // Besides, this would give as a proper control over camera transforamtion
00162    // matrix.
00163    //
00164    // Much better since Oct 2007, the clipping planes stuff still
00165    // needs to be cleaned.
00166 
00167    glViewport(fViewport.X(), fViewport.Y(), fViewport.Width(), fViewport.Height());
00168 
00169    if(fViewport.Width() == 0 || fViewport.Height() == 0)
00170    {
00171       glMatrixMode(GL_PROJECTION);
00172       glLoadIdentity();
00173       glMatrixMode(GL_MODELVIEW);
00174       glLoadIdentity();
00175       return;
00176    }
00177 
00178    glMatrixMode(GL_PROJECTION);
00179    glLoadIdentity();
00180 
00181    // To find decent near/far clip plane distances we construct the
00182    // frustum thus:
00183    // i) first setup perspective with arbitary near/far planes
00184    gluPerspective(fFOV, fViewport.Aspect(), 1.0, 1000.0);
00185    //   printf("FIRST STEP FOV %f, aspect %f, nearClip %f, farClip %f \n", fFOV, fViewport.Aspect(), 1., 1000.);
00186 
00187    // ii) setup modelview
00188    glMatrixMode(GL_MODELVIEW);
00189    glLoadIdentity();
00190    TGLMatrix  mx     = fCamBase*fCamTrans;
00191    TGLVector3 pos    = mx.GetTranslation();
00192    TGLVector3 fwd    = mx.GetBaseVec(1);
00193    TGLVector3 center = pos - fwd;
00194    TGLVector3 up     = fCamBase.GetBaseVec(3);
00195 
00196    gluLookAt(pos[0],    pos[1],    pos[2],
00197              center[0], center[1], center[2],
00198              up[0],     up[1],     up[2]);
00199 
00200    // iii) update the cached frustum planes so we can get eye point/direction
00201    Bool_t modifiedCache = kFALSE;
00202    if (fCacheDirty) {
00203       UpdateCache();
00204       modifiedCache = kTRUE;
00205    }
00206 
00207    // iv) Create a clip plane, using the eye direction as normal, passing through eye point
00208    TGLPlane clipPlane(EyeDirection(), EyePoint());
00209    fCacheDirty = modifiedCache;
00210 
00211    // v) find the near/far distance which just encapsulate the passed bounding box vertexes
00212    //    not ideal - should really find the nearest/further points on box surface
00213    //    which intersect frustum - however this much more complicated
00214    Double_t currentDist;
00215    for (UInt_t i=0; i<8; i++) {
00216       currentDist = clipPlane.DistanceTo(sceneBox[i]);
00217       if (i==0)
00218       {
00219          fNearClip = currentDist;
00220          fFarClip  = fNearClip;
00221       }
00222       if (currentDist < fNearClip)
00223          fNearClip = currentDist;
00224       if (currentDist > fFarClip)
00225          fFarClip = currentDist;
00226    }
00227    // Add 1% each way to avoid any rounding conflicts with drawn objects
00228    fNearClip *= 0.49; // 0.99; TODO Look at - avoid removing clipping + manip objs
00229    fFarClip  *= 2.01; // 1.01;
00230    if (fFarClip < 2.0)
00231       fFarClip = 2.0;
00232    if (fNearClip < fFarClip/1000.0)
00233       fNearClip = fFarClip/1000.0;
00234 
00235    glMatrixMode(GL_PROJECTION);
00236    glLoadIdentity();
00237 
00238    // vi) Load up any picking rect and reset the perspective using the
00239    // correct near/far clips distances
00240    if (pickRect)
00241    {
00242       TGLRect rect(*pickRect);
00243       WindowToViewport(rect);
00244       gluPickMatrix(rect.X(), rect.Y(), rect.Width(), rect.Height(),
00245                     (Int_t*) fViewport.CArr());
00246       gluPerspective(fFOV, fViewport.Aspect(), fNearClip, fFarClip);
00247    }
00248    else
00249    {
00250       gluPerspective(fFOV, fViewport.Aspect(), fNearClip, fFarClip);
00251       glGetDoublev(GL_PROJECTION_MATRIX, fLastNoPickProjM.Arr());
00252    }
00253 
00254    glMatrixMode(GL_MODELVIEW);
00255 
00256    if (fCacheDirty) UpdateCache();
00257 }
00258 
00259 //______________________________________________________________________________
00260 void TGLPerspectiveCamera::Configure(Double_t fov, Double_t dolly, Double_t center[3],
00261                                      Double_t hRotate, Double_t vRotate)
00262 {
00263    // Configure the camera state.
00264    //   fov     - set directly field-of-view in degrees (default = 30);
00265    //   dolly   - additional move along the camera forward direction;
00266    //   center  - new camera center (can be 0 for no change);
00267    //   hRotate - additional "up/down" rotation in radians;
00268    //   vRotate - additional "left/right" rotation in radians.
00269 
00270    fFOV = fov;
00271 
00272    // Don't generally constrain external configuration
00273    // However exceeding the vRotate limits or silly FOV values will
00274    // cause very weird behaviour or projections so fix these
00275 
00276    if (fFOV > 170.0) {
00277       fFOV = 170.0;
00278    } else if (fFOV < 0.1) {
00279       fFOV = 0.1;
00280    }
00281 
00282    if (center)
00283       SetCenterVec(center[0], center[1], center[2]);
00284 
00285    fCamTrans.MoveLF(1, dolly);
00286    RotateRad(hRotate, vRotate);
00287 
00288    IncTimeStamp();
00289 }

Generated on Tue Jul 5 14:18:08 2011 for ROOT_528-00b_version by  doxygen 1.5.1