aboutsummaryrefslogtreecommitdiff
path: root/dep/include/g3dlite/G3D/GCamera.h
blob: 50d5ca2244e768b1d28c8b4c578a6fe297c0a24f (plain)
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
  @file GCamera.h

  @maintainer Morgan McGuire, matrix@graphics3d.com

  @created 2001-06-02
  @edited  2006-02-11
*/

#ifndef G3D_GCAMERA_H
#define G3D_GCAMERA_H

#include "G3D/platform.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Vector3.h"
#include "G3D/Plane.h"

namespace G3D {

/**
  There is a viewport of width x height size in world space that corresponds to
  a screenWidth x screenHeight pixel grid on a
  renderDevice->getWidth() x renderDevice->getHeight()
  window.

  All viewport arguments are the pixel bounds of the viewport-- e.g.,
  RenderDevice::getViewport().
 */
class GCamera  {
private:

    /**
    Vertical field of view (in radians)
    */
    float                       fieldOfView;

    /**
     The image plane depth corresponding to a vertical field of
     view, where the film size is 1x1.
     */
    float                       imagePlaneDepth;

    /**
     Clipping plane, *not* imaging plane.  Positive numbers.
     */
    float                       nearPlane;

    /**
     Positive
     */
    float                       farPlane;

    CoordinateFrame             cframe;

public:

    class Frustum {
    public:
        class Face {
        public:
            /** Counter clockwise indices into vertexPos */
            int             vertexIndex[4];

            /** The plane containing the face. */
            Plane           plane;
        };

        /** The vertices, in homogeneous space.  If w == 0,
            a vertex is at infinity. */
        Array<Vector4>      vertexPos;

        /** The faces in the frustum.  When the
            far plane is at infinity, there are 5 faces,
            otherwise there are 6.  The faces are in the order
            N,R,L,B,T,[F].
            */
        Array<Face>         faceArray;
    };

    GCamera();

    virtual ~GCamera();


    CoordinateFrame getCoordinateFrame() const;
    void getCoordinateFrame(CoordinateFrame& c) const;
    void setCoordinateFrame(const CoordinateFrame& c);

   /**
     Sets the horizontal field of view, in radians.  The
     initial angle is toRadians(55).
     <UL>
      <LI> toRadians(50) - Telephoto
      <LI> toRadians(110) - Normal
      <LI> toRadians(140) - Wide angle
     </UL>
    */
    void setFieldOfView(float angle);

    /**
    Sets the field of view based on a desired image plane depth
    (<I>s'</I>) and film dimensions in world space.  Depth must be positive.  Width,
    depth, and height are measured in the same units (meters are
    recommended).  The field of view will span the diagonal to the
    image.<P> <I>Note</I>: to simulate a 35mm GCamera, set width =
    0.36 mm and height = 0.24 mm.  The width and height used are
    generally not the pixel dimensions of the image.
    */
    void setImagePlaneDepth(
        float                                   depth,
        const class Rect2D&                     viewport);

    inline double getFieldOfView() const {
        return fieldOfView;
    }

    /**
     Projects a world space point onto a width x height screen.  The
     returned coordinate uses pixmap addressing: x = right and y =
     down.  The resulting z value is <I>rhw</I>.

     If the point is behind the camera, Vector3::inf() is returned.
     */
    G3D::Vector3 project(
        const G3D::Vector3&                     point,
        const class Rect2D&                     viewport) const;

    /**
     Returns the pixel area covered by a shape of the given
     world space area at the given z value (z must be negative).
     */
    float worldToScreenSpaceArea(float area, float z, const class Rect2D& viewport) const;

    /**
     Returns the world space 3D viewport corners.  These
     are at the near clipping plane.  The corners are constructed
     from the nearPlaneZ, getViewportWidth, and getViewportHeight.
     "left" and "right" are from the GCamera's perspective.
     */
    void get3DViewportCorners(
        const class Rect2D&                     viewport,
        Vector3&                                outUR,
        Vector3&                                outUL,
        Vector3&                                outLL,
        Vector3&                                outLR) const;

    /**
     Returns the image plane depth, <I>s'</I>, given the current field
     of view for film of dimensions width x height.  See
     setImagePlaneDepth for a discussion of worldspace values width and height.
    */
    float getImagePlaneDepth(
        const class Rect2D&                     viewport) const;


    /**
      Returns the world space ray passing through the center of pixel
      (x, y) on the image plane.  The pixel x and y axes are opposite
      the 3D object space axes: (0,0) is the upper left corner of the screen.
      They are in viewport coordinates, not screen coordinates.


      Integer (x, y) values correspond to
      the upper left corners of pixels.  If you want to cast rays
      through pixel centers, add 0.5 to x and y.
    */
    Ray worldRay(
        float                                  x,
        float                                  y,
        const class Rect2D&                     viewport) const;


    /**
      Returns a negative z-value.
     */
    inline float getNearPlaneZ() const {
        return -nearPlane;
    }

    /**
     Returns a negative z-value.
     */
    inline float getFarPlaneZ() const {
        return -farPlane;
    }

    inline void setFarPlaneZ(float z) {
        debugAssert(z < 0);
        farPlane = -z;
    }

    inline void setNearPlaneZ(float z) {
        debugAssert(z < 0);
        nearPlane = -z;
    }

    /**
     Returns the GCamera space width of the viewport.
     */
    float getViewportWidth(
        const class Rect2D&                     viewport) const;

    /**
     Returns the GCamera space height of the viewport.
     */
    float getViewportHeight(
        const class Rect2D&                     viewport) const;

    /**
     Read back a GCamera space z-value at pixel (x, y) from the depth buffer.
    double getZValue(
        double          x,
        double          y,
        const class Rect2D&                     viewport,
        double          polygonOffset = 0) const;
     */

    void setPosition(const Vector3& t);

    void lookAt(const Vector3& position, const Vector3& up = Vector3::unitY());

   /**
    Returns the clipping planes of the frustum, in world space.
    The planes have normals facing <B>into</B> the view frustum.

    The plane order is guaranteed to be:
      Near, Right, Left, Top, Bottom, [Far]

    If the far plane is at infinity, the resulting array will have
    5 planes, otherwise there will be 6.

    The viewport is used only to determine the aspect ratio of the screen; the
    absolute dimensions and xy values don't matter.
    */
   void getClipPlanes(
       const Rect2D& viewport,
       Array<Plane>& outClip) const;

   /**
    Returns the world space view frustum, which is a truncated pyramid describing
    the volume of space seen by this camera.
    */
   void getFrustum(const Rect2D& viewport, GCamera::Frustum& f) const;

   GCamera::Frustum frustum(const Rect2D& viewport) const;

};

} // namespace G3D

#endif