Eric Sunshine
2014-02-20 20:56:39 UTC
Should ticket #1008 be closed now that this patch series has been committed?
Revision: 40009
http://sourceforge.net/p/crystal/code/40009
Author: kickvb
Date: 2014-02-20 15:41:08 +0000 (Thu, 20 Feb 2014)
-----------
As reported in #1008, there was previously some problems around the management of the field of view and aspect ratio of the perspective cameras. The methods SetFOV() and SetFOVAngle() were working inconsistently, and it was not possible to achieve proper zoom effects. There was also a confusion whether the various parameters should be used in view space or in normalized screen coordinates.
Another related problem was the fact that, in a lot of different places within the CS code, it is assumed that the camera has a perspective projection, although this can be a custom one.
Still another related problem, although purely on the design point of view, was a duplication of the definition of the viewport dimensions. They were supposed to be defined both in the iView and in the iCamera, although that's the iView that is supposed to manage the definition of the viewport.
This patch and the following ones globally address all of these issues by introducing new FOV-related methods that are now supposed to work correctly, new camera projection methods that work for all camera types, and by concentrating all viewport-related methods within iView.
The main target achievement of this set of patches is to make both the resizing of the 2D canvas and the management of custom matrix cameras work much more correctly.
- Added the methods iPerspectiveCamera::Set/GetVerticalFOV(), Set/GetVerticalFOVAngle(), Set/GetAspectRatio() that are now supposed to work as intended.
- Deprecated all previous FOV-related methods. The aforementioned new methods should be used instead.
- Deprecated the method iCamera::SetViewportSize(). That's now the iView that manages the viewport dimensions.
- Added the generic methods iCamera::Project() and InvProject() that work in normalized screen coordinates and for all camera types.
- Deprecated the methods iCamera::Perspective() and InvPerspective(). Project() and InvProject() should be used instead.
- Warning: The methods GetShiftX/Y() and SetPerspectiveCenter() where previously inconsistently used both in screen space and in normalized screen coordinates depending on the camera interface being used. They are now always supposed to be provided in normalized screen coordinates.
- API documentation improvements.
--------------
CS/trunk/include/iengine/camera.h
CS/trunk/plugins/engine/3d/camera.cpp
CS/trunk/plugins/engine/3d/camera.h
Modified: CS/trunk/include/iengine/camera.h
===================================================================
--- CS/trunk/include/iengine/camera.h 2014-02-20 15:38:02 UTC (rev 40008)
+++ CS/trunk/include/iengine/camera.h 2014-02-20 15:41:08 UTC (rev 40009)
@@ -28,8 +28,9 @@
#include "csgeom/matrix4.h"
+#include "csgeom/vector2.h"
#include "csutil/scf.h"
-#include "csgeom/matrix4.h"
+//#include "csgeom/matrix4.h"
#define CS_VEC_FORWARD csVector3(0,0,1)
#define CS_VEC_BACKWARD csVector3(0,0,-1)
@@ -47,7 +48,6 @@
class csOrthoTransform;
class csPlane3;
-class csVector2;
class csVector3;
struct iSector;
@@ -80,6 +80,8 @@
*
* - iCamera
+ *
+ * \deprecated Use iCameraListener instead
*/
struct CS_DEPRECATED_TYPE_MSG("Use iCameraListener instead")
iCameraSectorListener : public iCameraListener
@@ -97,27 +99,44 @@
/**
* Camera class. This class represents camera objects which can be used to
+ * render a world in the engine.
+ *
* - Home sector: The sector in which rendering starts.
* - Transformation: This is an orthonormal transformation which is applied
* to all rendered objects to move them from world space to camera space.
- * It is the mathematical representation of position and direction of the
- * camera. The position should be inside the home sector.
- * - Field of View: Controls the size on screen of the rendered objects and
- * can be used for zooming effects. The FOV can be given either in pixels
- * or as an angle in degrees.
- * - Shift amount: The projection center in screen coordinates.
+ * It is the mathematical representation of the position and direction of
+ * the camera. This transform is relative to the home sector.
+ * - Projection matrix: The matrix being used to project objects in 3D
+ * camera space into normalized screen coordinates.
* - Mirrored Flag: Should be set to true if the transformation is mirrored.
* - Far Plane: A distant plane that is orthogonal to the view direction. It
* is used to clip away all objects that are farther away than a certain
* distance, usually to improve rendering speed.
- * - Camera number: An identifier for a camera transformation, used
+ * - Camera number: An identifier for the state of the camera, used
* internally in the engine to detect outdated vertex buffers.
* - Only Portals Flag: If this is true then no collisions are detected for
* camera movement except for portals.
*
+ * iCamera is the base abstract interface for all camera types. Practically,
+ * all cameras will also implement either the iPerspectiveCamera or the
+ * iCustomMatrixCamera interfaces depending on the desired camera projection.
+ *
+ * The cameras work in normalized screen coordinates, that is, with the
+ * visible portion of the screen being mapped in the range [-1, 1], with the
+ * top-left corner of the screen being at the coordinates (-1, -1), and the
+ * bottom-right corner being at (1, 1).
+ *
+ * Normalized screen coordinates are independant on the size of the viewport
+ * (that is, the iView). If you want to manipulate coordinates expressed in
+ * pixels (that is, in screen space coordinates), then you can use the methods
+ * iView::Project(), iView::InvProject(), csEngineTools::NormalizedToScreen()
+ * and csEngineTools::ScreenToNormalized().
+ *
* - iEngine::CreateCamera()
+ * - iEngine::CreatePerspectiveCamera()
+ * - iEngine::CreateCustomMatrixCamera()
* - csView
*
@@ -126,10 +145,13 @@
* - csView
* - iView
+ *
+ * \sa iCameraPosition
*/
struct iCamera : public virtual iBase
{
- SCF_INTERFACE(iCamera, 3,0,0);
+ SCF_INTERFACE(iCamera, 4,0,0);
+
/**
* Create a clone of this camera. Note that the array of listeners
* is not cloned.
@@ -253,6 +275,7 @@
/**
* Eliminate roundoff error by snapping the camera orientation to a
* grid of density n
+ * \deprecated Don't use it anymore
*/
CS_DEPRECATED_METHOD_MSG("Don't use it anymore")
virtual void Correct (int n) = 0;
@@ -264,7 +287,7 @@
/**
* Get the 3D far plane that should be used to clip all geometry.
- * If this function returns 0 no far clipping is required.
+ * If this function returns 0 then no far clipping is required.
* Otherwise it must be used to clip the object before
* drawing.
*/
@@ -283,14 +306,36 @@
/**
* Get the camera number. This number is changed for every new camera
* instance and it is also updated whenever the camera transformation
- * changes. This number can be used to cache camera vertex arrays, for
- * example.
+ * or projection matrix changes. This number can be used to cache camera
+ * vertex arrays, for example.
*/
virtual long GetCameraNumber () const = 0;
- /// Calculate perspective corrected point for this camera.
+ /**
+ * Calculate a perspective corrected point for this camera, that is the
+ * projection of a 3D point expressed in camera space into the 2D camera
+ * screen.
+ * \param v The 3D point to be projected, in camera space coordinates.
+ * \return The 2D projection into the screen, in pixels.
+ * \sa InvPerspective()
+ * \deprecated Deprecated in 2.2. Use Project() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use Project() instead")
virtual csVector2 Perspective (const csVector3& v) const = 0;
- /// Calculate inverse perspective corrected point for this camera.
+
+ /**
+ * Calculate an inverse perspective corrected point for this camera,
+ * that is the inverse projection of a 2D point expressed in screen space
+ * into the 3D camera space.
+ * \param p The 2D point on the screen, in pixels.
+ * \param z The Z component of the projection point, that is the
+ * distance between the camera and the plane where the point was
+ * projected from.
+ * \return The 3D projection point, in camera space coordinates.
+ * \sa Perspective()
+ * \deprecated Deprecated in 2.2. Use InvProject() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use InvProject() instead")
virtual csVector3 InvPerspective (const csVector2& p, float z) const = 0;
/**
@@ -321,7 +366,13 @@
/// Remove a listener from this camera.
virtual void RemoveCameraListener (iCameraListener* listener) = 0;
- /// Get the projection matrix for this camera
+ /**
+ * Get the projection matrix for this camera. This matrix will project
+ * points in 3D camera space into normalized screen coordinates (that
+ * is, with the visible portion of the screen being mapped in the range
+ * [-1, 1]).
+ * \sa GetInvProjectionMatrix() csEngineTools::NormalizedToScreen()
+ */
virtual const CS::Math::Matrix4& GetProjectionMatrix () = 0;
/**
@@ -330,17 +381,59 @@
*/
virtual const csPlane3* GetVisibleVolume (uint32& mask) = 0;
- /// Set the size of the viewport this camera is associated with.
+ /**
+ * Set the size of the viewport this camera is associated with.
+ * \deprecated Deprecated in 2.2. Use iView instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use iView instead")
virtual void SetViewportSize (int width, int height) = 0;
- /// Get the inverse projection matrix for this camera
+ /**
+ * Get the inverse projection matrix for this camera. This matrix will
+ * project points in normalized screen coordinates (that is, with the
+ * visible portion of the screen being mapped in the range [-1, 1]) into
+ * 3D camera space.
+ * \sa GetProjectionMatrix() csEngineTools::ScreenToNormalized()
+ */
virtual const CS::Math::Matrix4& GetInvProjectionMatrix () = 0;
+
+ /**
+ * Calculate a projection corrected point for this camera, that is the
+ * projection of a 3D point expressed in camera space into the 2D camera
+ * screen.
+ * \param v The 3D point to be projected, in camera space coordinates.
+ * \return The 2D projection into the screen, in normalized screen
+ * coordinates.
+ * \sa InvProject() csEngineTools::NormalizedToScreen()
+ */
+ virtual csVector2 Project (const csVector3& v) const = 0;
+
+ /**
+ * Calculate an inverse projection corrected point for this camera,
+ * that is the inverse projection of a 2D point expressed in normalized
+ * screen coordinates into the 3D camera space.
+ * \param p The 2D point on the screen, in normalized screen coordinates.
+ * \param z The Z component of the projection point, that is the
+ * distance between the camera and the plane where the point is projected.
+ * \return The 3D projection point, in camera space coordinates.
+ * \sa Project() csEngineTools::ScreenToNormalized()
+ */
+ virtual csVector3 InvProject (const csVector2& p, float z) const = 0;
};
/**
* An implementation of iCamera that renders a world with a classical
* perspective.
*
+ * - Field of View (FOV): Controls the size on screen of the rendered objects
+ * and can be used for zooming effects. The FOV can be defined either as a
+ * global scale or as an angle in degrees.
+ * - Aspect ratio: The aspect ratio between the horizontal and the vertical
+ * FOVs.
+ * - Shift amount: The projection center of the perspective, that is, the
+ * position of the vanishing point of the perspective.
+ *
* - iEngine::CreatePerspectiveCamera()
*
@@ -349,42 +442,74 @@
*/
struct iPerspectiveCamera : public virtual iBase
{
- SCF_INTERFACE(iPerspectiveCamera, 1, 0, 1);
+ SCF_INTERFACE(iPerspectiveCamera, 1, 0, 2);
/// Get the iCamera interface for this camera.
virtual iCamera* GetCamera() = 0;
- /// Return the normalized FOV (field of view)
+ /**
+ * Return the vertical FOV (field of view) in normalized screen
+ * coordinates.
+ * \deprecated Deprecated in 2.2. Use GetVerticalFOV() and GetAspectRatio() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use GetVerticalFOV() and GetAspectRatio() instead")
virtual float GetFOV () const = 0;
- /// Return the inverse of normalized field of view (1/FOV)
+ /**
+ * Return the inverse of the normalized vertical field of view
+ * (1/FOV)
+ * \deprecated Deprecated in 2.2. Use GetVerticalFOV() and
+ * GetAspectRatio() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use GetVerticalFOV() and GetAspectRatio() instead")
virtual float GetInvFOV () const = 0;
- /// Return the FOV (field of view) in degrees.
+ /**
+ * Return the vertical FOV (field of view) in degrees.
+ * \deprecated Deprecated in 2.2. Use GetVerticalFOVAngle() and
+ * GetAspectRatio() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use GetVerticalFOVAngle() and GetAspectRatio() instead")
virtual float GetFOVAngle () const = 0;
/**
* Set the FOV. \a fov is the desired FOV in normalized screen coordinates.
* \a width is the display width, also normalized.
+ * \deprecated Deprecated in 2.2. Use SetVerticalFOV() and
+ * SetAspectRatio() instead
*/
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use SetVerticalFOV() and SetAspectRatio() instead")
virtual void SetFOV (float fov, float width) = 0;
/**
* Set the FOV in degrees. \a fov is the desired FOV in degrees. \a width is
* the display width in normalized screen coordinates.
+ * \deprecated Deprecated in 2.2. Use SetVerticalFOVAngle() and
+ * SetAspectRatio() instead
*/
- virtual void SetFOVAngle (float fov, float width) = 0;
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use SetVerticalFOVAngle() and SetAspectRatio() instead")
+ virtual void SetFOVAngle (float fov, float aspect) = 0;
/**
- * Get the X shift amount. The parameter specified the desired X coordinate
+ * Get the X shift amount. The parameter specifies the X coordinate
* on the normalized screen of the projection center of the camera.
+ * \sa SetPerspectiveCenter()
*/
virtual float GetShiftX () const = 0;
/**
- * Get the Y shift amount. The parameter specified the desired Y coordinate
+ * Get the Y shift amount. The parameter specifies the Y coordinate
* on the normalized screen of the projection center of the camera.
+ * \sa SetPerspectiveCenter()
*/
virtual float GetShiftY () const = 0;
/**
- * Set the shift amount. The parameter specified the desired projection
- * center of the camera on the normalized screen.
+ * Set the X and Y shift amounts. Those parameters specify the desired
+ * projection center of the camera on the normalized screen, that is, the
+ * position of the vanishing point of the perspective.
+ *
+ * The default values for both \a x and \a y are 0.5, this corresponds to the
+ * vanishing point being at the center of the screen. A value of 0 sets the
+ * vanishing point respectively on the left and bottom of the screen, while a
+ * value of 1 sets it respectively at the right and top of the screen.
+ *
+ * \sa GetShiftX() GetShiftY()
*/
virtual void SetPerspectiveCenter (float x, float y) = 0;
@@ -401,11 +526,55 @@
*/
virtual float GetNearClipDistance() const = 0;
/**
- * Set near clip distance of this camera.
+ * Set the near clip distance of this camera.
*
* The default near clipping distance is controlled by the engine.
*/
virtual void SetNearClipDistance (float dist) = 0;
+
+ /// Return the vertical FOV (field of view) in normalized screen coordinates.
+ virtual float GetVerticalFOV () const = 0;
+
+ /**
+ * Set the vertical FOV (field of view) in normalized screen coordinates.
+ * This corresponds to the global scale that the camera applies on its
+ * view. The horizontal FOV will be computed using the value set in
+ * SetAspectRatio().
+ *
+ * The default value is 1.0. Bigger values result in wide angle views,
+ * while lower values result in zoom effects.
+ */
+ virtual void SetVerticalFOV (float fov) = 0;
+
+ /// Return the vertical FOV (field of view) in degrees.
+ virtual float GetVerticalFOVAngle () const = 0;
+
+ /**
+ * Set the vertical FOV (field of view) as an angle in degrees. This is
+ * the angle seen by the camera between the top and the bottom edges of
+ * the screen. The horizontal FOV will be computed using the value set in
+ * SetAspectRatio().
+ *
+ * The default value is 90. Bigger values result in wide angle views,
+ * while lower values result in zoom effects.
+ */
+ virtual void SetVerticalFOVAngle (float fov) = 0;
+
+ /**
+ * Get the aspect ratio between the horizontal and the vertical FOVs.
+ */
+ virtual float GetAspectRatio () const = 0;
+
+ /**
+ * Set the aspect ratio between the horizontal and the vertical FOVs.
+ *
+ * If you use a different aspect ratio than the one of your window size
+ * (that is, its width divided by its height), then it will result in some
+ * stretching of the image. The default value is controlled by the engine
+ * and is set to the aspect ratio of the 2D canvas at initialization time
+ * (that is, usually 4:3).
+ */
+ virtual void SetAspectRatio (float aspect) = 0;
};
/**
@@ -425,7 +594,10 @@
/// Get the iCamera interface for this camera.
virtual iCamera* GetCamera() = 0;
- /// Set the projection matrix.
+ /**
+ * Set the projection matrix of this camera.
+ * \sa iCamera::GetProjectionMatrix() iCamera::GetInvProjectionMatrix()
+ */
virtual void SetProjectionMatrix (const CS::Math::Matrix4& mat) = 0;
};
Modified: CS/trunk/plugins/engine/3d/camera.cpp
===================================================================
--- CS/trunk/plugins/engine/3d/camera.cpp 2014-02-20 15:38:02 UTC (rev 40008)
+++ CS/trunk/plugins/engine/3d/camera.cpp 2014-02-20 15:41:08 UTC (rev 40009)
@@ -169,51 +169,66 @@
//---------------------------------------------------------------------------
-float PerspectiveImpl:: default_aspect = 0;
-float PerspectiveImpl:: default_inv_aspect = 0;
-float PerspectiveImpl:: default_fov_angle = 90;
+float PerspectiveImpl:: default_aspect_ratio = 1.f;
+float PerspectiveImpl:: default_inv_aspect_ratio = 1.f;
+float PerspectiveImpl:: default_fov_ratio = 1.f;
+float PerspectiveImpl:: default_inv_fov_ratio = 1.f;
PerspectiveImpl::PerspectiveImpl (csEngine* engine)
: nearClip (engine->csEngine::GetDefaultNearClipDistance()),
matrixDirty (true), invMatrixDirty (true)
{
- aspect = default_aspect;
- inv_aspect = default_inv_aspect;
- fov_angle = default_fov_angle;
+ aspect_ratio = default_aspect_ratio;
+ inv_aspect_ratio = default_inv_aspect_ratio;
+ fov_ratio = default_fov_ratio;
+ inv_fov_ratio = default_inv_fov_ratio;
shift_x = 0.5f;
shift_y = 0.5f;
}
-void PerspectiveImpl::SetDefaultFOVAngle (float a, float width)
+void PerspectiveImpl::SetDefaultFOV (float fov, float aspect)
{
- // make sure we have valid angles
- if (a >= 180)
+ // Make sure we have valid angles
+ if (fov < SMALL_EPSILON)
{
- a = 180 - SMALL_EPSILON;
+ fov = SMALL_EPSILON;
}
- else if (a <= 0)
+
+ default_fov_ratio = fov;
+ default_inv_fov_ratio = 1.0f / default_fov_ratio;
+ default_aspect_ratio = aspect;
+ default_inv_aspect_ratio = 1.0f / aspect;
+}
+
+void PerspectiveImpl::SetDefaultFOVAngle (float fov, float aspect)
+{
+ // Make sure we have valid angles
+ if (fov >= 180.f)
{
- a = SMALL_EPSILON;
+ fov = 180.f - SMALL_EPSILON;
}
+ else if (fov < SMALL_EPSILON)
+ {
+ fov = SMALL_EPSILON;
+ }
- // This is our reference point.
- // It must be somewhere on the function graph.
- // This reference point was composed by testing.
- // If anyone knows a 100 percent correct reference point, please put it here.
- // But for now it's about 99% correct
- float vRefFOVAngle = 53;
- float vRefFOV = width;
+ // The FOV ratio is the tangent of the half fov angle (in radiant).
+ default_fov_ratio = tan ((fov * 0.5f * PI) / 180.f);
- // We calculate the new aspect relative to a reference point
- default_aspect = ((tan((vRefFOVAngle * 0.5) / 180 * PI) * vRefFOV) /
- tan((a * 0.5) / 180 * PI));
+ // Set the other necessary variables
+ default_inv_fov_ratio = 1.0f / default_fov_ratio;
+ default_aspect_ratio = aspect;
+ default_inv_aspect_ratio = 1.0f / aspect;
+}
- // set the other neccessary variables
- default_inv_aspect = 1.0f / default_aspect;
- default_fov_angle = a;
+void PerspectiveImpl::SetFOV (float a, float width)
+{
+ inv_fov_ratio = 1.0f;
+ fov_ratio = 1.0f;
+ aspect_ratio = 1.0f / a;
+ inv_aspect_ratio = a;
}
-
void PerspectiveImpl::SetFOVAngle (float a, float width)
{
// make sure we have valid angles
@@ -226,52 +241,75 @@
a = SMALL_EPSILON;
}
- // This is our reference point.
- // It must be somewhere on the function graph.
- // This reference point was composed by testing.
- // If anyone knows a 100 percent correct reference point, please put it here.
- // But for now it's about 99% correct
- float vRefFOVAngle = 53;
- float vRefFOV = width;
+ // We calculate the new aspect relative to the reference height of 0.5
+ inv_fov_ratio = (0.5f * width) / tan ((a * 0.5f) / 180.f * PI);
- // We calculate the new aspect relative to a reference point
- aspect = ((tan((vRefFOVAngle * 0.5) / 180 * PI) * vRefFOV) /
- tan((a * 0.5) / 180 * PI));
+ // Set the other necessary variables
+ fov_ratio = 1.0f / fov_ratio;
+ aspect_ratio = width;
+ inv_aspect_ratio = 1.0f / aspect_ratio;
- // set the other neccessary variables
- inv_aspect = 1.0f / aspect;
- fov_angle = a;
Dirtify();
}
-void PerspectiveImpl::ComputeAngle (float width)
+void PerspectiveImpl::SetVerticalFOV (float fov)
{
- float rview_fov = (float)GetFOV () * 0.5f;
- float disp_width = (float)width * 0.5f;
- float inv_disp_radius = csQisqrt (
- rview_fov * rview_fov + disp_width * disp_width);
- fov_angle = 2.0f * (float)acos (disp_width * inv_disp_radius)
- * (360.0f / TWO_PI);
+ // Make sure we have valid angles
+ if (fov < SMALL_EPSILON)
+ {
+ fov = SMALL_EPSILON;
+ }
+
+ fov_ratio = fov;
+ inv_fov_ratio = 1.0f / fov_ratio;
+
Dirtify();
}
-void PerspectiveImpl::ComputeDefaultAngle (float width)
+void PerspectiveImpl::SetVerticalFOVAngle (float fov)
{
- float rview_fov = (float)GetDefaultFOV () * 0.5f;
- float disp_width = (float)width * 0.5f;
- float inv_disp_radius = csQisqrt (
- rview_fov * rview_fov + disp_width * disp_width);
- default_fov_angle = 2.0f * (float)acos (disp_width * inv_disp_radius)
- * (360.0f / TWO_PI);
+ // Make sure we have valid angles
+ if (fov >= 180.f)
+ {
+ fov = 180.f - SMALL_EPSILON;
+ }
+ else if (fov < SMALL_EPSILON)
+ {
+ fov = SMALL_EPSILON;
+ }
+
+ // The FOV ratio is the tangent of the half FOV angle (in radiant).
+ fov_ratio = tan ((fov * 0.5f * PI) / 180.f);
+ inv_fov_ratio = 1.0f / fov_ratio;
+
+ Dirtify ();
}
+float PerspectiveImpl::GetFOVAngle () const
+{
+ return atan (fov_ratio) * 360.f / PI;
+}
+
+float PerspectiveImpl::GetVerticalFOVAngle () const
+{
+ return atan (fov_ratio) * 360.f / PI;
+}
+
+void PerspectiveImpl::SetAspectRatio (float aspect)
+{
+ aspect_ratio = aspect;
+ inv_aspect_ratio = 1.0f / aspect;
+
+ Dirtify ();
+}
+
void PerspectiveImpl::UpdateMatrix ()
{
if (!matrixDirty) return;
-
- matrix = CS::Math::Projections::CSPerspective (1.0f,
- aspect, shift_x, shift_y*aspect, inv_aspect, nearClip);
-
+
+ matrix = CS::Math::Projections::CSPerspective
+ (aspect_ratio, 1.0f, shift_x * aspect_ratio, shift_y, fov_ratio, nearClip);
+
matrixDirty = false;
invMatrixDirty = true;
}
@@ -285,6 +323,42 @@
invMatrixDirty = false;
}
+csVector2 PerspectiveImpl::Perspective (const csVector3& v) const
+{
+ csVector2 p;
+ float iz = fov_ratio / v.z;
+ p.x = v.x * inv_aspect_ratio * iz + shift_x;
+ p.y = v.y * iz + shift_y;
+ return p;
+}
+
+csVector3 PerspectiveImpl::InvPerspective (const csVector2& p, float z) const
+{
+ csVector3 v;
+ v.z = z;
+ v.x = (p.x - shift_x) * z * inv_fov_ratio * aspect_ratio;
+ v.y = (p.y - shift_y) * z * inv_fov_ratio;
+ return v;
+}
+
+csVector2 PerspectiveImpl::Project (const csVector3& v) const
+{
+ csVector2 p;
+ float iz = fov_ratio / v.z;
+ p.x = (v.x * inv_aspect_ratio * iz + shift_x) * 2.f - 1.f;
+ p.y = (v.y * iz + shift_y) * 2.f - 1.f;
+ return p;
+}
+
+csVector3 PerspectiveImpl::InvProject (const csVector2& p, float z) const
+{
+ csVector3 v;
+ v.z = z;
+ v.x = (p.x * 0.5f + 0.5f - shift_x) * z * inv_fov_ratio * aspect_ratio;
+ v.y = (p.y * 0.5f + 0.5f - shift_y) * z * inv_fov_ratio;
+ return v;
+}
+
//---------------------------------------------------------------------------
void csCameraPerspective::UpdateClipPlanes()
@@ -292,10 +366,10 @@
if (!clipPlanesDirty) return;
float lx, rx, ty, by;
- lx = -shift_x * inv_aspect;
- rx = (1.0f - shift_x) * inv_aspect;
- ty = -shift_y;
- by = (1.0f - shift_y);
+ lx = -shift_x * inv_fov_ratio * aspect_ratio;
+ rx = (1.0f - shift_x) * inv_fov_ratio * aspect_ratio;
+ ty = -shift_y * inv_fov_ratio;
+ by = (1.0f - shift_y) * inv_fov_ratio;
csPlane3* frust = clipPlanes;
csVector3 v1 (lx, ty, 1);
@@ -327,22 +401,13 @@
//---------------------------------------------------------------------------
csCameraCustomMatrix::csCameraCustomMatrix (csCameraBase* other)
- : scfImplementationType (this, other), invMatrixDirty (true),
- clipPlanesDirty (true)
+ : scfImplementationType (this, other), clipPlanesDirty (true)
{
// csCameraBase copy ctor already bumped the cam
matrix = other->GetProjectionMatrix();
+ invMatrix = other->GetInvProjectionMatrix();
}
-void csCameraCustomMatrix::UpdateInvMatrix ()
-{
- if (!invMatrixDirty) return;
-
- invMatrix = matrix.GetInverse();
-
- invMatrixDirty = false;
-}
-
const csPlane3* csCameraCustomMatrix::GetVisibleVolume (uint32& mask)
{
if (clipPlanesDirty)
@@ -391,6 +456,25 @@
return clipPlanes;
}
+csVector2 csCameraCustomMatrix::Project (const csVector3& v) const
+{
+ csVector4 v_proj (matrix * csVector4 (v, 1.f));
+ float inv_w = 1.f / v_proj.w;
+ csVector2 p;
+ p.x = v_proj.x * inv_w;
+ p.y = v_proj.y * inv_w;
+ return p;
}
+
+csVector3 csCameraCustomMatrix::InvProject (const csVector2& p, float z) const
+{
+ csVector4 v_proj =
+ invMatrix * csVector4 (p.x, p.y, 0.f, 1.f);
+ float scale = z / v_proj[2];
+ csVector3 v (scale * v_proj[0], scale * v_proj[1], z);
+ return v;
+}
+
+}
CS_PLUGIN_NAMESPACE_END(Engine)
Modified: CS/trunk/plugins/engine/3d/camera.h
===================================================================
--- CS/trunk/plugins/engine/3d/camera.h 2014-02-20 15:38:02 UTC (rev 40008)
+++ CS/trunk/plugins/engine/3d/camera.h 2014-02-20 15:41:08 UTC (rev 40009)
@@ -250,7 +250,8 @@
*/
void Correct (int n);
- void SetPerspectiveCenter (float, float) { }
+ void SetPerspectiveCenter (float, float) { }
+
virtual csVector2 Perspective (const csVector3& v) const
{
csVector2 p (0);
@@ -333,26 +334,26 @@
class PerspectiveImpl : public iPerspectiveCamera
{
- ///
- float aspect;
- static float default_aspect;
- ///
- float inv_aspect;
- static float default_inv_aspect;
- ///
+ /// Aspect ratio between the horizontal and the vertical FOVs.
+ float aspect_ratio;
+ static float default_aspect_ratio;
+ float inv_aspect_ratio;
+ static float default_inv_aspect_ratio;
+
+ /// Field Of View
+ float fov_ratio;
+ static float default_fov_ratio;
+ float inv_fov_ratio;
+ static float default_inv_fov_ratio;
+
+ /// Perspective center
float shift_x;
float shift_y;
- /// FOV in angles (degrees).
- float fov_angle;
- static float default_fov_angle;
-
+ /// Clip distances
float nearClip;
- /// Compute above angle.
- void ComputeAngle (float width);
- static void ComputeDefaultAngle (float width);
-
+ // Projection matrices
CS::Math::Matrix4 matrix;
CS::Math::Matrix4 invMatrix;
bool matrixDirty;
@@ -360,45 +361,49 @@
void UpdateMatrix ();
void UpdateInvMatrix ();
+
PerspectiveImpl (csEngine* engine);
/// Set the default FOV for new cameras.
- static void SetDefaultFOV (float fov, float width)
- {
- default_aspect = fov;
- default_inv_aspect = 1.0f / default_aspect;
- ComputeDefaultAngle (width);
- }
- static void SetDefaultFOVAngle (float a, float width);
+ static void SetDefaultFOV (float fov, float aspect);
+ static void SetDefaultFOVAngle (float fov, float aspect);
/// Get the default FOV for new cameras.
- static float GetDefaultFOV () { return default_aspect; }
+ static float GetDefaultFOV () { return default_fov_ratio; }
/// Get the default inverse FOV for new cameras.
- static float GetDefaultInvFOV () { return default_inv_aspect; }
+ static float GetDefaultInvFOV () { return default_inv_fov_ratio; }
/// Get the default FOV in angles (degrees).
- static float GetDefaultFOVAngle () { return default_fov_angle; }
+ static float GetDefaultFOVAngle () { return default_aspect_ratio * 180.f / PI; }
/// Set the FOV for this camera.
- void SetFOV (float a, float width)
- {
- aspect = a;
- inv_aspect = 1.0f / a;
- ComputeAngle (width);
- }
+ void SetFOV (float a, float width);
/// Get the FOV for this camera
- float GetFOV () const { return aspect; }
+ float GetFOV () const { return fov_ratio; }
/// Get the inverse FOV for this camera.
- float GetInvFOV () const { return inv_aspect; }
+ float GetInvFOV () const { return inv_fov_ratio; }
/// Set the FOV in angles (degrees).
void SetFOVAngle (float a, float width);
/// Get the FOV in angles (degrees).
- float GetFOVAngle () const
- {
- return fov_angle;
- }
+ float GetFOVAngle () const;
+ /// Set the vertical FOV
+ void SetVerticalFOV (float fov);
+ /// Get the vertical FOV
+ float GetVerticalFOV () const { return fov_ratio; }
+
+ /// Set the vertical FOV in angles (degrees).
+ void SetVerticalFOVAngle (float fov);
+ /// Get the vertical FOV in angles (degrees).
+ float GetVerticalFOVAngle () const;
+
+ /// Set the aspect ratio between the horizontal and the vertical FOVs.
+ void SetAspectRatio (float aspect);
+ /// Get the aspect ratio between the horizontal and the vertical FOVs.
+ float GetAspectRatio () const
+ { return aspect_ratio; }
+
/// Get the X shift value.
float GetShiftX () const { return shift_x; }
/// Get the Y shift value.
@@ -412,24 +417,13 @@
}
/// Calculate perspective corrected point for this camera.
- csVector2 Perspective (const csVector3& v) const
- {
- csVector2 p;
- float iz = 1.0 / v.z;
- p.x = v.x * aspect * iz + shift_x;
- p.y = v.y * iz + shift_y;
- return p;
- }
-
+ csVector2 Perspective (const csVector3& v) const;
/// Calculate inverse perspective corrected point for this camera.
- csVector3 InvPerspective (const csVector2& p, float z) const
- {
- csVector3 v;
- v.z = z;
- v.x = (p.x - shift_x) * z * inv_aspect;
- v.y = (p.y - shift_y) * z;
- return v;
- }
+ csVector3 InvPerspective (const csVector2& p, float z) const;
+ /// Calculate perspective corrected point for this camera.
+ csVector2 Project (const csVector3& v) const;
+ /// Calculate inverse perspective corrected point for this camera.
+ csVector3 InvProject (const csVector2& p, float z) const;
const CS::Math::Matrix4& GetProjectionMatrix ()
{
@@ -502,21 +496,20 @@
{
CS_ASSERT_MSG("SetViewportSize() not called",
(vp_width > 0) && (vp_height > 0));
- return Persp().PerspectiveImpl::GetShiftX() * vp_width;
+ return Persp().PerspectiveImpl::GetShiftX ();
}
float GetShiftY () const
{
CS_ASSERT_MSG("SetViewportSize() not called",
(vp_width > 0) && (vp_height > 0));
- return Persp().PerspectiveImpl::GetShiftY() * vp_height;
+ return Persp().PerspectiveImpl::GetShiftY ();
}
void SetPerspectiveCenter (float x, float y)
{
CS_ASSERT_MSG("SetViewportSize() not called",
(vp_width > 0) && (vp_height > 0));
- Persp().PerspectiveImpl::SetPerspectiveCenter (x/(float)vp_width,
- y/(float)vp_height);
+ Persp().PerspectiveImpl::SetPerspectiveCenter (x, y);
BumpCamera();
}
csVector2 Perspective (const csVector3& v) const
@@ -538,8 +531,12 @@
void SetViewportSize (int width, int height)
{
vp_width = width; vp_height = height;
- Persp().Dirtify();
+ BumpCamera ();
}
+ csVector2 Project (const csVector3& v) const
+ { return Persp().PerspectiveImpl::Project (v); }
+ csVector3 InvProject (const csVector2& p, float z) const
+ { return Persp().PerspectiveImpl::InvProject (p, z); }
};
@@ -596,15 +593,13 @@
{
CS::Math::Matrix4 matrix;
CS::Math::Matrix4 invMatrix;
- bool invMatrixDirty;
bool clipPlanesDirty;
csPlane3 clipPlanes[6];
uint32 clipPlanesMask;
- void UpdateInvMatrix ();
csCameraCustomMatrix () : scfImplementationType (this),
- invMatrixDirty (true), clipPlanesDirty (true) {}
+ clipPlanesDirty (true) {}
csCameraCustomMatrix (csCameraBase* other);
csPtr<iCamera> Clone () const
@@ -619,17 +614,17 @@
void SetProjectionMatrix (const CS::Math::Matrix4& m)
{
matrix = m;
+ invMatrix = matrix.GetInverse();
clipPlanesDirty = true;
- invMatrixDirty = true;
BumpCamera();
}
const CS::Math::Matrix4& GetInvProjectionMatrix ()
- {
- UpdateInvMatrix ();
- return invMatrix;
- }
+ { return invMatrix; }
const csPlane3* GetVisibleVolume (uint32& mask);
+
+ virtual csVector2 Project (const csVector3& v) const;
+ virtual csVector3 InvProject (const csVector2& p, float z) const;
};
#include "csutil/deprecated_warn_on.h"
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk
_______________________________________________
Crystal-cvs mailing list
https://lists.sourceforge.net/lists/listinfo/crystal-cvs
http://sourceforge.net/p/crystal/code/40009
Author: kickvb
Date: 2014-02-20 15:41:08 +0000 (Thu, 20 Feb 2014)
-----------
As reported in #1008, there was previously some problems around the management of the field of view and aspect ratio of the perspective cameras. The methods SetFOV() and SetFOVAngle() were working inconsistently, and it was not possible to achieve proper zoom effects. There was also a confusion whether the various parameters should be used in view space or in normalized screen coordinates.
Another related problem was the fact that, in a lot of different places within the CS code, it is assumed that the camera has a perspective projection, although this can be a custom one.
Still another related problem, although purely on the design point of view, was a duplication of the definition of the viewport dimensions. They were supposed to be defined both in the iView and in the iCamera, although that's the iView that is supposed to manage the definition of the viewport.
This patch and the following ones globally address all of these issues by introducing new FOV-related methods that are now supposed to work correctly, new camera projection methods that work for all camera types, and by concentrating all viewport-related methods within iView.
The main target achievement of this set of patches is to make both the resizing of the 2D canvas and the management of custom matrix cameras work much more correctly.
- Added the methods iPerspectiveCamera::Set/GetVerticalFOV(), Set/GetVerticalFOVAngle(), Set/GetAspectRatio() that are now supposed to work as intended.
- Deprecated all previous FOV-related methods. The aforementioned new methods should be used instead.
- Deprecated the method iCamera::SetViewportSize(). That's now the iView that manages the viewport dimensions.
- Added the generic methods iCamera::Project() and InvProject() that work in normalized screen coordinates and for all camera types.
- Deprecated the methods iCamera::Perspective() and InvPerspective(). Project() and InvProject() should be used instead.
- Warning: The methods GetShiftX/Y() and SetPerspectiveCenter() where previously inconsistently used both in screen space and in normalized screen coordinates depending on the camera interface being used. They are now always supposed to be provided in normalized screen coordinates.
- API documentation improvements.
--------------
CS/trunk/include/iengine/camera.h
CS/trunk/plugins/engine/3d/camera.cpp
CS/trunk/plugins/engine/3d/camera.h
Modified: CS/trunk/include/iengine/camera.h
===================================================================
--- CS/trunk/include/iengine/camera.h 2014-02-20 15:38:02 UTC (rev 40008)
+++ CS/trunk/include/iengine/camera.h 2014-02-20 15:41:08 UTC (rev 40009)
@@ -28,8 +28,9 @@
#include "csgeom/matrix4.h"
+#include "csgeom/vector2.h"
#include "csutil/scf.h"
-#include "csgeom/matrix4.h"
+//#include "csgeom/matrix4.h"
#define CS_VEC_FORWARD csVector3(0,0,1)
#define CS_VEC_BACKWARD csVector3(0,0,-1)
@@ -47,7 +48,6 @@
class csOrthoTransform;
class csPlane3;
-class csVector2;
class csVector3;
struct iSector;
@@ -80,6 +80,8 @@
*
* - iCamera
+ *
+ * \deprecated Use iCameraListener instead
*/
struct CS_DEPRECATED_TYPE_MSG("Use iCameraListener instead")
iCameraSectorListener : public iCameraListener
@@ -97,27 +99,44 @@
/**
* Camera class. This class represents camera objects which can be used to
+ * render a world in the engine.
+ *
* - Home sector: The sector in which rendering starts.
* - Transformation: This is an orthonormal transformation which is applied
* to all rendered objects to move them from world space to camera space.
- * It is the mathematical representation of position and direction of the
- * camera. The position should be inside the home sector.
- * - Field of View: Controls the size on screen of the rendered objects and
- * can be used for zooming effects. The FOV can be given either in pixels
- * or as an angle in degrees.
- * - Shift amount: The projection center in screen coordinates.
+ * It is the mathematical representation of the position and direction of
+ * the camera. This transform is relative to the home sector.
+ * - Projection matrix: The matrix being used to project objects in 3D
+ * camera space into normalized screen coordinates.
* - Mirrored Flag: Should be set to true if the transformation is mirrored.
* - Far Plane: A distant plane that is orthogonal to the view direction. It
* is used to clip away all objects that are farther away than a certain
* distance, usually to improve rendering speed.
- * - Camera number: An identifier for a camera transformation, used
+ * - Camera number: An identifier for the state of the camera, used
* internally in the engine to detect outdated vertex buffers.
* - Only Portals Flag: If this is true then no collisions are detected for
* camera movement except for portals.
*
+ * iCamera is the base abstract interface for all camera types. Practically,
+ * all cameras will also implement either the iPerspectiveCamera or the
+ * iCustomMatrixCamera interfaces depending on the desired camera projection.
+ *
+ * The cameras work in normalized screen coordinates, that is, with the
+ * visible portion of the screen being mapped in the range [-1, 1], with the
+ * top-left corner of the screen being at the coordinates (-1, -1), and the
+ * bottom-right corner being at (1, 1).
+ *
+ * Normalized screen coordinates are independant on the size of the viewport
+ * (that is, the iView). If you want to manipulate coordinates expressed in
+ * pixels (that is, in screen space coordinates), then you can use the methods
+ * iView::Project(), iView::InvProject(), csEngineTools::NormalizedToScreen()
+ * and csEngineTools::ScreenToNormalized().
+ *
* - iEngine::CreateCamera()
+ * - iEngine::CreatePerspectiveCamera()
+ * - iEngine::CreateCustomMatrixCamera()
* - csView
*
@@ -126,10 +145,13 @@
* - csView
* - iView
+ *
+ * \sa iCameraPosition
*/
struct iCamera : public virtual iBase
{
- SCF_INTERFACE(iCamera, 3,0,0);
+ SCF_INTERFACE(iCamera, 4,0,0);
+
/**
* Create a clone of this camera. Note that the array of listeners
* is not cloned.
@@ -253,6 +275,7 @@
/**
* Eliminate roundoff error by snapping the camera orientation to a
* grid of density n
+ * \deprecated Don't use it anymore
*/
CS_DEPRECATED_METHOD_MSG("Don't use it anymore")
virtual void Correct (int n) = 0;
@@ -264,7 +287,7 @@
/**
* Get the 3D far plane that should be used to clip all geometry.
- * If this function returns 0 no far clipping is required.
+ * If this function returns 0 then no far clipping is required.
* Otherwise it must be used to clip the object before
* drawing.
*/
@@ -283,14 +306,36 @@
/**
* Get the camera number. This number is changed for every new camera
* instance and it is also updated whenever the camera transformation
- * changes. This number can be used to cache camera vertex arrays, for
- * example.
+ * or projection matrix changes. This number can be used to cache camera
+ * vertex arrays, for example.
*/
virtual long GetCameraNumber () const = 0;
- /// Calculate perspective corrected point for this camera.
+ /**
+ * Calculate a perspective corrected point for this camera, that is the
+ * projection of a 3D point expressed in camera space into the 2D camera
+ * screen.
+ * \param v The 3D point to be projected, in camera space coordinates.
+ * \return The 2D projection into the screen, in pixels.
+ * \sa InvPerspective()
+ * \deprecated Deprecated in 2.2. Use Project() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use Project() instead")
virtual csVector2 Perspective (const csVector3& v) const = 0;
- /// Calculate inverse perspective corrected point for this camera.
+
+ /**
+ * Calculate an inverse perspective corrected point for this camera,
+ * that is the inverse projection of a 2D point expressed in screen space
+ * into the 3D camera space.
+ * \param p The 2D point on the screen, in pixels.
+ * \param z The Z component of the projection point, that is the
+ * distance between the camera and the plane where the point was
+ * projected from.
+ * \return The 3D projection point, in camera space coordinates.
+ * \sa Perspective()
+ * \deprecated Deprecated in 2.2. Use InvProject() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use InvProject() instead")
virtual csVector3 InvPerspective (const csVector2& p, float z) const = 0;
/**
@@ -321,7 +366,13 @@
/// Remove a listener from this camera.
virtual void RemoveCameraListener (iCameraListener* listener) = 0;
- /// Get the projection matrix for this camera
+ /**
+ * Get the projection matrix for this camera. This matrix will project
+ * points in 3D camera space into normalized screen coordinates (that
+ * is, with the visible portion of the screen being mapped in the range
+ * [-1, 1]).
+ * \sa GetInvProjectionMatrix() csEngineTools::NormalizedToScreen()
+ */
virtual const CS::Math::Matrix4& GetProjectionMatrix () = 0;
/**
@@ -330,17 +381,59 @@
*/
virtual const csPlane3* GetVisibleVolume (uint32& mask) = 0;
- /// Set the size of the viewport this camera is associated with.
+ /**
+ * Set the size of the viewport this camera is associated with.
+ * \deprecated Deprecated in 2.2. Use iView instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use iView instead")
virtual void SetViewportSize (int width, int height) = 0;
- /// Get the inverse projection matrix for this camera
+ /**
+ * Get the inverse projection matrix for this camera. This matrix will
+ * project points in normalized screen coordinates (that is, with the
+ * visible portion of the screen being mapped in the range [-1, 1]) into
+ * 3D camera space.
+ * \sa GetProjectionMatrix() csEngineTools::ScreenToNormalized()
+ */
virtual const CS::Math::Matrix4& GetInvProjectionMatrix () = 0;
+
+ /**
+ * Calculate a projection corrected point for this camera, that is the
+ * projection of a 3D point expressed in camera space into the 2D camera
+ * screen.
+ * \param v The 3D point to be projected, in camera space coordinates.
+ * \return The 2D projection into the screen, in normalized screen
+ * coordinates.
+ * \sa InvProject() csEngineTools::NormalizedToScreen()
+ */
+ virtual csVector2 Project (const csVector3& v) const = 0;
+
+ /**
+ * Calculate an inverse projection corrected point for this camera,
+ * that is the inverse projection of a 2D point expressed in normalized
+ * screen coordinates into the 3D camera space.
+ * \param p The 2D point on the screen, in normalized screen coordinates.
+ * \param z The Z component of the projection point, that is the
+ * distance between the camera and the plane where the point is projected.
+ * \return The 3D projection point, in camera space coordinates.
+ * \sa Project() csEngineTools::ScreenToNormalized()
+ */
+ virtual csVector3 InvProject (const csVector2& p, float z) const = 0;
};
/**
* An implementation of iCamera that renders a world with a classical
* perspective.
*
+ * - Field of View (FOV): Controls the size on screen of the rendered objects
+ * and can be used for zooming effects. The FOV can be defined either as a
+ * global scale or as an angle in degrees.
+ * - Aspect ratio: The aspect ratio between the horizontal and the vertical
+ * FOVs.
+ * - Shift amount: The projection center of the perspective, that is, the
+ * position of the vanishing point of the perspective.
+ *
* - iEngine::CreatePerspectiveCamera()
*
@@ -349,42 +442,74 @@
*/
struct iPerspectiveCamera : public virtual iBase
{
- SCF_INTERFACE(iPerspectiveCamera, 1, 0, 1);
+ SCF_INTERFACE(iPerspectiveCamera, 1, 0, 2);
/// Get the iCamera interface for this camera.
virtual iCamera* GetCamera() = 0;
- /// Return the normalized FOV (field of view)
+ /**
+ * Return the vertical FOV (field of view) in normalized screen
+ * coordinates.
+ * \deprecated Deprecated in 2.2. Use GetVerticalFOV() and GetAspectRatio() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use GetVerticalFOV() and GetAspectRatio() instead")
virtual float GetFOV () const = 0;
- /// Return the inverse of normalized field of view (1/FOV)
+ /**
+ * Return the inverse of the normalized vertical field of view
+ * (1/FOV)
+ * \deprecated Deprecated in 2.2. Use GetVerticalFOV() and
+ * GetAspectRatio() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use GetVerticalFOV() and GetAspectRatio() instead")
virtual float GetInvFOV () const = 0;
- /// Return the FOV (field of view) in degrees.
+ /**
+ * Return the vertical FOV (field of view) in degrees.
+ * \deprecated Deprecated in 2.2. Use GetVerticalFOVAngle() and
+ * GetAspectRatio() instead
+ */
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use GetVerticalFOVAngle() and GetAspectRatio() instead")
virtual float GetFOVAngle () const = 0;
/**
* Set the FOV. \a fov is the desired FOV in normalized screen coordinates.
* \a width is the display width, also normalized.
+ * \deprecated Deprecated in 2.2. Use SetVerticalFOV() and
+ * SetAspectRatio() instead
*/
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use SetVerticalFOV() and SetAspectRatio() instead")
virtual void SetFOV (float fov, float width) = 0;
/**
* Set the FOV in degrees. \a fov is the desired FOV in degrees. \a width is
* the display width in normalized screen coordinates.
+ * \deprecated Deprecated in 2.2. Use SetVerticalFOVAngle() and
+ * SetAspectRatio() instead
*/
- virtual void SetFOVAngle (float fov, float width) = 0;
+ CS_DEPRECATED_METHOD_MSG("Deprecated in 2.2. Use SetVerticalFOVAngle() and SetAspectRatio() instead")
+ virtual void SetFOVAngle (float fov, float aspect) = 0;
/**
- * Get the X shift amount. The parameter specified the desired X coordinate
+ * Get the X shift amount. The parameter specifies the X coordinate
* on the normalized screen of the projection center of the camera.
+ * \sa SetPerspectiveCenter()
*/
virtual float GetShiftX () const = 0;
/**
- * Get the Y shift amount. The parameter specified the desired Y coordinate
+ * Get the Y shift amount. The parameter specifies the Y coordinate
* on the normalized screen of the projection center of the camera.
+ * \sa SetPerspectiveCenter()
*/
virtual float GetShiftY () const = 0;
/**
- * Set the shift amount. The parameter specified the desired projection
- * center of the camera on the normalized screen.
+ * Set the X and Y shift amounts. Those parameters specify the desired
+ * projection center of the camera on the normalized screen, that is, the
+ * position of the vanishing point of the perspective.
+ *
+ * The default values for both \a x and \a y are 0.5, this corresponds to the
+ * vanishing point being at the center of the screen. A value of 0 sets the
+ * vanishing point respectively on the left and bottom of the screen, while a
+ * value of 1 sets it respectively at the right and top of the screen.
+ *
+ * \sa GetShiftX() GetShiftY()
*/
virtual void SetPerspectiveCenter (float x, float y) = 0;
@@ -401,11 +526,55 @@
*/
virtual float GetNearClipDistance() const = 0;
/**
- * Set near clip distance of this camera.
+ * Set the near clip distance of this camera.
*
* The default near clipping distance is controlled by the engine.
*/
virtual void SetNearClipDistance (float dist) = 0;
+
+ /// Return the vertical FOV (field of view) in normalized screen coordinates.
+ virtual float GetVerticalFOV () const = 0;
+
+ /**
+ * Set the vertical FOV (field of view) in normalized screen coordinates.
+ * This corresponds to the global scale that the camera applies on its
+ * view. The horizontal FOV will be computed using the value set in
+ * SetAspectRatio().
+ *
+ * The default value is 1.0. Bigger values result in wide angle views,
+ * while lower values result in zoom effects.
+ */
+ virtual void SetVerticalFOV (float fov) = 0;
+
+ /// Return the vertical FOV (field of view) in degrees.
+ virtual float GetVerticalFOVAngle () const = 0;
+
+ /**
+ * Set the vertical FOV (field of view) as an angle in degrees. This is
+ * the angle seen by the camera between the top and the bottom edges of
+ * the screen. The horizontal FOV will be computed using the value set in
+ * SetAspectRatio().
+ *
+ * The default value is 90. Bigger values result in wide angle views,
+ * while lower values result in zoom effects.
+ */
+ virtual void SetVerticalFOVAngle (float fov) = 0;
+
+ /**
+ * Get the aspect ratio between the horizontal and the vertical FOVs.
+ */
+ virtual float GetAspectRatio () const = 0;
+
+ /**
+ * Set the aspect ratio between the horizontal and the vertical FOVs.
+ *
+ * If you use a different aspect ratio than the one of your window size
+ * (that is, its width divided by its height), then it will result in some
+ * stretching of the image. The default value is controlled by the engine
+ * and is set to the aspect ratio of the 2D canvas at initialization time
+ * (that is, usually 4:3).
+ */
+ virtual void SetAspectRatio (float aspect) = 0;
};
/**
@@ -425,7 +594,10 @@
/// Get the iCamera interface for this camera.
virtual iCamera* GetCamera() = 0;
- /// Set the projection matrix.
+ /**
+ * Set the projection matrix of this camera.
+ * \sa iCamera::GetProjectionMatrix() iCamera::GetInvProjectionMatrix()
+ */
virtual void SetProjectionMatrix (const CS::Math::Matrix4& mat) = 0;
};
Modified: CS/trunk/plugins/engine/3d/camera.cpp
===================================================================
--- CS/trunk/plugins/engine/3d/camera.cpp 2014-02-20 15:38:02 UTC (rev 40008)
+++ CS/trunk/plugins/engine/3d/camera.cpp 2014-02-20 15:41:08 UTC (rev 40009)
@@ -169,51 +169,66 @@
//---------------------------------------------------------------------------
-float PerspectiveImpl:: default_aspect = 0;
-float PerspectiveImpl:: default_inv_aspect = 0;
-float PerspectiveImpl:: default_fov_angle = 90;
+float PerspectiveImpl:: default_aspect_ratio = 1.f;
+float PerspectiveImpl:: default_inv_aspect_ratio = 1.f;
+float PerspectiveImpl:: default_fov_ratio = 1.f;
+float PerspectiveImpl:: default_inv_fov_ratio = 1.f;
PerspectiveImpl::PerspectiveImpl (csEngine* engine)
: nearClip (engine->csEngine::GetDefaultNearClipDistance()),
matrixDirty (true), invMatrixDirty (true)
{
- aspect = default_aspect;
- inv_aspect = default_inv_aspect;
- fov_angle = default_fov_angle;
+ aspect_ratio = default_aspect_ratio;
+ inv_aspect_ratio = default_inv_aspect_ratio;
+ fov_ratio = default_fov_ratio;
+ inv_fov_ratio = default_inv_fov_ratio;
shift_x = 0.5f;
shift_y = 0.5f;
}
-void PerspectiveImpl::SetDefaultFOVAngle (float a, float width)
+void PerspectiveImpl::SetDefaultFOV (float fov, float aspect)
{
- // make sure we have valid angles
- if (a >= 180)
+ // Make sure we have valid angles
+ if (fov < SMALL_EPSILON)
{
- a = 180 - SMALL_EPSILON;
+ fov = SMALL_EPSILON;
}
- else if (a <= 0)
+
+ default_fov_ratio = fov;
+ default_inv_fov_ratio = 1.0f / default_fov_ratio;
+ default_aspect_ratio = aspect;
+ default_inv_aspect_ratio = 1.0f / aspect;
+}
+
+void PerspectiveImpl::SetDefaultFOVAngle (float fov, float aspect)
+{
+ // Make sure we have valid angles
+ if (fov >= 180.f)
{
- a = SMALL_EPSILON;
+ fov = 180.f - SMALL_EPSILON;
}
+ else if (fov < SMALL_EPSILON)
+ {
+ fov = SMALL_EPSILON;
+ }
- // This is our reference point.
- // It must be somewhere on the function graph.
- // This reference point was composed by testing.
- // If anyone knows a 100 percent correct reference point, please put it here.
- // But for now it's about 99% correct
- float vRefFOVAngle = 53;
- float vRefFOV = width;
+ // The FOV ratio is the tangent of the half fov angle (in radiant).
+ default_fov_ratio = tan ((fov * 0.5f * PI) / 180.f);
- // We calculate the new aspect relative to a reference point
- default_aspect = ((tan((vRefFOVAngle * 0.5) / 180 * PI) * vRefFOV) /
- tan((a * 0.5) / 180 * PI));
+ // Set the other necessary variables
+ default_inv_fov_ratio = 1.0f / default_fov_ratio;
+ default_aspect_ratio = aspect;
+ default_inv_aspect_ratio = 1.0f / aspect;
+}
- // set the other neccessary variables
- default_inv_aspect = 1.0f / default_aspect;
- default_fov_angle = a;
+void PerspectiveImpl::SetFOV (float a, float width)
+{
+ inv_fov_ratio = 1.0f;
+ fov_ratio = 1.0f;
+ aspect_ratio = 1.0f / a;
+ inv_aspect_ratio = a;
}
-
void PerspectiveImpl::SetFOVAngle (float a, float width)
{
// make sure we have valid angles
@@ -226,52 +241,75 @@
a = SMALL_EPSILON;
}
- // This is our reference point.
- // It must be somewhere on the function graph.
- // This reference point was composed by testing.
- // If anyone knows a 100 percent correct reference point, please put it here.
- // But for now it's about 99% correct
- float vRefFOVAngle = 53;
- float vRefFOV = width;
+ // We calculate the new aspect relative to the reference height of 0.5
+ inv_fov_ratio = (0.5f * width) / tan ((a * 0.5f) / 180.f * PI);
- // We calculate the new aspect relative to a reference point
- aspect = ((tan((vRefFOVAngle * 0.5) / 180 * PI) * vRefFOV) /
- tan((a * 0.5) / 180 * PI));
+ // Set the other necessary variables
+ fov_ratio = 1.0f / fov_ratio;
+ aspect_ratio = width;
+ inv_aspect_ratio = 1.0f / aspect_ratio;
- // set the other neccessary variables
- inv_aspect = 1.0f / aspect;
- fov_angle = a;
Dirtify();
}
-void PerspectiveImpl::ComputeAngle (float width)
+void PerspectiveImpl::SetVerticalFOV (float fov)
{
- float rview_fov = (float)GetFOV () * 0.5f;
- float disp_width = (float)width * 0.5f;
- float inv_disp_radius = csQisqrt (
- rview_fov * rview_fov + disp_width * disp_width);
- fov_angle = 2.0f * (float)acos (disp_width * inv_disp_radius)
- * (360.0f / TWO_PI);
+ // Make sure we have valid angles
+ if (fov < SMALL_EPSILON)
+ {
+ fov = SMALL_EPSILON;
+ }
+
+ fov_ratio = fov;
+ inv_fov_ratio = 1.0f / fov_ratio;
+
Dirtify();
}
-void PerspectiveImpl::ComputeDefaultAngle (float width)
+void PerspectiveImpl::SetVerticalFOVAngle (float fov)
{
- float rview_fov = (float)GetDefaultFOV () * 0.5f;
- float disp_width = (float)width * 0.5f;
- float inv_disp_radius = csQisqrt (
- rview_fov * rview_fov + disp_width * disp_width);
- default_fov_angle = 2.0f * (float)acos (disp_width * inv_disp_radius)
- * (360.0f / TWO_PI);
+ // Make sure we have valid angles
+ if (fov >= 180.f)
+ {
+ fov = 180.f - SMALL_EPSILON;
+ }
+ else if (fov < SMALL_EPSILON)
+ {
+ fov = SMALL_EPSILON;
+ }
+
+ // The FOV ratio is the tangent of the half FOV angle (in radiant).
+ fov_ratio = tan ((fov * 0.5f * PI) / 180.f);
+ inv_fov_ratio = 1.0f / fov_ratio;
+
+ Dirtify ();
}
+float PerspectiveImpl::GetFOVAngle () const
+{
+ return atan (fov_ratio) * 360.f / PI;
+}
+
+float PerspectiveImpl::GetVerticalFOVAngle () const
+{
+ return atan (fov_ratio) * 360.f / PI;
+}
+
+void PerspectiveImpl::SetAspectRatio (float aspect)
+{
+ aspect_ratio = aspect;
+ inv_aspect_ratio = 1.0f / aspect;
+
+ Dirtify ();
+}
+
void PerspectiveImpl::UpdateMatrix ()
{
if (!matrixDirty) return;
-
- matrix = CS::Math::Projections::CSPerspective (1.0f,
- aspect, shift_x, shift_y*aspect, inv_aspect, nearClip);
-
+
+ matrix = CS::Math::Projections::CSPerspective
+ (aspect_ratio, 1.0f, shift_x * aspect_ratio, shift_y, fov_ratio, nearClip);
+
matrixDirty = false;
invMatrixDirty = true;
}
@@ -285,6 +323,42 @@
invMatrixDirty = false;
}
+csVector2 PerspectiveImpl::Perspective (const csVector3& v) const
+{
+ csVector2 p;
+ float iz = fov_ratio / v.z;
+ p.x = v.x * inv_aspect_ratio * iz + shift_x;
+ p.y = v.y * iz + shift_y;
+ return p;
+}
+
+csVector3 PerspectiveImpl::InvPerspective (const csVector2& p, float z) const
+{
+ csVector3 v;
+ v.z = z;
+ v.x = (p.x - shift_x) * z * inv_fov_ratio * aspect_ratio;
+ v.y = (p.y - shift_y) * z * inv_fov_ratio;
+ return v;
+}
+
+csVector2 PerspectiveImpl::Project (const csVector3& v) const
+{
+ csVector2 p;
+ float iz = fov_ratio / v.z;
+ p.x = (v.x * inv_aspect_ratio * iz + shift_x) * 2.f - 1.f;
+ p.y = (v.y * iz + shift_y) * 2.f - 1.f;
+ return p;
+}
+
+csVector3 PerspectiveImpl::InvProject (const csVector2& p, float z) const
+{
+ csVector3 v;
+ v.z = z;
+ v.x = (p.x * 0.5f + 0.5f - shift_x) * z * inv_fov_ratio * aspect_ratio;
+ v.y = (p.y * 0.5f + 0.5f - shift_y) * z * inv_fov_ratio;
+ return v;
+}
+
//---------------------------------------------------------------------------
void csCameraPerspective::UpdateClipPlanes()
@@ -292,10 +366,10 @@
if (!clipPlanesDirty) return;
float lx, rx, ty, by;
- lx = -shift_x * inv_aspect;
- rx = (1.0f - shift_x) * inv_aspect;
- ty = -shift_y;
- by = (1.0f - shift_y);
+ lx = -shift_x * inv_fov_ratio * aspect_ratio;
+ rx = (1.0f - shift_x) * inv_fov_ratio * aspect_ratio;
+ ty = -shift_y * inv_fov_ratio;
+ by = (1.0f - shift_y) * inv_fov_ratio;
csPlane3* frust = clipPlanes;
csVector3 v1 (lx, ty, 1);
@@ -327,22 +401,13 @@
//---------------------------------------------------------------------------
csCameraCustomMatrix::csCameraCustomMatrix (csCameraBase* other)
- : scfImplementationType (this, other), invMatrixDirty (true),
- clipPlanesDirty (true)
+ : scfImplementationType (this, other), clipPlanesDirty (true)
{
// csCameraBase copy ctor already bumped the cam
matrix = other->GetProjectionMatrix();
+ invMatrix = other->GetInvProjectionMatrix();
}
-void csCameraCustomMatrix::UpdateInvMatrix ()
-{
- if (!invMatrixDirty) return;
-
- invMatrix = matrix.GetInverse();
-
- invMatrixDirty = false;
-}
-
const csPlane3* csCameraCustomMatrix::GetVisibleVolume (uint32& mask)
{
if (clipPlanesDirty)
@@ -391,6 +456,25 @@
return clipPlanes;
}
+csVector2 csCameraCustomMatrix::Project (const csVector3& v) const
+{
+ csVector4 v_proj (matrix * csVector4 (v, 1.f));
+ float inv_w = 1.f / v_proj.w;
+ csVector2 p;
+ p.x = v_proj.x * inv_w;
+ p.y = v_proj.y * inv_w;
+ return p;
}
+
+csVector3 csCameraCustomMatrix::InvProject (const csVector2& p, float z) const
+{
+ csVector4 v_proj =
+ invMatrix * csVector4 (p.x, p.y, 0.f, 1.f);
+ float scale = z / v_proj[2];
+ csVector3 v (scale * v_proj[0], scale * v_proj[1], z);
+ return v;
+}
+
+}
CS_PLUGIN_NAMESPACE_END(Engine)
Modified: CS/trunk/plugins/engine/3d/camera.h
===================================================================
--- CS/trunk/plugins/engine/3d/camera.h 2014-02-20 15:38:02 UTC (rev 40008)
+++ CS/trunk/plugins/engine/3d/camera.h 2014-02-20 15:41:08 UTC (rev 40009)
@@ -250,7 +250,8 @@
*/
void Correct (int n);
- void SetPerspectiveCenter (float, float) { }
+ void SetPerspectiveCenter (float, float) { }
+
virtual csVector2 Perspective (const csVector3& v) const
{
csVector2 p (0);
@@ -333,26 +334,26 @@
class PerspectiveImpl : public iPerspectiveCamera
{
- ///
- float aspect;
- static float default_aspect;
- ///
- float inv_aspect;
- static float default_inv_aspect;
- ///
+ /// Aspect ratio between the horizontal and the vertical FOVs.
+ float aspect_ratio;
+ static float default_aspect_ratio;
+ float inv_aspect_ratio;
+ static float default_inv_aspect_ratio;
+
+ /// Field Of View
+ float fov_ratio;
+ static float default_fov_ratio;
+ float inv_fov_ratio;
+ static float default_inv_fov_ratio;
+
+ /// Perspective center
float shift_x;
float shift_y;
- /// FOV in angles (degrees).
- float fov_angle;
- static float default_fov_angle;
-
+ /// Clip distances
float nearClip;
- /// Compute above angle.
- void ComputeAngle (float width);
- static void ComputeDefaultAngle (float width);
-
+ // Projection matrices
CS::Math::Matrix4 matrix;
CS::Math::Matrix4 invMatrix;
bool matrixDirty;
@@ -360,45 +361,49 @@
void UpdateMatrix ();
void UpdateInvMatrix ();
+
PerspectiveImpl (csEngine* engine);
/// Set the default FOV for new cameras.
- static void SetDefaultFOV (float fov, float width)
- {
- default_aspect = fov;
- default_inv_aspect = 1.0f / default_aspect;
- ComputeDefaultAngle (width);
- }
- static void SetDefaultFOVAngle (float a, float width);
+ static void SetDefaultFOV (float fov, float aspect);
+ static void SetDefaultFOVAngle (float fov, float aspect);
/// Get the default FOV for new cameras.
- static float GetDefaultFOV () { return default_aspect; }
+ static float GetDefaultFOV () { return default_fov_ratio; }
/// Get the default inverse FOV for new cameras.
- static float GetDefaultInvFOV () { return default_inv_aspect; }
+ static float GetDefaultInvFOV () { return default_inv_fov_ratio; }
/// Get the default FOV in angles (degrees).
- static float GetDefaultFOVAngle () { return default_fov_angle; }
+ static float GetDefaultFOVAngle () { return default_aspect_ratio * 180.f / PI; }
/// Set the FOV for this camera.
- void SetFOV (float a, float width)
- {
- aspect = a;
- inv_aspect = 1.0f / a;
- ComputeAngle (width);
- }
+ void SetFOV (float a, float width);
/// Get the FOV for this camera
- float GetFOV () const { return aspect; }
+ float GetFOV () const { return fov_ratio; }
/// Get the inverse FOV for this camera.
- float GetInvFOV () const { return inv_aspect; }
+ float GetInvFOV () const { return inv_fov_ratio; }
/// Set the FOV in angles (degrees).
void SetFOVAngle (float a, float width);
/// Get the FOV in angles (degrees).
- float GetFOVAngle () const
- {
- return fov_angle;
- }
+ float GetFOVAngle () const;
+ /// Set the vertical FOV
+ void SetVerticalFOV (float fov);
+ /// Get the vertical FOV
+ float GetVerticalFOV () const { return fov_ratio; }
+
+ /// Set the vertical FOV in angles (degrees).
+ void SetVerticalFOVAngle (float fov);
+ /// Get the vertical FOV in angles (degrees).
+ float GetVerticalFOVAngle () const;
+
+ /// Set the aspect ratio between the horizontal and the vertical FOVs.
+ void SetAspectRatio (float aspect);
+ /// Get the aspect ratio between the horizontal and the vertical FOVs.
+ float GetAspectRatio () const
+ { return aspect_ratio; }
+
/// Get the X shift value.
float GetShiftX () const { return shift_x; }
/// Get the Y shift value.
@@ -412,24 +417,13 @@
}
/// Calculate perspective corrected point for this camera.
- csVector2 Perspective (const csVector3& v) const
- {
- csVector2 p;
- float iz = 1.0 / v.z;
- p.x = v.x * aspect * iz + shift_x;
- p.y = v.y * iz + shift_y;
- return p;
- }
-
+ csVector2 Perspective (const csVector3& v) const;
/// Calculate inverse perspective corrected point for this camera.
- csVector3 InvPerspective (const csVector2& p, float z) const
- {
- csVector3 v;
- v.z = z;
- v.x = (p.x - shift_x) * z * inv_aspect;
- v.y = (p.y - shift_y) * z;
- return v;
- }
+ csVector3 InvPerspective (const csVector2& p, float z) const;
+ /// Calculate perspective corrected point for this camera.
+ csVector2 Project (const csVector3& v) const;
+ /// Calculate inverse perspective corrected point for this camera.
+ csVector3 InvProject (const csVector2& p, float z) const;
const CS::Math::Matrix4& GetProjectionMatrix ()
{
@@ -502,21 +496,20 @@
{
CS_ASSERT_MSG("SetViewportSize() not called",
(vp_width > 0) && (vp_height > 0));
- return Persp().PerspectiveImpl::GetShiftX() * vp_width;
+ return Persp().PerspectiveImpl::GetShiftX ();
}
float GetShiftY () const
{
CS_ASSERT_MSG("SetViewportSize() not called",
(vp_width > 0) && (vp_height > 0));
- return Persp().PerspectiveImpl::GetShiftY() * vp_height;
+ return Persp().PerspectiveImpl::GetShiftY ();
}
void SetPerspectiveCenter (float x, float y)
{
CS_ASSERT_MSG("SetViewportSize() not called",
(vp_width > 0) && (vp_height > 0));
- Persp().PerspectiveImpl::SetPerspectiveCenter (x/(float)vp_width,
- y/(float)vp_height);
+ Persp().PerspectiveImpl::SetPerspectiveCenter (x, y);
BumpCamera();
}
csVector2 Perspective (const csVector3& v) const
@@ -538,8 +531,12 @@
void SetViewportSize (int width, int height)
{
vp_width = width; vp_height = height;
- Persp().Dirtify();
+ BumpCamera ();
}
+ csVector2 Project (const csVector3& v) const
+ { return Persp().PerspectiveImpl::Project (v); }
+ csVector3 InvProject (const csVector2& p, float z) const
+ { return Persp().PerspectiveImpl::InvProject (p, z); }
};
@@ -596,15 +593,13 @@
{
CS::Math::Matrix4 matrix;
CS::Math::Matrix4 invMatrix;
- bool invMatrixDirty;
bool clipPlanesDirty;
csPlane3 clipPlanes[6];
uint32 clipPlanesMask;
- void UpdateInvMatrix ();
csCameraCustomMatrix () : scfImplementationType (this),
- invMatrixDirty (true), clipPlanesDirty (true) {}
+ clipPlanesDirty (true) {}
csCameraCustomMatrix (csCameraBase* other);
csPtr<iCamera> Clone () const
@@ -619,17 +614,17 @@
void SetProjectionMatrix (const CS::Math::Matrix4& m)
{
matrix = m;
+ invMatrix = matrix.GetInverse();
clipPlanesDirty = true;
- invMatrixDirty = true;
BumpCamera();
}
const CS::Math::Matrix4& GetInvProjectionMatrix ()
- {
- UpdateInvMatrix ();
- return invMatrix;
- }
+ { return invMatrix; }
const csPlane3* GetVisibleVolume (uint32& mask);
+
+ virtual csVector2 Project (const csVector3& v) const;
+ virtual csVector3 InvProject (const csVector2& p, float z) const;
};
#include "csutil/deprecated_warn_on.h"
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk
_______________________________________________
Crystal-cvs mailing list
https://lists.sourceforge.net/lists/listinfo/crystal-cvs