| 1 | /** |
|---|
| 2 | @file GCamera.h |
|---|
| 3 | |
|---|
| 4 | @maintainer Morgan McGuire, matrix@graphics3d.com |
|---|
| 5 | |
|---|
| 6 | @created 2001-06-02 |
|---|
| 7 | @edited 2006-02-11 |
|---|
| 8 | */ |
|---|
| 9 | |
|---|
| 10 | #ifndef G3D_GCAMERA_H |
|---|
| 11 | #define G3D_GCAMERA_H |
|---|
| 12 | |
|---|
| 13 | #include "G3D/platform.h" |
|---|
| 14 | #include "G3D/CoordinateFrame.h" |
|---|
| 15 | #include "G3D/Vector3.h" |
|---|
| 16 | #include "G3D/Plane.h" |
|---|
| 17 | |
|---|
| 18 | namespace G3D { |
|---|
| 19 | |
|---|
| 20 | /** |
|---|
| 21 | There is a viewport of width x height size in world space that corresponds to |
|---|
| 22 | a screenWidth x screenHeight pixel grid on a |
|---|
| 23 | renderDevice->getWidth() x renderDevice->getHeight() |
|---|
| 24 | window. |
|---|
| 25 | |
|---|
| 26 | All viewport arguments are the pixel bounds of the viewport-- e.g., |
|---|
| 27 | RenderDevice::getViewport(). |
|---|
| 28 | */ |
|---|
| 29 | class GCamera { |
|---|
| 30 | private: |
|---|
| 31 | |
|---|
| 32 | /** |
|---|
| 33 | Vertical field of view (in radians) |
|---|
| 34 | */ |
|---|
| 35 | float fieldOfView; |
|---|
| 36 | |
|---|
| 37 | /** |
|---|
| 38 | The image plane depth corresponding to a vertical field of |
|---|
| 39 | view, where the film size is 1x1. |
|---|
| 40 | */ |
|---|
| 41 | float imagePlaneDepth; |
|---|
| 42 | |
|---|
| 43 | /** |
|---|
| 44 | Clipping plane, *not* imaging plane. Positive numbers. |
|---|
| 45 | */ |
|---|
| 46 | float nearPlane; |
|---|
| 47 | |
|---|
| 48 | /** |
|---|
| 49 | Positive |
|---|
| 50 | */ |
|---|
| 51 | float farPlane; |
|---|
| 52 | |
|---|
| 53 | CoordinateFrame cframe; |
|---|
| 54 | |
|---|
| 55 | public: |
|---|
| 56 | |
|---|
| 57 | class Frustum { |
|---|
| 58 | public: |
|---|
| 59 | class Face { |
|---|
| 60 | public: |
|---|
| 61 | /** Counter clockwise indices into vertexPos */ |
|---|
| 62 | int vertexIndex[4]; |
|---|
| 63 | |
|---|
| 64 | /** The plane containing the face. */ |
|---|
| 65 | Plane plane; |
|---|
| 66 | }; |
|---|
| 67 | |
|---|
| 68 | /** The vertices, in homogeneous space. If w == 0, |
|---|
| 69 | a vertex is at infinity. */ |
|---|
| 70 | Array<Vector4> vertexPos; |
|---|
| 71 | |
|---|
| 72 | /** The faces in the frustum. When the |
|---|
| 73 | far plane is at infinity, there are 5 faces, |
|---|
| 74 | otherwise there are 6. The faces are in the order |
|---|
| 75 | N,R,L,B,T,[F]. |
|---|
| 76 | */ |
|---|
| 77 | Array<Face> faceArray; |
|---|
| 78 | }; |
|---|
| 79 | |
|---|
| 80 | GCamera(); |
|---|
| 81 | |
|---|
| 82 | virtual ~GCamera(); |
|---|
| 83 | |
|---|
| 84 | |
|---|
| 85 | CoordinateFrame getCoordinateFrame() const; |
|---|
| 86 | void getCoordinateFrame(CoordinateFrame& c) const; |
|---|
| 87 | void setCoordinateFrame(const CoordinateFrame& c); |
|---|
| 88 | |
|---|
| 89 | /** |
|---|
| 90 | Sets the horizontal field of view, in radians. The |
|---|
| 91 | initial angle is toRadians(55). |
|---|
| 92 | <UL> |
|---|
| 93 | <LI> toRadians(50) - Telephoto |
|---|
| 94 | <LI> toRadians(110) - Normal |
|---|
| 95 | <LI> toRadians(140) - Wide angle |
|---|
| 96 | </UL> |
|---|
| 97 | */ |
|---|
| 98 | void setFieldOfView(float angle); |
|---|
| 99 | |
|---|
| 100 | /** |
|---|
| 101 | Sets the field of view based on a desired image plane depth |
|---|
| 102 | (<I>s'</I>) and film dimensions in world space. Depth must be positive. Width, |
|---|
| 103 | depth, and height are measured in the same units (meters are |
|---|
| 104 | recommended). The field of view will span the diagonal to the |
|---|
| 105 | image.<P> <I>Note</I>: to simulate a 35mm GCamera, set width = |
|---|
| 106 | 0.36 mm and height = 0.24 mm. The width and height used are |
|---|
| 107 | generally not the pixel dimensions of the image. |
|---|
| 108 | */ |
|---|
| 109 | void setImagePlaneDepth( |
|---|
| 110 | float depth, |
|---|
| 111 | const class Rect2D& viewport); |
|---|
| 112 | |
|---|
| 113 | inline double getFieldOfView() const { |
|---|
| 114 | return fieldOfView; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | /** |
|---|
| 118 | Projects a world space point onto a width x height screen. The |
|---|
| 119 | returned coordinate uses pixmap addressing: x = right and y = |
|---|
| 120 | down. The resulting z value is <I>rhw</I>. |
|---|
| 121 | |
|---|
| 122 | If the point is behind the camera, Vector3::inf() is returned. |
|---|
| 123 | */ |
|---|
| 124 | G3D::Vector3 project( |
|---|
| 125 | const G3D::Vector3& point, |
|---|
| 126 | const class Rect2D& viewport) const; |
|---|
| 127 | |
|---|
| 128 | /** |
|---|
| 129 | Returns the pixel area covered by a shape of the given |
|---|
| 130 | world space area at the given z value (z must be negative). |
|---|
| 131 | */ |
|---|
| 132 | float worldToScreenSpaceArea(float area, float z, const class Rect2D& viewport) const; |
|---|
| 133 | |
|---|
| 134 | /** |
|---|
| 135 | Returns the world space 3D viewport corners. These |
|---|
| 136 | are at the near clipping plane. The corners are constructed |
|---|
| 137 | from the nearPlaneZ, getViewportWidth, and getViewportHeight. |
|---|
| 138 | "left" and "right" are from the GCamera's perspective. |
|---|
| 139 | */ |
|---|
| 140 | void get3DViewportCorners( |
|---|
| 141 | const class Rect2D& viewport, |
|---|
| 142 | Vector3& outUR, |
|---|
| 143 | Vector3& outUL, |
|---|
| 144 | Vector3& outLL, |
|---|
| 145 | Vector3& outLR) const; |
|---|
| 146 | |
|---|
| 147 | /** |
|---|
| 148 | Returns the image plane depth, <I>s'</I>, given the current field |
|---|
| 149 | of view for film of dimensions width x height. See |
|---|
| 150 | setImagePlaneDepth for a discussion of worldspace values width and height. |
|---|
| 151 | */ |
|---|
| 152 | float getImagePlaneDepth( |
|---|
| 153 | const class Rect2D& viewport) const; |
|---|
| 154 | |
|---|
| 155 | |
|---|
| 156 | /** |
|---|
| 157 | Returns the world space ray passing through the center of pixel |
|---|
| 158 | (x, y) on the image plane. The pixel x and y axes are opposite |
|---|
| 159 | the 3D object space axes: (0,0) is the upper left corner of the screen. |
|---|
| 160 | They are in viewport coordinates, not screen coordinates. |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | Integer (x, y) values correspond to |
|---|
| 164 | the upper left corners of pixels. If you want to cast rays |
|---|
| 165 | through pixel centers, add 0.5 to x and y. |
|---|
| 166 | */ |
|---|
| 167 | Ray worldRay( |
|---|
| 168 | float x, |
|---|
| 169 | float y, |
|---|
| 170 | const class Rect2D& viewport) const; |
|---|
| 171 | |
|---|
| 172 | |
|---|
| 173 | /** |
|---|
| 174 | Returns a negative z-value. |
|---|
| 175 | */ |
|---|
| 176 | inline float getNearPlaneZ() const { |
|---|
| 177 | return -nearPlane; |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | /** |
|---|
| 181 | Returns a negative z-value. |
|---|
| 182 | */ |
|---|
| 183 | inline float getFarPlaneZ() const { |
|---|
| 184 | return -farPlane; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | inline void setFarPlaneZ(float z) { |
|---|
| 188 | debugAssert(z < 0); |
|---|
| 189 | farPlane = -z; |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | inline void setNearPlaneZ(float z) { |
|---|
| 193 | debugAssert(z < 0); |
|---|
| 194 | nearPlane = -z; |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | /** |
|---|
| 198 | Returns the GCamera space width of the viewport. |
|---|
| 199 | */ |
|---|
| 200 | float getViewportWidth( |
|---|
| 201 | const class Rect2D& viewport) const; |
|---|
| 202 | |
|---|
| 203 | /** |
|---|
| 204 | Returns the GCamera space height of the viewport. |
|---|
| 205 | */ |
|---|
| 206 | float getViewportHeight( |
|---|
| 207 | const class Rect2D& viewport) const; |
|---|
| 208 | |
|---|
| 209 | /** |
|---|
| 210 | Read back a GCamera space z-value at pixel (x, y) from the depth buffer. |
|---|
| 211 | double getZValue( |
|---|
| 212 | double x, |
|---|
| 213 | double y, |
|---|
| 214 | const class Rect2D& viewport, |
|---|
| 215 | double polygonOffset = 0) const; |
|---|
| 216 | */ |
|---|
| 217 | |
|---|
| 218 | void setPosition(const Vector3& t); |
|---|
| 219 | |
|---|
| 220 | void lookAt(const Vector3& position, const Vector3& up = Vector3::unitY()); |
|---|
| 221 | |
|---|
| 222 | /** |
|---|
| 223 | Returns the clipping planes of the frustum, in world space. |
|---|
| 224 | The planes have normals facing <B>into</B> the view frustum. |
|---|
| 225 | |
|---|
| 226 | The plane order is guaranteed to be: |
|---|
| 227 | Near, Right, Left, Top, Bottom, [Far] |
|---|
| 228 | |
|---|
| 229 | If the far plane is at infinity, the resulting array will have |
|---|
| 230 | 5 planes, otherwise there will be 6. |
|---|
| 231 | |
|---|
| 232 | The viewport is used only to determine the aspect ratio of the screen; the |
|---|
| 233 | absolute dimensions and xy values don't matter. |
|---|
| 234 | */ |
|---|
| 235 | void getClipPlanes( |
|---|
| 236 | const Rect2D& viewport, |
|---|
| 237 | Array<Plane>& outClip) const; |
|---|
| 238 | |
|---|
| 239 | /** |
|---|
| 240 | Returns the world space view frustum, which is a truncated pyramid describing |
|---|
| 241 | the volume of space seen by this camera. |
|---|
| 242 | */ |
|---|
| 243 | void getFrustum(const Rect2D& viewport, GCamera::Frustum& f) const; |
|---|
| 244 | |
|---|
| 245 | GCamera::Frustum frustum(const Rect2D& viewport) const; |
|---|
| 246 | |
|---|
| 247 | }; |
|---|
| 248 | |
|---|
| 249 | } // namespace G3D |
|---|
| 250 | |
|---|
| 251 | #endif |
|---|