From 9b6f3582e30fcb260344e639d7f1ae5eedb2c189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 29 Dec 2010 18:39:07 +0100 Subject: [PATCH] Orthographic and perspective camera projections. --- src/Camera.cpp | 35 +++++++++++++++++++++++++++ src/Camera.h | 21 ++++++++++++++++ src/Test/CMakeLists.txt | 1 + src/Test/CameraTest.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ src/Test/CameraTest.h | 32 +++++++++++++++++++++++++ 5 files changed, 142 insertions(+) create mode 100644 src/Test/CameraTest.cpp create mode 100644 src/Test/CameraTest.h diff --git a/src/Camera.cpp b/src/Camera.cpp index 45e12d31e..72f2de11b 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -18,6 +18,41 @@ namespace Magnum { Camera::Camera(AbstractObject* parent): AbstractObject(parent), viewportWidth(0), viewportHeight(0), _aspectRatioPolicy(Extend) { + setOrthographic(2, 1, 1000); +} + +void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) { + /* Scale the volume down so it fits in (-1, 1) in all directions */ + GLfloat xyScale = 2/size; + GLfloat zScale = 2/(far-near); + rawProjectionMatrix = Matrix4::scaling(xyScale, xyScale, -zScale); + + /* Move the volume on z into (-1, 1) range */ + rawProjectionMatrix = Matrix4::translation(0, 0, -1-near*zScale)*rawProjectionMatrix; + + fixAspectRatio(); +} + +void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) { + /* First move the volume on z in (-1, 1) range */ + rawProjectionMatrix = Matrix4::translation(0, 0, 2*far*near/(far+near)); + + /* Then apply magic perspective matrix (with reversed Z) */ + static GLfloat a[] = { 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, -1, -1, + 0, 0, 0, 0 }; + rawProjectionMatrix = Matrix4(a)*rawProjectionMatrix; + + /* Then scale the volume down so it fits in (-1, 1) in all directions */ + GLfloat xyScale = 1/tan(fov/2); + GLfloat zScale = 1+2*near/(far-near); + rawProjectionMatrix = Matrix4::scaling(xyScale, xyScale, zScale)*rawProjectionMatrix; + + /* And... another magic */ + rawProjectionMatrix.set(3, 3, 0); + + fixAspectRatio(); } Matrix4 Camera::cameraMatrix() const { diff --git a/src/Camera.h b/src/Camera.h index 417bb5fd9..085699ee1 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -40,6 +40,8 @@ class Camera: public AbstractObject { /** * @brief Constructor * @param parent Parent object + * + * Calls setOrthographic(2, 1, 1000). */ Camera(AbstractObject* parent = 0); @@ -49,6 +51,25 @@ class Camera: public AbstractObject { /** @brief Set aspect ratio policy */ void setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; } + /** + * @brief Set orthographic projection + * @param size Size of (square) view + * @param near Near clipping plane + * @param far Far clipping plane + * + * The volume of given size will be scaled down to range (-1, 1) on all + * directions. + */ + void setOrthographic(GLfloat size, GLfloat near, GLfloat far); + + /** + * @brief Set perspective projection + * @param fov Field of view angle + * @param near Near clipping plane + * @param far Far clipping plane + */ + void setPerspective(GLfloat fov, GLfloat near, GLfloat far); + /** * @brief Camera matrix * diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 17b1d14fa..4870d1582 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1 +1,2 @@ magnum_add_test(AbstractObjectTest AbstractObjectTest.h AbstractObjectTest.cpp Magnum) +magnum_add_test(CameraTest CameraTest.h CameraTest.cpp Magnum) diff --git a/src/Test/CameraTest.cpp b/src/Test/CameraTest.cpp new file mode 100644 index 000000000..40bb77e4e --- /dev/null +++ b/src/Test/CameraTest.cpp @@ -0,0 +1,53 @@ +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "CameraTest.h" +#include "Camera.h" + +#include + +QTEST_APPLESS_MAIN(Magnum::Test::CameraTest) + +namespace Magnum { namespace Test { + +void CameraTest::orthographic() { + Camera camera; + camera.setOrthographic(5, 1, 9); + + GLfloat a[] = { + 0.4f, 0, 0, 0, + 0, 0.4f, 0, 0, + 0, 0, -0.25f, 0, + 0, 0, -1.25f, 1 + }; + + QVERIFY(camera.projectionMatrix() == a); +} + +void CameraTest::perspective() { + Camera camera; + camera.setPerspective(27*PI/180, 32.0f, 100); + + GLfloat a[] = { + 4.1652994f, 0, 0, 0, + 0, 4.1652994f, 0, 0, + 0, 0, -1.9411764f, -1, + 0, 0, -94.1176452f, 0 + }; + + QVERIFY(camera.projectionMatrix() == Matrix4(a)); +} + +}} diff --git a/src/Test/CameraTest.h b/src/Test/CameraTest.h new file mode 100644 index 000000000..d3ce17513 --- /dev/null +++ b/src/Test/CameraTest.h @@ -0,0 +1,32 @@ +#ifndef Magnum_CameraTest_h +#define Magnum_CameraTest_h +/* + Copyright © 2010 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include + +namespace Magnum { namespace Test { + +class CameraTest: public QObject { + Q_OBJECT + + private slots: + void orthographic(); + void perspective(); +}; + +}} + +#endif