Home Documentation Download Examples Developer

# The standardCamera example

A 'standard' Camera with fixed near and far planes.

A new `StandardCamera` class is derived from `Camera`. Its near and far planes distances are set to fixed values (instead of being fit to scene dimensions as is done in the `QGLViewer::Camera`).

The orthographic frustum dimensions are fixed instead of depending on the distance to the `revolveAroundPoint()`. Since this may be needed for some applications, you may want to use this `standardCamera` class in your code.

## standardCamera.h

    #include <QGLViewer/camera.h>

    class StandardCamera : public qglviewer::Camera
    {
    public :
      StandardCamera();

      virtual float zNear() const;
      virtual float zFar() const;

      void toggleMode() { standard = !standard; }
      bool isStandard() { return standard; }

      void changeOrthoFrustumSize(int delta);
      virtual void getOrthoWidthHeight(GLdouble &halfWidth, GLdouble &halfHeight) const;

    private :
      bool standard;
      float orthoSize;
    };

## standardCamera.cpp

    #include "standardCamera.h"

    #if QT_VERSION >= 0x040000
    # include <QWheelEvent>
    #endif

    using namespace qglviewer;

    StandardCamera::StandardCamera()
    {
      standard = true;
      orthoSize = 1.0;
    }

    float StandardCamera::zNear() const
    {
      if (standard)
        return 0.001f;
      else
        return Camera::zNear();
    }

    float StandardCamera::zFar() const
    {
      if (standard)
        return 1000.0;
      else
        return Camera::zFar();
    }

    void StandardCamera::changeOrthoFrustumSize(int delta)
    {
      if (delta > 0)
        orthoSize *= 1.1f;
      else
        orthoSize /= 1.1f;
    }

    void StandardCamera::getOrthoWidthHeight(GLdouble &halfWidth, GLdouble &halfHeight) const
    {
      if (standard)
      {
        halfHeight = orthoSize;
        halfWidth = aspectRatio() * orthoSize;
      }
      else
        Camera::getOrthoWidthHeight(halfWidth, halfHeight);
    }

## cameraViewer.h

    #include <QGLViewer/qglviewer.h>

    class CameraViewer : public QGLViewer
    {
    public :
      CameraViewer(qglviewer::Camera* camera);

    protected :
      virtual void draw();
      virtual void init();

    private :
      qglviewer::Camera* c;
    };

## viewer.h

    #include <QGLViewer/qglviewer.h>

    class StandardCamera;

    class Viewer : public QGLViewer
    {
    Q_OBJECT

    public :
      Viewer(StandardCamera* camera);

    public :
     signals :
      void cameraChanged();

    protected :
      virtual void draw();
      virtual void init();
      virtual QString helpString() const;
      virtual void keyPressEvent(QKeyEvent *e);
      virtual void 	wheelEvent (QWheelEvent *e);

    private :
      void showMessage();
    };

## cameraViewer.cpp

    #include "cameraViewer.h"

    using namespace qglviewer;

    CameraViewer::CameraViewer(Camera* camera) : c(camera) {};

    void CameraViewer::draw()
    {
      // Exactly the same draw than for 'Viewer'. The two viewers could also share a 'Scene' instance.
      const float nbSteps = 200.0;

      glBegin(GL_QUAD_STRIP);
      for (int i=0; i<nbSteps; ++i)
        {
          const float ratio = i/nbSteps;
          const float angle = 21.0*ratio;
          const float c = cos(angle);
          const float s = sin(angle);
          const float r1 = 1.0 - 0.8f*ratio;
          const float r2 = 0.8f - 0.8f*ratio;
          const float alt = ratio - 0.5f;
          const float nor = 0.5f;
          const float up = sqrt(1.0-nor*nor);
          glColor3f(1.0-ratio, 0.2f , ratio);
          glNormal3f(nor*c, up, nor*s);
          glVertex3f(r1*c, alt, r1*s);
          glVertex3f(r2*c, alt+0.05f, r2*s);
        }
      glEnd();

      // Draws the other viewer's camera
      glDisable(GL_LIGHTING);
      glLineWidth(4.0);
      glColor4f(1.0, 1.0, 1.0, 0.5);
      c->draw();
      glEnable(GL_LIGHTING);
    }

    void CameraViewer::init()
    {
      // Places the cameraViewer's camera far away in order to see the (other viewer) camera.
      if (!restoreStateFromFile())
      {
        // Make near and far planes much further from scene in order not to clip c's display.
    	camera()->setZClippingCoefficient(50.0);
        camera()->setViewDirection(qglviewer::Vec(0.0, -1.0, 0.0));
        showEntireScene();
      }

      // Enable semi-transparent culling planes
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

## main.cpp

    #include "standardCamera.h"
    #include "viewer.h"
    #include "cameraViewer.h"
    #include <qapplication.h>

    int main(int argc, char** argv)
    {
      QApplication application(argc,argv);

      // Instantiate the two viewers.
      StandardCamera* sc = new StandardCamera();
      Viewer viewer(sc);
      CameraViewer cviewer(sc);

      // Make sure every v camera movement updates the camera viewer
      QObject::connect(viewer.camera()->frame(), SIGNAL(manipulated()), &cviewer, SLOT(updateGL()));
      QObject::connect(viewer.camera()->frame(), SIGNAL(spun()), &cviewer, SLOT(updateGL()));
      // Also update on camera change (type or mode)
      QObject::connect(&viewer, SIGNAL(cameraChanged()), &cviewer, SLOT(updateGL()));

    #if QT_VERSION < 0x040000
      application.setMainWidget(&viewer);
    #else
      viewer.setWindowTitle("standardCamera");
      cviewer.setWindowTitle("Camera viewer");
    #endif

      cviewer.show();
      viewer.show();

      return application.exec();
    }

## viewer.cpp

    #include "viewer.h"
    #include "standardCamera.h"

    #if QT_VERSION >= 0x040000
    # include <QKeyEvent>
    #endif

    using namespace std;
    using namespace qglviewer;

    Viewer::Viewer(StandardCamera* nfc)
    {
      // Change the camera.
      Camera* c = camera();
      setCamera(nfc);
      delete c;
    }

    // Draws a spiral
    void Viewer::draw()
    {
      const float nbSteps = 200.0;

      glBegin(GL_QUAD_STRIP);
      for (int i=0; i<nbSteps; ++i)
        {
          const float ratio = i/nbSteps;
          const float angle = 21.0*ratio;
          const float c = cos(angle);
          const float s = sin(angle);
          const float r1 = 1.0 - 0.8f*ratio;
          const float r2 = 0.8f - 0.8f*ratio;
          const float alt = ratio - 0.5f;
          const float nor = 0.5f;
          const float up = sqrt(1.0-nor*nor);
          glColor3f(1.0-ratio, 0.2f , ratio);
          glNormal3f(nor*c, up, nor*s);
          glVertex3f(r1*c, alt, r1*s);
          glVertex3f(r2*c, alt+0.05f, r2*s);
        }
      glEnd();
    }

    void Viewer::init()
    {
      // Restore previous viewer state.
      if (!restoreStateFromFile())
      showEntireScene();

      setKeyDescription(Qt::Key_T, "Toggles camera type (perspective or orthographic)");
      setKeyDescription(Qt::Key_M, "Toggles camera mode (standard or QGLViewer)");

      setMouseBindingDescription(Qt::SHIFT + Qt::MidButton, "Change frustum size (for standard camera in orthographic mode)");

      // Display help window.
      help();
    }

    void Viewer::showMessage()
    {
      QString std = ((StandardCamera*)camera())->isStandard()?"Standard camera":"QGLViewer camera";
      QString type = camera()->type() == Camera::PERSPECTIVE?"Perspective":"Orthographic";
      displayMessage(std + " - " + type);
      emit cameraChanged();
    }

    void Viewer::keyPressEvent(QKeyEvent *e)
    {
      if (e->key() == Qt::Key_M) {
      // 'M' changes mode : standard or QGLViewer camera
        ((StandardCamera*)camera())->toggleMode();
        showMessage();
      } else
        if (e->key() == Qt::Key_T) {
        // 'T' changes the projection type : perspective or orthogonal
          if (camera()->type() == Camera::ORTHOGRAPHIC)
            camera()->setType(Camera::PERSPECTIVE);
          else
            camera()->setType(Camera::ORTHOGRAPHIC);
            showMessage();
          } else
            QGLViewer::keyPressEvent(e);
    }

    void Viewer::wheelEvent(QWheelEvent *e)
    {
      if ((camera()->type() == Camera::ORTHOGRAPHIC) && (((StandardCamera*)camera())->isStandard()) &&
    #if QT_VERSION >= 0x040000
        (e->modifiers() & Qt::ShiftModifier))
    #else
        (e->state() & Qt::ShiftButton))
    #endif
      {
        ((StandardCamera*)camera())->changeOrthoFrustumSize(e->delta());
        emit cameraChanged();
        updateGL();
      }
      else
        QGLViewer::wheelEvent(e);
    }

    QString Viewer::helpString() const
    {
      QString text("<h2>S t a n d a r d C a m e r a</h2>");
      text += "An overloaded <code>Camera</code> class is used, that reproduces the 'standard' OpenGL settings.<br><br>";

      text += "With this camera, the near and (resp. far) plane distance is set to a very small (resp. very large) value. ";
      text += "With the orthographic camera type, the frustum dimensions are fixed. Use <code>Shift</code> and the mouse wheel to change them.<br><br>";

      text += "On the other hand, the QGLViewer camera fits the near and far distances to the scene radius. ";
      text += "Fine tuning is available using <code>zClippingCoefficient()</code> and <code>zNearCoefficient()</code>. ";
      text += "However, visual results do not seem to be impacted by this zBuffer fitted range.<br><br>";
      text += "The QGLViewer camera also adapts the orthographic frustum dimensions to the distance to the <code>revolveAroundPoint()</code> to mimic a perspective camera. ";
      text += "Since this behavior may not be needed, this example shows how to override it.<br><br>";

      text += "The second viewer displays the first one's camera to show its configuration.<br><br>";

      text += "Use <b>M</b> to switch between 'standard' and QGLViewer camera behavior.<br>";
      text += "Use <b>T</b> to switch between perspective and orthographic camera type.<br><br>";

      text += "Use <b>Shift+wheel</b> to change standard camera orthographic size.";

      return text;
    }

Back to the examples main page.

Last modified on Monday, August 31, 2009.