Home Download Gallery Documentation 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 `pivotPoint()`. 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 qreal zNear() const;
      virtual qreal 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"

    #include <QWheelEvent>

    using namespace qglviewer;

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

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

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

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

    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:
    Q_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 "cameraViewer.h"
    #include "standardCamera.h"
    #include "viewer.h"

    #include <QApplication>
    #include <QGLViewer/manipulatedCameraFrame.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()));

      viewer.setWindowTitle("standardCamera");
      cviewer.setWindowTitle("Camera viewer");

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

      return application.exec();
    }

## viewer.cpp

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

    #include <QKeyEvent>

    #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
    #define MidButton MiddleButton
    #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::ShiftModifier, 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);
      Q_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()) &&
          (e->modifiers() & Qt::ShiftModifier)) {
    #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        ((StandardCamera *)camera())->changeOrthoFrustumSize(e->delta());
    #else
        ((StandardCamera *)camera())->changeOrthoFrustumSize(e->angleDelta().y());
    #endif
        Q_EMIT cameraChanged();
        update();
      } 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>pivotPoint()</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.