#pragma once
#include "ofNode.h"
#include "ofRectangle.h"
class ofRectangle;
// \todo Use the public API of ofNode for all transformations
// \todo add set projection matrix
// \todo support for left handed or right handed?
/// \brief A basic camera object for interacting with objects in 3D space.
/// \author Memo Akten, MSA Visuals Ltd. 2011
class ofCamera : public ofNode {
public:
/// \name Constructor and Destructor
/// \{
/// \brief Construct a default camera.
ofCamera();
/// \brief Destroy the camera.
virtual ~ofCamera();
/// \}
/// \name Camera Settings
/// \{
/// \brief Set the field of view for a perspective camera.
///
/// This sets the vertical field of view for the camera, in degrees.
/// This only operates with perspective cameras, and will have no effect
/// with cameras in orthographic mode.
///
/// \param f The desired field of view for the camera, in degrees.
void setFov(float f);
void setNearClip(float f);
void setFarClip(float f);
/// \brief Set the "lens offset" applied to this camera.
///
/// Ordinarily, the camera is pointed straight down the center of its view
/// frustum. However, it is possible to orient the camera towards a location
/// offset from the center of its frustum. This is called an "assymetric
/// frustum" and is used (for example) in stereo views. It is acheived by
/// applying an offset to the center of projection. This function sets this
/// offset from an ofVec2f argument. For more information see
/// <http://www.orthostereo.com/geometryopengl.html>.
///
/// \param lensOffset The "lens offset" to apply to this camera, encoded in
/// an ofVec2f.
void setLensOffset(const glm::vec2 & lensOffset);
/// \brief Set the recommended aspect ratio for a perspective camera.
///
/// Sets the aspect ratio of the camera to the desired float, and forces the
/// use of aspect ratio calculations. Currently only used with perspective
/// cameras. The default value (and the value used with orthographic
/// cameras) is the ratio of the viewport's width to the viewport's height.
///
/// \param aspectRatio The desired aspect ratio, e.g. 1.3333, 1.6, etc.
void setAspectRatio(float aspectRatio);
/// \brief Set whether or not the aspect ratio of this camera is forced to a non-default setting.
///
/// The camera's aspect ratio, by default, is the aspect ratio of your
/// viewport. If you have set a non-default value (with
/// ofCamera::setAspectRatio()), you can toggle whether or not this value is
/// applied.
///
/// \param forceAspectRatio Whether or not this camera should use an aspect ratio you have set yourself.
void setForceAspectRatio(bool forceAspectRatio);
/// \brief Get the camera's field of view, in degrees.
///
/// Get the camera's vertical field of view, in degrees. This is only
/// meaningful for perspective cameras.
///
/// \returns The camera's field of view, in degrees.
float getFov() const { return fov; };
float getNearClip() const { return nearClip; };
float getFarClip() const { return farClip; };
/// \brief Get the "lens offset" applied to this camera, encoded as an ofVec2f.
///
/// Ordinarily, the camera is pointed straight down the center of its view
/// frustum. However, it is possible to orient the camera towards a
/// location offset from the center of its frustum. This is called an
/// "asymetric frustum" and is used (for example) in stereo views. It is
/// acheived by applying an offset to the center of projection. This
/// function returns the offset that has been applied, as an ofVec2f. For
/// more information see http://www.orthostereo.com/geometryopengl.html.
///
/// \returns The "lens offset" applied to this camera, encoded in an ofVec2f.
glm::vec2 getLensOffset() const { return lensOffset; };
/// \brief Get the boolean state which indicates whether the aspect ratio of this camera is forced to a non-default setting.
///
/// \returns A boolean: whether or not this camera's aspect ratio is set to a non-default value.
bool getForceAspectRatio() const {return forceAspectRatio;};
/// \brief Get the aspect ratio of this camera's viewport.
///
/// Returns the aspect ratio of this camera's viewport. Usually this will be
/// the ratio of the width to height of your display. Intended for
/// perspective cameras.
///
/// \returns The aspect ratio of this camera's viewport.
float getAspectRatio() const {return aspectRatio; };
/// \}
/// \name OpenGL Setup
/// \{
void setupPerspective(bool vFlip = true, float fov = 60, float nearDist = 0, float farDist = 0, const glm::vec2 & lensOffset = glm::vec2(0.0f, 0.0f));
void setupOffAxisViewPortal(const glm::vec3 & topLeft, const glm::vec3 & bottomLeft, const glm::vec3 & bottomRight);
void setVFlip(bool vflip);
bool isVFlipped() const;
void enableOrtho();
void disableOrtho();
bool getOrtho() const;
float getImagePlaneDistance(const ofRectangle & viewport = ofRectangle()) const;
/// \}
/// \name Rendering
/// \{
/// \brief Begins rendering with the camera.
///
/// ~~~~{.cpp}
/// void draw() {
/// // Begin rendering from the camera's perspective.
/// camera.begin();
///
/// ofLine(0, 0, ofGetWidth(), ofGetHeight());
/// // Additional rendering ...
///
/// // End rendering form the camera's perspective.
/// camera.end();
/// }
/// ~~~~
/// \param viewport The camera's rendering viewport.
virtual void begin(){
begin(getViewport());
}
virtual void begin(const ofRectangle & viewport);
/// \brief Ends rendering with the camera.
virtual void end();
/// \}
/// \name OpenGL Matrix
/// \{
/// \brief Access the projection matrix.
/// \returns the current 4x4 projection matrix.
glm::mat4 getProjectionMatrix() const{
return getProjectionMatrix(getViewport());
}
glm::mat4 getProjectionMatrix(const ofRectangle & viewport) const;
/// \brief Access the model view matrix.
/// \returns the current 4x4 model view matrix.
glm::mat4 getModelViewMatrix() const;
/// \todo getModelViewProjectionMatrix()
glm::mat4 getModelViewProjectionMatrix(const ofRectangle & viewport) const;
glm::mat4 getModelViewProjectionMatrix() const{
return getModelViewProjectionMatrix(getViewport());
}
/// \}
/// \name Coordinate Conversion
/// \{
/// \brief Obtain the screen coordinates of a point in the 3D world.
///
/// Takes an (X,Y,Z) point in your 3D world, encoded as an ofVec3f,
/// and returns the location (also as an ofVec3f) where this point would
/// appear on your (two-dimensional) display. The screen position's "Z
/// coordinate" is set to be the same as your camera's.
///
/// \param WorldXYZ A 3D point in the world, whose screen coordinates you wish to know.
/// \param viewport (Optional) A viewport. The default is ofGetCurrentViewport().
/// \returns An ofVec3f containing the screen coordinates of your 3D point of interest.
glm::vec3 worldToScreen(glm::vec3 WorldXYZ, const ofRectangle & viewport) const;
glm::vec3 worldToScreen(glm::vec3 WorldXYZ) const{
return worldToScreen(WorldXYZ, getViewport());
}
/// \brief Obtain the coordinates, in the 3D world, of a 2D point presumed to be on your screen.
///
/// Takes a pixel location on your screen, encoded in an ofVec3f,
/// and returns (also as an ofVec3f) the 3D world coordinates of that point.
/// You'll also need to specify a Z value when providing your screen point.
/// This Z value is interpreted as a distance into or away from the screen.
///
/// \param ScreenXYZ A point on your screen, whose 3D world coordinates you wish to know.
glm::vec3 screenToWorld(glm::vec3 ScreenXYZ, const ofRectangle & viewport) const;
glm::vec3 screenToWorld(glm::vec3 ScreenXYZ) const{
return screenToWorld(ScreenXYZ, getViewport());
}
/// \todo worldToCamera()
glm::vec3 worldToCamera(glm::vec3 WorldXYZ, const ofRectangle & viewport) const;
glm::vec3 worldToCamera(glm::vec3 WorldXYZ) const{
return worldToCamera(WorldXYZ, getViewport());
}
/// \todo cameraToWorld()
glm::vec3 cameraToWorld(glm::vec3 CameraXYZ, const ofRectangle & viewport) const;
glm::vec3 cameraToWorld(glm::vec3 CameraXYZ) const{
return cameraToWorld(CameraXYZ, getViewport());
}
/// \}
/// \name Renderer
/// \{
void setRenderer(std::shared_ptr<ofBaseRenderer> renderer);
/// \}
/// \brief Draw a visual representation of the camera's frustum
/// \note This will only be visible when the camera drawing its
/// frustum is viewed through another camera.
void drawFrustum(const ofRectangle & viewport) const;
void drawFrustum() const{
drawFrustum(getViewport());
}
protected:
ofRectangle getViewport() const;
std::shared_ptr<ofBaseRenderer> getRenderer() const;
void calcClipPlanes(const ofRectangle & viewport);
private:
bool isOrtho;
float fov;
float nearClip;
float farClip;
glm::vec2 lensOffset;
bool forceAspectRatio;
float aspectRatio; // only used when forceAspect=true, = w / h
bool vFlip;
std::shared_ptr<ofBaseRenderer> renderer;
};
Comments