/** @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 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 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). */ void setFieldOfView(float angle); /** Sets the field of view based on a desired image plane depth (s') 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.

Note: 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 rhw. 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, s', 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 into 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& 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