FixedCamera.cc 2.92 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "FixedCamera.hh"

#include <glm/glm.hpp>

using namespace glow::extras;

FixedCamera::FixedCamera()
{
}

FixedCamera::FixedCamera(const glm::vec3 &_pos, const glm::mat4 &_view, const glm::mat4 &_proj, const glm::uvec2 &_viewport)
  : mPosition(_pos), mViewMatrix(_view), mViewportSize(_viewport)
{
    setProjectionMatrix(_proj);
}

void FixedCamera::setProjectionMatrix(glm::mat4 const &_val)
{
    mProjectionMatrix = _val;

    //
    // Calculate near and far plane from the matrix
    // As the matrix does not have to be a standard OpenGL
    // projection matrix, we can't derrive the values from
    // the matrix entries directly but we have to reproject
    // points from the NDC cube... ...but as some matrices
    // project to -1..1 and others to 0..1 we have to figure
    // this out first... ...keeping in mind, that some also
    // invert the range inside of the Z buffer, so Z=1 might
    // be the near plane while Z=0 is the far plane...
    // ...oh, and the far plane might be at infinity...
    //

    //
    // First step, figure out which values project to
    // -1, 0 and 1:
    //
    glm::mat4 invProj = glm::inverse(mProjectionMatrix);
    glm::vec4 tmp = invProj * glm::vec4(0.0f, 0.0f, -1.0f, 1.0f);
    float reproj_minusOne = tmp.z / tmp.w;
    tmp = invProj * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
    float reproj_Zero = tmp.z / tmp.w;
    tmp = invProj * glm::vec4(0.0f, 0.0f, 1.0f, 1.0f);
    float reproj_One = tmp.z / tmp.w;

    //
    // Next step, figure out which value is the near plane and which is the far plane.
    //
    // right handed coordinate system -> the camera was looking along the negative Z axis
    // if it was an OpenGL matrix, the projections will result in -near, -something, -far
    // if it was an OpenGL matrix with infinit far plane, the projections will result in -near, -something, -inf
    // if it was a reverse DX style matrix it will result in +near, -inf, -near

    if (reproj_minusOne > 0.0f)
    {
        // near,far mapped to 1,0 or 0,1 as -1 was mapped to a positive value which is behind the camera
        // if we assume we are looking along the negative Z axis!
        if (-reproj_Zero > -reproj_One)
        {
            // the far plane is mapped to 0 -> inverse DX style
            mFarPlane = -reproj_Zero;
            mNearPlane = -reproj_One;
        }
        else
        {
            // the near plane is mapped to zero -> DX style
            mFarPlane = -reproj_One;
            mNearPlane = -reproj_Zero;
        }
    }
    else
    {
        // OpenGL style, mapping to -1..1 or 1..-1
        if (-reproj_minusOne > -reproj_One)
        {
            // the far plane is mapped to -1 -> inverse GL style
            mFarPlane = -reproj_minusOne;
            mNearPlane = -reproj_One;
        }
        else
        {
            // the near plane is mapped to -1 -> GL style
            mFarPlane = -reproj_One;
            mNearPlane = -reproj_minusOne;
        }
    }
}