Frustum partial implementation.
This commit is contained in:
@@ -142,175 +142,250 @@ namespace J3ML::Geometry
|
||||
Matrix4x4 viewProjectionMatrix;
|
||||
public:
|
||||
|
||||
/// The default constructor creates an uninitialized Frustum object.
|
||||
/** This means that the values of the members type, projectiveSpace, handedness, pos, front, up, nearPlaneDistance, farPlaneDistance, horizontalFov/orthographicWidth and
|
||||
verticalFov/orthographicHeight are all NaN after creating a new Frustum using this
|
||||
default constructor. Remember to assign to them before use.
|
||||
@note As an exception to other classes in MathGeoLib, this class initializes its members to NaNs, whereas the other classes leave the members uninitialized. This difference
|
||||
is because the Frustum class implements a caching mechanism where world, projection and viewProj matrices are recomputed on demand, which does not work nicely together
|
||||
if the defaults were uninitialized.
|
||||
*/
|
||||
/// The default constructor creates an uninitialized Frustum object.
|
||||
/** This means that the values of the members type, projectiveSpace, handedness, pos, front, up, nearPlaneDistance, farPlaneDistance, horizontalFov/orthographicWidth and
|
||||
verticalFov/orthographicHeight are all NaN after creating a new Frustum using this
|
||||
default constructor. Remember to assign to them before use.
|
||||
@note As an exception to other classes in MathGeoLib, this class initializes its members to NaNs, whereas the other classes leave the members uninitialized. This difference
|
||||
is because the Frustum class implements a caching mechanism where world, projection and viewProj matrices are recomputed on demand, which does not work nicely together
|
||||
if the defaults were uninitialized. */
|
||||
Frustum();
|
||||
|
||||
/// Quickly returns an arbitrary point inside this Frustum. Used in GJK intersection test.
|
||||
inline Vector3 AnyPointFast() const { return CornerPoint(0); }
|
||||
|
||||
static Frustum CreateFrustumFromCamera(const CoordinateFrame& cam, float aspect, float fovY, float zNear, float zFar);
|
||||
public:
|
||||
|
||||
|
||||
/// Quickly returns an arbitrary point inside this Frustum. Used in GJK intersection test.
|
||||
[[nodiscard]] Vector3 AnyPointFast() const { return CornerPoint(0); }
|
||||
|
||||
|
||||
/// Returns the tightest AABB that contains this Frustum.
|
||||
/** This function computes the optimal minimum volume AABB that encloses this Frustum.
|
||||
@note Since an AABB cannot generally represent a Frustum, this conversion is not exact, but the returned AABB
|
||||
specifies a larger volume.
|
||||
@see MinimalEnclosingOBB(), ToPolyhedron(). */
|
||||
AABB MinimalEnclosingAABB() const;
|
||||
[[nodiscard]] AABB MinimalEnclosingAABB() const;
|
||||
|
||||
[[nodiscard]] bool IsFinite() const;
|
||||
|
||||
/// Returns the tightest OBB that encloses this Frustum.
|
||||
/** This function computes the optimal minimum volume OBB that encloses this Frustum.
|
||||
@note If the type of this frustum is Perspective, this conversion is not exact, but the returned OBB specifies
|
||||
a larger volume. If the type of this Frustum is orthographic, this conversion is exact, since the shape of an
|
||||
orthographic Frustum is an OBB.
|
||||
@see MinimalEnclosingAABB(), ToPolyhedron(). */
|
||||
OBB MinimalEnclosingOBB() const;
|
||||
[[nodiscard]] OBB MinimalEnclosingOBB(float expandGuardband = 1e-5f) const;
|
||||
|
||||
/// Sets the type of this Frustum.
|
||||
/** @note Calling this function recomputes the cached view and projection matrices of this Frustum.
|
||||
@see SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), ProjectiveSpace(), Handedness(). */
|
||||
void SetKind(FrustumProjectiveSpace projectiveSpace, FrustumHandedness handedness);
|
||||
/// Sets the depth clip distances of this Frustum.
|
||||
/** @param nearPlaneDistance The z distance from the eye point to the position of the Frustum near clip plane. Always pass a positive value here.
|
||||
@param farPlaneDistance The z distance from the eye point to the position of the Frustum far clip plane. Always pass a value that is larger than nearClipDistance.
|
||||
/** @param n The z distance from the eye point to the position of the Frustum near clip plane. Always pass a positive value here.
|
||||
@param f The z distance from the eye point to the position of the Frustum far clip plane. Always pass a value that is larger than nearClipDistance.
|
||||
@note Calling this function recomputes the cached projection matrix of this Frustum.
|
||||
@see SetKind(), SetFrame(), SetPos(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), NearPlaneDistance(), FarPlaneDistance(). */
|
||||
void SetViewPlaneDistances(float nearPlaneDistance, float farPlaneDistance);
|
||||
void SetViewPlaneDistances(float n, float f);
|
||||
|
||||
/// Specifies the full coordinate space of this Frustum in one call.
|
||||
/** @note Calling this function recomputes the cached world matrix of this Frustum.
|
||||
@note As a micro-optimization, prefer this function over the individual SetPos/SetFront/SetUp functions if you need to do a batch of two or more changes, to avoid
|
||||
redundant recomputation of the world matrix.
|
||||
@see SetKind(), SetViewPlaneDistances(), SetPos(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), Pos(), Front(), Up(). */
|
||||
void SetFrame(const Vector3& pos, const Vector3& front, const Vector3& up);
|
||||
|
||||
/// Sets the world-space position of this Frustum.
|
||||
/** @note Calling this function recomputes the cached world matrix of this Frustum.
|
||||
@see SetKind(), SetViewPlaneDistances(), SetFrame(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), Pos(). */
|
||||
void SetPos(const Vector3& pos);
|
||||
|
||||
/// Sets the world-space direction the Frustum eye is looking towards.
|
||||
/** @note Calling this function recomputes the cached world matrix of this Frustum.
|
||||
@see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetUp(), SetPerspective(), SetOrthographic(), Front(). */
|
||||
void SetFront(const Vector3& front);
|
||||
|
||||
/// Sets the world-space camera up direction vector of this Frustum.
|
||||
/** @note Calling this function recomputes the cached world matrix of this Frustum.
|
||||
@see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetPerspective(), SetOrthographic(), Up(). */
|
||||
void SetUp(const Vector3& up);
|
||||
|
||||
/// Makes this Frustum use a perspective projection formula with the given FOV parameters.
|
||||
/** A Frustum that uses the perspective projection is shaped like a pyramid that is cut from the top, and has a
|
||||
base with a rectangular area.
|
||||
@note Calling this function recomputes the cached projection matrix of this Frustum.
|
||||
@see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetUp(), SetOrthographic(), HorizontalFov(), VerticalFov(), SetHorizontalFovAndAspectRatio(), SetVerticalFovAndAspectRatio(). */
|
||||
void SetPerspective(float horizontalFov, float verticalFov);
|
||||
void SetPerspective(float h, float v);
|
||||
|
||||
/// Makes this Frustum use an orthographic projection formula with the given FOV parameters.
|
||||
/** A Frustum that uses the orthographic projection is shaded like a cube (an OBB).
|
||||
@note Calling this function recomputes the cached projection matrix of this Frustum.
|
||||
@see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetUp(), SetOrthographic(), OrthographicWidth(), OrthographicHeight(). */
|
||||
void SetOrthographic(float orthographicWidth, float orthographicHeight);
|
||||
void SetOrthographic(float w, float h);
|
||||
|
||||
/// Returns the handedness of the projection formula used by this Frustum.
|
||||
/** @see SetKind(), FrustumHandedness. */
|
||||
FrustumHandedness Handedness() const { return handedness; }
|
||||
[[nodiscard]] FrustumHandedness Handedness() const { return handedness; }
|
||||
/// Returns the type of the projection formula used by this Frustum.
|
||||
/** @see SetPerspective(), SetOrthographic(), FrustumType. */
|
||||
FrustumType Type() const { return type; }
|
||||
[[nodiscard]] FrustumType Type() const { return type; }
|
||||
/// Returns the convention of the post-projective space used by this Frustum.
|
||||
/** @see SetKind(), FrustumProjectiveSpace. */
|
||||
FrustumProjectiveSpace ProjectiveSpace() const { return projectiveSpace;}
|
||||
[[nodiscard]] FrustumProjectiveSpace ProjectiveSpace() const { return projectiveSpace;}
|
||||
/// Returns the world-space position of this Frustum.
|
||||
/** @see SetPos(), Front(), Up(). */
|
||||
const Vector3 &Pos() const {return pos;}
|
||||
[[nodiscard]] const Vector3 &Pos() const {return pos;}
|
||||
/// Returns the world-space camera look-at direction of this Frustum.
|
||||
/** @see Pos(), SetFront(), Up(). */
|
||||
const Vector3 &Front() const { return front; }
|
||||
[[nodiscard]] const Vector3 &Front() const { return front; }
|
||||
/// Returns the world-space camera up direction of this Frustum.
|
||||
/** @see Pos(), Front(), SetUp(). */
|
||||
const Vector3 &Up() const { return up; }
|
||||
[[nodiscard]] const Vector3 &Up() const { return up; }
|
||||
/// Returns the distance from the Frustum eye to the near clip plane.
|
||||
/** @see SetViewPlaneDistances(), FarPlaneDistance(). */
|
||||
float NearPlaneDistance() const { return nearPlaneDistance; }
|
||||
[[nodiscard]] float NearPlaneDistance() const { return nearPlaneDistance; }
|
||||
/// Returns the distance from the Frustum eye to the far clip plane.
|
||||
/** @see SetViewPlaneDistances(), NearPlaneDistance(). */
|
||||
float FarPlaneDistance() const { return farPlaneDistance;}
|
||||
[[nodiscard]] float FarPlaneDistance() const { return farPlaneDistance;}
|
||||
/// Returns the horizontal field-of-view used by this Frustum, in radians.
|
||||
/** @note Calling this function when the Frustum is not set to use perspective projection will return values that are meaningless.
|
||||
@see SetPerspective(), Type(), VerticalFov(). */
|
||||
float HorizontalFov() const { return horizontalFov;}
|
||||
[[nodiscard]] float HorizontalFov() const { return horizontalFov;}
|
||||
/// Returns the vertical field-of-view used by this Frustum, in radians.
|
||||
/** @note Calling this function when the Frustum is not set to use perspective projection will return values that are meaningless.
|
||||
@see SetPerspective(), Type(), HorizontalFov(). */
|
||||
float VerticalFov() const { return verticalFov;}
|
||||
[[nodiscard]] float VerticalFov() const { return verticalFov;}
|
||||
/// Returns the world-space width of this Frustum.
|
||||
/** @note Calling this function when the Frustum is not set to use orthographic projection will return values that are meaningless.
|
||||
@see SetOrthographic(), Type(), OrthographicHeight(). */
|
||||
float OrthographicWidth() const { return orthographicWidth; }
|
||||
[[nodiscard]] float OrthographicWidth() const { return orthographicWidth; }
|
||||
/// Returns the world-space height of this Frustum.
|
||||
/** @note Calling this function when the Frustum is not set to use orthographic projection will return values that are meaningless.
|
||||
@see SetOrthographic(), Type(), OrthographicWidth(). */
|
||||
float OrthograhpicHeight() const { return orthographicHeight; }
|
||||
[[nodiscard]] float OrthograhpicHeight() const { return orthographicHeight; }
|
||||
/// Returns the number of line segment edges that this Frustum is made up of, which is always 12.
|
||||
/** This function is used in template-based algorithms to provide an unified API for iterating over the features of a Polyhedron. */
|
||||
int NumEdges() const { return 12; }
|
||||
static int NumEdges() { return 12; }
|
||||
/// Returns the aspect ratio of the view rectangle on the near plane.
|
||||
/** The aspect ratio is the ratio of the width of the viewing rectangle to its height. This can also be computed by
|
||||
the expression horizontalFov / verticalFov. To produce a proper non-stretched image when rendering, this
|
||||
aspect ratio should match the aspect ratio of the actual render target (e.g. 4:3, 16:9 or 16:10 in full screen mode).
|
||||
@see horizontalFov, verticalFov. */
|
||||
float AspectRatio() const;
|
||||
[[nodiscard]] float AspectRatio() const;
|
||||
|
||||
/// Makes this Frustum use a perspective projection formula with the given horizontal FOV parameter and aspect ratio.
|
||||
/** Specifies the horizontal and vertical field-of-view values for this Frustum based on the given horizontal FOV
|
||||
and the screen size aspect ratio.
|
||||
@note Calling this function recomputes the cached projection matrix of this Frustum.
|
||||
@see SetPerspective(), SetVerticalFovAndAspectRatio(). */
|
||||
void SetHorizontalFovAndAspectRatio(float horizontalFov, float aspectRatio);
|
||||
void SetHorizontalFovAndAspectRatio(float hFov, float aspectRatio);
|
||||
|
||||
/// Makes this Frustum use a perspective projection formula with the given vertical FOV parameter and aspect ratio.
|
||||
/** Specifies the horizontal and vertical field-of-view values for this Frustum based on the given vertical FOV
|
||||
and the screen size aspect ratio.
|
||||
@note Calling this function recomputes the cached projection matrix of this Frustum.
|
||||
@see SetPerspective(), SetHorizontalFovAndAspectRatio(). */
|
||||
void SetVerticalFovAndAspectRatio(float verticalFov, float aspectRatio);
|
||||
void SetVerticalFovAndAspectRatio(float vFov, float aspectRatio);
|
||||
|
||||
Vector3 CornerPoint(int cornerIndex) const;
|
||||
/// Finds a ray in world space that originates at the eye point and looks in the given direction inside the frustum.
|
||||
/** The (x,y) coordinate specifies the normalized viewport coordinate through which the ray passes.
|
||||
Both x and y must be in the range [-1,1].
|
||||
Specifying (-1, -1) returns the bottom-left corner of the near plane.
|
||||
The point (1, 1) corresponds to the top-right corner of the near plane. */
|
||||
Ray UnProject(float x, float y) const;
|
||||
|
||||
Vector3 NearPlanePos(float x, float y) const;
|
||||
Vector3 FarPlanePos(float x, float y) const;
|
||||
Ray UnProject(const Vector2& xy) const;
|
||||
|
||||
Ray UnProjectFromNearPlane(float x, float y) const;
|
||||
|
||||
[[nodiscard]] LineSegment UnProjectLineSegment(float x, float y) const;
|
||||
|
||||
Vector3 PointInside(float x, float y, float z) const;
|
||||
|
||||
Vector3 PointInside(const Vector3& xyz) const;
|
||||
|
||||
|
||||
[[nodiscard]] Vector3 CenterPoint() const;
|
||||
|
||||
[[nodiscard]] Vector3 CornerPoint(int cornerIndex) const;
|
||||
|
||||
/// Returns a point on the near plane.
|
||||
/** @param x A value in the range [-1, 1].
|
||||
@param y A value in the range [-1, 1].
|
||||
Specifying (-1, -1) returns the bottom-left corner of the near plane.
|
||||
The point (1, 1) corresponds to the top-right corner of the near plane.
|
||||
@note This coordinate space is called the normalized viewport coordinate space.
|
||||
@see FarPlanePos(). */
|
||||
[[nodiscard]] Vector3 NearPlanePos(float x, float y) const;
|
||||
[[nodiscard]] Vector3 NearPlanePos(const Vector2& point) const;
|
||||
|
||||
/// Returns a point on the far plane.
|
||||
/** @param x A value in the range [-1, 1].
|
||||
@param y A value in the range [-1, 1].
|
||||
Specifying (-1, -1) returns the bottom-left corner of the far plane.
|
||||
The point (1, 1) corresponds to the top-right corner of the far plane.
|
||||
@note This coordinate space is called the normalized viewport coordinate space.
|
||||
@see NearPlanePos(). */
|
||||
[[nodiscard]] Vector3 FarPlanePos(float x, float y) const;
|
||||
[[nodiscard]] Vector3 FarPlanePos(const Vector2& point) const;
|
||||
|
||||
/// Computes the direction vector that points logically to the right-hand side of the Frustum.
|
||||
/** This vector together with the member variables 'front' and 'up' form the orthonormal basis of the view frustum.
|
||||
@see pos, front. */
|
||||
Vector3 WorldRight() const;
|
||||
[[nodiscard]] Vector3 WorldRight() const;
|
||||
|
||||
[[nodiscard]] Plane TopPlane() const; ///< [similarOverload: LeftPlane] [hideIndex]
|
||||
[[nodiscard]] Plane BottomPlane() const; ///< [similarOverload: LeftPlane] [hideIndex]
|
||||
[[nodiscard]] Plane RightPlane() const; ///< [similarOverload: LeftPlane] [hideIndex]
|
||||
|
||||
|
||||
Plane TopPlane() const; ///< [similarOverload: LeftPlane] [hideIndex]
|
||||
Plane BottomPlane() const; ///< [similarOverload: LeftPlane] [hideIndex]
|
||||
Plane RightPlane() const; ///< [similarOverload: LeftPlane] [hideIndex]
|
||||
/// Returns the plane equation of the specified side of this Frustum.
|
||||
/** The normal vector of the returned plane points outwards from the volume inside the frustum.
|
||||
This means the negative half-space of the Frustum is the space inside the Frustum.
|
||||
[indexTitle: Left/Right/Top/BottomPlane]
|
||||
@see NearPlane(), FarPlane(), GetPlane(), GetPlanes(). */
|
||||
Plane LeftPlane() const;
|
||||
[[nodiscard]] Plane LeftPlane() const;
|
||||
|
||||
/// Computes the plane equation of the far plane of this Frustum. [similarOverload: NearPlane]
|
||||
/** The normal vector of the returned plane points outwards from the volume inside the frustum, i.e. away from the eye point.
|
||||
(towards front). This means the negative half-space of the Frustum is the space inside the Frustum.
|
||||
@see front, FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(), GetPlane(), GetPlanes(). */
|
||||
Plane FarPlane() const;
|
||||
[[nodiscard]] Plane FarPlane() const;
|
||||
|
||||
/// Computes the plane equation of the near plane of this Frustum.
|
||||
/** The normal vector of the returned plane points outwards from the volume inside the frustum, i.e. towards the eye point
|
||||
(towards -front). This means the negative half-space of the Frustum is the space inside the Frustum.
|
||||
@see front, FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(), GetPlane(), GetPlanes(). */
|
||||
Plane NearPlane() const;
|
||||
[[nodiscard]] Plane NearPlane() const;
|
||||
|
||||
/// Computes the width of the near plane quad in world space units.
|
||||
/** @see NearPlaneHeight(). */
|
||||
float NearPlaneWidth() const;
|
||||
[[nodiscard]] float NearPlaneWidth() const;
|
||||
|
||||
/// Computes the height of the near plane quad in world space units.
|
||||
/** @see NearPlaneHeight(). */
|
||||
float NearPlaneHeight() const;
|
||||
[[nodiscard]] float NearPlaneHeight() const;
|
||||
|
||||
|
||||
/// Returns the specified plane of this frustum.
|
||||
/** The normal vector of the returned plane points outwards from the volume inside the frustum.
|
||||
@param faceIndex A number in the range [0,5], which returns the plane at the selected index from
|
||||
the array { near, far, left, right, top, bottom} */
|
||||
Plane GetPlane(int faceIndex) const;
|
||||
|
||||
/// Returns all six planes of this Frustum.
|
||||
/** The planes will be output in the order { near, far, left, right, top, bottom }.
|
||||
@param outArray [out] A pointer to an array of at least 6 elements. This pointer will receive the planes of this Frustum.
|
||||
This pointer may not be null.
|
||||
@see GetPlane(), NearPlane(), FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(). */
|
||||
void GetPlanes(Plane *outArray) const;
|
||||
|
||||
|
||||
/// Moves this Frustum by the given offset vector.
|
||||
/** @note This function operates in-place.
|
||||
@param offset The world space offset to apply to the position of this Frustum.
|
||||
@see Transform(). */
|
||||
void Translate(const Vector3& offset);
|
||||
|
||||
/// Applies a transformation to this Frustum.
|
||||
/** @param transform The transformation to apply to this Frustum. This transformation must be
|
||||
* affine, and must contain an orthogoal set of column vectors (may not contain shear or projection).
|
||||
@@ -325,23 +400,56 @@ namespace J3ML::Geometry
|
||||
/** This function returns a Polyhedron representation of this Frustum. This conversion is exact, meaning that the returned
|
||||
Polyhedron represents exactly the same set of points that this Frustum does.
|
||||
@see MinimalEnclosingAABB(), MinimalEnclosingOBB(). */
|
||||
Polyhedron ToPolyhedron() const;
|
||||
[[nodiscard]] Polyhedron ToPolyhedron() const;
|
||||
|
||||
/// Converts this Frustum to a PBVolume.
|
||||
/** This function returns a plane-bounded volume representation of this Frustum. The conversion is exact, meaning that the
|
||||
returned PBVolume<6> represents exactly the same set of points that this Frustum does.
|
||||
@see ToPolyhedron(). */
|
||||
//PBVolume<6> ToPBVolume() const;
|
||||
[[nodiscard]] PBVolume<6> ToPBVolume() const;
|
||||
|
||||
|
||||
Matrix4x4 ViewProjMatrix() const { return viewProjectionMatrix; }
|
||||
Matrix4x4 ComputeViewProjMatrix() const;
|
||||
[[nodiscard]] Vector3 Project(const Vector3& point) const;
|
||||
|
||||
/// Computes the matrix that transforms from the world (global) space to the projection space of this Frustum.
|
||||
/** The matrix computed by this function is simply the concatenation ProjectionMatrix()*ViewMatrix(). This order
|
||||
of concatenation follows the M*v convention of transforming vectors (as opposed to the v*M convention). This
|
||||
multiplication order is used, since the matrices ProjectionMatrix() and ViewMatrix() also follow the M*v convention.
|
||||
@return A matrix that performs the world->view->proj transformation. This matrix is neither invertible or
|
||||
orthonormal. The returned matrix is built to use the convention Matrix * vector
|
||||
to map a point between these spaces. (as opposed to the convention v*M).
|
||||
@see WorldMatrix(), ViewMatrix(), ProjectionMatrix(). */
|
||||
[[nodiscard]] Matrix4x4 ViewProjMatrix() const;
|
||||
[[nodiscard]] Matrix4x4 ComputeViewProjMatrix() const;
|
||||
|
||||
|
||||
/// Computes the matrix that transforms from the view space to the world (global) space of this Frustum.
|
||||
/** @note The returned matrix is the inverse of the matrix returned by ViewMatrix().
|
||||
@return An orthonormal affine matrix that performs the view->world transformation. The returned
|
||||
matrix is built to use the convention Matrix * vector to map a point between these spaces.
|
||||
(as opposed to the convention v*M).
|
||||
@see ViewMatrix(), ProjectionMatrix(), ViewProjMatrix(). */
|
||||
[[nodiscard]] Matrix4x4 WorldMatrix() const;
|
||||
[[nodiscard]] Matrix4x4 ComputeWorldMatrix() const;
|
||||
|
||||
/// Computes the matrix that transforms from the world (global) space to the view space of this Frustum.
|
||||
/** @note The returned matrix is the inverse of the matrix returned by WorldMatrix().
|
||||
@return An orthonormal affine matrix that performs the world->view transformation. The returned
|
||||
matrix is built to use the convention Matrix * vector to map a point between these spaces.
|
||||
(as opposed to the convention v*M).
|
||||
@see WorldMatrix(), ProjectionMatrix(), ViewProjMatrix(). */
|
||||
[[nodiscard]] Matrix4x4 ViewMatrix() const;
|
||||
[[nodiscard]] Matrix4x4 ComputeViewMatrix() const;
|
||||
|
||||
|
||||
/// Computes the matrix that projects from the view space to the projection space of this Frustum.
|
||||
/** @return A projection matrix that performs the view->proj transformation. This matrix is neither
|
||||
invertible or orthonormal. The returned matrix is built to use the convention Matrix * vector
|
||||
to map a point between these spaces. (as opposed to the convention v*M).
|
||||
@see WorldMatrix(), ViewMatrix(), ViewProjMatrix(). */
|
||||
[[nodiscard]] Matrix4x4 ProjectionMatrix() const;
|
||||
[[nodiscard]] Matrix4x4 ComputeProjectionMatrix() const;
|
||||
|
||||
Vector3 Project(const Vector3& point) const {
|
||||
Vector4 projectedPoint = ViewProjMatrix().Mul(Vector4(point, 1.f));
|
||||
projectedPoint.NormalizeW();
|
||||
return projectedPoint.XYZ();
|
||||
}
|
||||
|
||||
/// Tests if the given object is fully contained inside this Frustum.
|
||||
/** This function returns true if the given object lies inside this Frustum, and false otherwise.
|
||||
@@ -349,26 +457,27 @@ namespace J3ML::Geometry
|
||||
due to float inaccuracies, this cannot generally be relied upon.
|
||||
@todo Add Contains(Circle/Disc/Sphere/Capsule).
|
||||
@see Distance(), Intersects(), ClosestPoint(). */
|
||||
bool Contains(const Vector3 &point) const {
|
||||
const float eps = 1e-3f;
|
||||
const float position = 1.f + eps;
|
||||
const float neg = -position;
|
||||
Vector3 projected = Project(point);
|
||||
}
|
||||
bool Contains(const LineSegment &lineSegment) const;
|
||||
bool Contains(const Triangle &triangle) const;
|
||||
bool Contains(const Polygon &polygon) const;
|
||||
bool Contains(const AABB &aabb) const;
|
||||
bool Contains(const OBB &obb) const;
|
||||
bool Contains(const Frustum &frustum) const;
|
||||
bool Contains(const Polyhedron &polyhedron) const;
|
||||
[[nodiscard]] bool Contains(const Vector3 &point) const;
|
||||
[[nodiscard]] bool Contains(const LineSegment &lineSegment) const;
|
||||
[[nodiscard]] bool Contains(const Triangle &triangle) const;
|
||||
[[nodiscard]] bool Contains(const Polygon &polygon) const;
|
||||
[[nodiscard]] bool Contains(const AABB &aabb) const;
|
||||
[[nodiscard]] bool Contains(const OBB &obb) const;
|
||||
[[nodiscard]] bool Contains(const Frustum &frustum) const;
|
||||
[[nodiscard]] bool Contains(const Polyhedron &polyhedron) const;
|
||||
|
||||
/// Computes the distance between this Frustum and the given object.
|
||||
/** This function finds the nearest pair of points on this and the given object, and computes their distance.
|
||||
If the two objects intersect, or one object is contained inside the other, the returned distance is zero.
|
||||
@todo Add Frustum::Distance(Line/Ray/LineSegment/Plane/Triangle/Polygon/Circle/Disc/AABB/OBB/Capsule/Frustum/Polyhedron).
|
||||
@see Contains(), Intersects(), ClosestPoint(). */
|
||||
float Distance(const Vector3 &point) const;
|
||||
[[nodiscard]] float Distance(const Vector3 &point) const;
|
||||
|
||||
/// Computes the closest point inside this frustum to the given point.
|
||||
/** If the target point lies inside this Frustum, then that point is returned.
|
||||
@see Distance(), Contains(), Intersects().
|
||||
@todo Add ClosestPoint(Line/Ray/LineSegment/Plane/Triangle/Polygon/Circle/Disc/AABB/OBB/Capsule/Frustum/Polyhedron). */
|
||||
[[nodiscard]] Vector3 ClosestPoint(const Vector3& point) const;
|
||||
|
||||
/// Tests whether this Frustum and the given object intersect.
|
||||
/** Both objects are treated as "solid", meaning that if one of the objects is fully contained inside
|
||||
@@ -377,18 +486,19 @@ namespace J3ML::Geometry
|
||||
The first parameter of this function specifies the other object to test against.
|
||||
@see Contains(), Distance(), ClosestPoint().
|
||||
@todo Add Intersects(Circle/Disc). */
|
||||
bool Intersects(const Ray& ray) const;
|
||||
//bool Intersects(const Line& line) const;
|
||||
bool Intersects(const LineSegment& lineSegment) const;
|
||||
bool Intersects(const AABB& aabb) const;
|
||||
bool Intersects(const OBB& obb) const;
|
||||
bool Intersects(const Plane& plane) const;
|
||||
bool Intersects(const Triangle& triangle) const;
|
||||
bool Intersects(const Polygon& lineSegment) const;
|
||||
bool Intersects(const Sphere& aabb) const;
|
||||
bool Intersects(const Capsule& obb) const;
|
||||
bool Intersects(const Frustum& plane) const;
|
||||
bool Intersects(const Polyhedron& triangle) const;
|
||||
[[nodiscard]] bool Intersects(const Ray& ray) const;
|
||||
[[nodiscard]] bool Intersects(const Line &line) const;
|
||||
[[nodiscard]] bool Intersects(const LineSegment& lineSegment) const;
|
||||
[[nodiscard]] bool Intersects(const AABB& aabb) const;
|
||||
[[nodiscard]] bool Intersects(const OBB& obb) const;
|
||||
[[nodiscard]] bool Intersects(const Plane& plane) const;
|
||||
[[nodiscard]] bool Intersects(const Triangle& triangle) const;
|
||||
[[nodiscard]] bool Intersects(const Polygon& lineSegment) const;
|
||||
[[nodiscard]] bool Intersects(const Sphere& aabb) const;
|
||||
[[nodiscard]] bool Intersects(const Capsule& obb) const;
|
||||
[[nodiscard]] bool Intersects(const Frustum& plane) const;
|
||||
[[nodiscard]] bool Intersects(const Polyhedron& triangle) const;
|
||||
|
||||
/// Projects this Frustum onto the given 1D axis direction vector.
|
||||
/** This function collapses this Frustum onto an 1D axis for the purposes of e.g. separate axis test computations.
|
||||
The function returns a 1D range [outMin, outMax] denoting the interval of the projection.
|
||||
@@ -402,9 +512,23 @@ namespace J3ML::Geometry
|
||||
|
||||
Vector3 ExtremePoint(const Vector3 &direction, float &projectionDistance) const;
|
||||
|
||||
LineSegment Edge(int edgeIndex) const;
|
||||
[[nodiscard]] LineSegment Edge(int edgeIndex) const;
|
||||
|
||||
bool Intersects(const Line &line) const;
|
||||
|
||||
|
||||
/// Maps a point from the normalized viewport space to the screen space
|
||||
/** In normalized viewport space, top-left: (-1, 1), top-right: (1,1), bottom-left: (-1, -1), bottom-right: (-1, 1)
|
||||
In screen space: top-left: (0, 0), top-right: (0, screenWidth-1), bottom-left: (0, screenHeight-1), bottom-right: (screenWidth-1, screenHeight-1).
|
||||
This mapping is affine.
|
||||
@see ScreenToViewportSpace(). */
|
||||
static Vector2 ViewportToScreenSpace(float x, float y, int screenWidth, int screenHeight);
|
||||
static Vector2 ViewportToScreenSpace(const Vector2& point, int screenWidth, int screenHeight);
|
||||
|
||||
/// Maps a point from screen space to normalized viewport space.
|
||||
/** This function computes the inverse function of ViewportToScreenSpace(). This mapping is affine.
|
||||
@see ViewportToScreenSpace(). */
|
||||
static Vector2 ScreenToViewportSpace(float x, float y, int screenWidth, int screenHeight);
|
||||
static Vector2 ScreenToViewportSpace(const Vector2& point, int screenWidth, int screenHeight);
|
||||
};
|
||||
|
||||
Frustum operator * (const Matrix3x3& transform, const Frustum& frustum);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
#include <J3ML/Geometry/Common.h>
|
||||
#include <J3ML/Geometry/Frustum.h>
|
||||
#include <cmath>
|
||||
#include "J3ML/Geometry/AABB.h"
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <J3ML/Geometry/Polyhedron.h>
|
||||
#include <J3ML/Geometry/LineSegment.h>
|
||||
#include <J3ML/Geometry/Polygon.h>
|
||||
#include <J3ML/Algorithm/GJK.h>
|
||||
#include <J3ML/Algorithm/GJK.hpp>
|
||||
|
||||
|
||||
namespace J3ML::Geometry
|
||||
@@ -96,6 +96,22 @@ namespace J3ML::Geometry
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 Frustum::ViewportToScreenSpace(float x, float y, int screenWidth, int screenHeight) {
|
||||
return {(x + 1.f) * 0.5f * (screenWidth - 1.f), (1.f - y) * 0.5f * (screenHeight - 1.f)};
|
||||
}
|
||||
|
||||
Vector2 Frustum::ViewportToScreenSpace(const Vector2 &point, int screenWidth, int screenHeight) {
|
||||
return ViewportToScreenSpace(point.x, point.y, screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
Vector2 Frustum::ScreenToViewportSpace(float x, float y, int screenWidth, int screenHeight) {
|
||||
return {x * 2.f / (screenWidth -1.f) - 1.f, 1.f - y * 2.f / (screenHeight - 1.f)};
|
||||
}
|
||||
|
||||
Vector2 Frustum::ScreenToViewportSpace(const Vector2 &point, int screenWidth, int screenHeight) {
|
||||
return ScreenToViewportSpace(point.x, point.y, screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
Vector3 Frustum::ExtremePoint(const Vector3 &direction, float &projectionDistance) const
|
||||
{
|
||||
Vector3 corners[8];
|
||||
@@ -130,6 +146,19 @@ namespace J3ML::Geometry
|
||||
return frustum;
|
||||
}
|
||||
|
||||
|
||||
PBVolume<6> Frustum::ToPBVolume() const {
|
||||
PBVolume<6> frustumVolume;
|
||||
frustumVolume.p[0] = NearPlane();
|
||||
frustumVolume.p[1] = LeftPlane();
|
||||
frustumVolume.p[2] = RightPlane();
|
||||
frustumVolume.p[3] = TopPlane();
|
||||
frustumVolume.p[4] = BottomPlane();
|
||||
frustumVolume.p[5] = FarPlane();
|
||||
|
||||
return frustumVolume;
|
||||
}
|
||||
|
||||
AABB Frustum::MinimalEnclosingAABB() const {
|
||||
AABB aabb;
|
||||
aabb.SetNegativeInfinity();
|
||||
@@ -138,6 +167,141 @@ namespace J3ML::Geometry
|
||||
return aabb;
|
||||
}
|
||||
|
||||
bool Frustum::IsFinite() const {
|
||||
return pos.IsFinite() && front.IsFinite() && up.IsFinite() && Math::IsFinite(nearPlaneDistance)
|
||||
&& Math::IsFinite(farPlaneDistance) && Math::IsFinite(horizontalFov) && Math::IsFinite(verticalFov);
|
||||
}
|
||||
|
||||
OBB Frustum::MinimalEnclosingOBB(float expandGuardband) const {
|
||||
assert(IsFinite());
|
||||
assert(front.IsNormalized());
|
||||
assert(up.IsNormalized());
|
||||
|
||||
OBB obb;
|
||||
obb.pos = pos + (nearPlaneDistance + farPlaneDistance) * 0.5f * front;
|
||||
obb.axis[1] = up;
|
||||
obb.axis[2] = -front;
|
||||
obb.axis[0] = Vector3::Cross(obb.axis[1], obb.axis[2]);
|
||||
obb.r = Vector3::Zero;
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
obb.Enclose(CornerPoint(i));
|
||||
|
||||
// Expand the generated OBB very slightly to avoid numerical issues when
|
||||
// testing whether this Frustum actually is contained inside the generated OBB.
|
||||
obb.r.x += expandGuardband;
|
||||
obb.r.y += expandGuardband;
|
||||
obb.r.z += expandGuardband;
|
||||
|
||||
return obb;
|
||||
}
|
||||
|
||||
void Frustum::SetKind(FrustumProjectiveSpace projectiveSpace, FrustumHandedness handedness) {
|
||||
|
||||
}
|
||||
|
||||
void Frustum::SetViewPlaneDistances(float n, float f) {
|
||||
nearPlaneDistance = n;
|
||||
farPlaneDistance = f;
|
||||
ProjectionMatrixChanged();
|
||||
|
||||
}
|
||||
|
||||
void Frustum::SetFrame(const Vector3 &pos, const Vector3 &front, const Vector3 &up) {
|
||||
this->pos = pos;
|
||||
this->front = front;
|
||||
this->up = up;
|
||||
WorldMatrixChanged();
|
||||
}
|
||||
|
||||
void Frustum::SetPos(const Vector3 &pos) {
|
||||
this->pos = pos;
|
||||
WorldMatrixChanged();
|
||||
}
|
||||
|
||||
void Frustum::SetFront(const Vector3 &front) {
|
||||
this->front = front;
|
||||
WorldMatrixChanged();
|
||||
}
|
||||
|
||||
void Frustum::SetUp(const Vector3 &up) {
|
||||
this->up = up;
|
||||
WorldMatrixChanged();
|
||||
}
|
||||
|
||||
void Frustum::SetPerspective(float h, float v) {
|
||||
type = FrustumType::Perspective;
|
||||
this->horizontalFov = h;
|
||||
this->verticalFov = v;
|
||||
ProjectionMatrixChanged();
|
||||
}
|
||||
|
||||
void Frustum::SetOrthographic(float w, float h) {
|
||||
type = FrustumType::Orthographic;
|
||||
orthographicWidth = w;
|
||||
orthographicHeight = h;
|
||||
ProjectionMatrixChanged();
|
||||
}
|
||||
|
||||
float Frustum::AspectRatio() const {
|
||||
return Math::Tan(horizontalFov* 0.5f) / Math::Tan(verticalFov*0.5f);
|
||||
}
|
||||
|
||||
void Frustum::SetHorizontalFovAndAspectRatio(float hFov, float aspectRatio) {
|
||||
type = FrustumType::Perspective;
|
||||
horizontalFov = hFov;
|
||||
verticalFov = 2.f * Math::Atan(Math::Tan(hFov * 0.5f) / aspectRatio);
|
||||
ProjectionMatrixChanged();
|
||||
}
|
||||
|
||||
void Frustum::SetVerticalFovAndAspectRatio(float vFov, float aspectRatio) {
|
||||
type = FrustumType::Perspective;
|
||||
verticalFov = vFov;
|
||||
horizontalFov = 2.f * Math::Atan(Math::Tan(vFov * 0.5f) * aspectRatio);
|
||||
return ProjectionMatrixChanged();
|
||||
}
|
||||
|
||||
Ray Frustum::UnProject(float x, float y) const {
|
||||
assert(x >= -1.f);
|
||||
assert(x <= 1.f);
|
||||
assert(y >= -1.f);
|
||||
assert(y <= 1.f);
|
||||
|
||||
if (type == FrustumType::Perspective) {
|
||||
Vector3 nearPlanePos = NearPlanePos(x, y);
|
||||
return Ray(pos, (nearPlanePos - pos).Normalized());
|
||||
} else
|
||||
return UnProjectFromNearPlane(x, y);
|
||||
}
|
||||
|
||||
Ray Frustum::UnProject(const Vector2 &xy) const {
|
||||
return UnProject(xy.x, xy.y);
|
||||
}
|
||||
|
||||
Ray Frustum::UnProjectFromNearPlane(float x, float y) const {
|
||||
return UnProjectLineSegment(x, y).ToRay();
|
||||
}
|
||||
|
||||
LineSegment Frustum::UnProjectLineSegment(float x, float y) const {
|
||||
Vector3 nearPlanePos = NearPlanePos(x, y);
|
||||
Vector3 farPlanePos = FarPlanePos(x, y);
|
||||
return {nearPlanePos, farPlanePos};
|
||||
}
|
||||
|
||||
Vector3 Frustum::PointInside(float x, float y, float z) const {
|
||||
assert(z >= 0.f);
|
||||
assert(z <= 1.f);
|
||||
return UnProjectLineSegment(x, y).GetPoint(z);
|
||||
}
|
||||
|
||||
Vector3 Frustum::PointInside(const Vector3 &xyz) const {
|
||||
return PointInside(xyz.x, xyz.y, xyz.z);
|
||||
}
|
||||
|
||||
Vector3 Frustum::CenterPoint() const {
|
||||
return pos + (nearPlaneDistance + farPlaneDistance) * 0.5f * front;
|
||||
}
|
||||
|
||||
Vector3 Frustum::CornerPoint(int cornerIndex) const {
|
||||
assert(0 <= cornerIndex && cornerIndex <= 7);
|
||||
switch(cornerIndex)
|
||||
@@ -175,6 +339,8 @@ namespace J3ML::Geometry
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 Frustum::NearPlanePos(const Vector2 &point) const { return NearPlanePos(point.x, point.y); }
|
||||
|
||||
Vector3 Frustum::FarPlanePos(float x, float y) const {
|
||||
assert(type == FrustumType::Perspective || type == FrustumType::Orthographic);
|
||||
|
||||
@@ -195,6 +361,134 @@ namespace J3ML::Geometry
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 Frustum::FarPlanePos(const Vector2 &point) const {
|
||||
return FarPlanePos(point.x, point.y);
|
||||
}
|
||||
|
||||
Plane Frustum::TopPlane() const {
|
||||
if (type == FrustumType::Perspective) {
|
||||
Vector3 topSide = front + Math::Tan(verticalFov * 0.5f) * up;
|
||||
Vector3 right = WorldRight();
|
||||
Vector3 topSideNormal = ((handedness == FrustumHandedness::Right) ? Vector3::Cross(right, topSide) : Vector3::Cross(topSide, right)).Normalized();
|
||||
}
|
||||
}
|
||||
|
||||
Plane Frustum::BottomPlane() const {
|
||||
if (type == FrustumType::Perspective) {
|
||||
Vector3 bottomSide = front - Math::Tan(verticalFov * 0.5f) * up;
|
||||
Vector3 left = -WorldRight();
|
||||
Vector3 bottomSideNormal = ((handedness == FrustumHandedness::Right) ? Vector3::Cross(left, bottomSide) : Vector3::Cross(bottomSide, left)).Normalized();
|
||||
} else {
|
||||
return Plane(NearPlanePos(0.f, -1.f), -up);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Plane Frustum::RightPlane() const {
|
||||
if (type == FrustumType::Perspective) {
|
||||
Vector3 right = WorldRight();
|
||||
right.ScaleToLength(Math::Tan(horizontalFov * 0.5f));
|
||||
Vector3 rightSide = front + right;
|
||||
Vector3 rightSideNormal = ((handedness == FrustumHandedness::Right) ? Vector3::Cross(rightSide, up) : Vector3::Cross(up, rightSide)).Normalized();
|
||||
} else {
|
||||
Vector3 right = WorldRight();
|
||||
return Plane(NearPlanePos(1.f,0.f), right.Normalized());
|
||||
}
|
||||
}
|
||||
|
||||
Plane Frustum::LeftPlane() const {
|
||||
if (type == FrustumType::Perspective) {
|
||||
Vector3 left = -WorldRight();
|
||||
left.ScaleToLength(Math::Tan(horizontalFov*0.5f));
|
||||
Vector3 leftSide = front + left;
|
||||
Vector3 leftSideNormal = ((handedness == FrustumHandedness::Right) ? Vector3::Cross(up, leftSide) : Vector3::Cross(leftSide, up)).Normalized();
|
||||
return Plane(pos, leftSideNormal);
|
||||
} else {
|
||||
Vector3 left = -WorldRight();
|
||||
return Plane(NearPlanePos(-1.f, 0.f), left.Normalized());
|
||||
}
|
||||
}
|
||||
|
||||
Plane Frustum::FarPlane() const {
|
||||
return Plane(pos + front * farPlaneDistance, front);
|
||||
}
|
||||
|
||||
Plane Frustum::NearPlane() const {
|
||||
return Plane(pos + front * nearPlaneDistance, -front);
|
||||
}
|
||||
|
||||
float Frustum::NearPlaneWidth() const {
|
||||
if (type == FrustumType::Perspective)
|
||||
return Math::Tan(horizontalFov*0.5f)*2.f * nearPlaneDistance;
|
||||
else
|
||||
return orthographicWidth;
|
||||
}
|
||||
|
||||
float Frustum::NearPlaneHeight() const {
|
||||
if (type == FrustumType::Perspective)
|
||||
return Math::Tan(verticalFov*0.5f) * 2.f * nearPlaneDistance;
|
||||
else
|
||||
return orthographicWidth;
|
||||
}
|
||||
|
||||
Plane Frustum::GetPlane(int faceIndex) const {
|
||||
assert(0 <= faceIndex && faceIndex <= 5);
|
||||
switch(faceIndex)
|
||||
{
|
||||
default: // For release builds where assume() is disabled, always return the first option if out-of-bounds.
|
||||
case 0: return NearPlane();
|
||||
case 1: return FarPlane();
|
||||
case 2: return LeftPlane();
|
||||
case 3: return RightPlane();
|
||||
case 4: return TopPlane();
|
||||
case 5: return BottomPlane();
|
||||
}
|
||||
}
|
||||
|
||||
void Frustum::GetPlanes(Plane *outArray) const {
|
||||
assert(outArray);
|
||||
for (int i = 0; i < 6; ++i)
|
||||
outArray[i] = GetPlane(i);
|
||||
}
|
||||
|
||||
void Frustum::Translate(const Vector3 &offset) {
|
||||
pos += offset;
|
||||
}
|
||||
|
||||
|
||||
void Frustum::Transform(const Matrix3x3& transform) {
|
||||
assert(transform.HasUniformScale());
|
||||
pos = transform * pos;
|
||||
front = transform * front;
|
||||
float scaleFactor = front.Normalize();
|
||||
up = (transform * up).Normalized();
|
||||
nearPlaneDistance *= scaleFactor;
|
||||
farPlaneDistance *= scaleFactor;
|
||||
|
||||
if (type == FrustumType::Orthographic) {
|
||||
orthographicWidth *= scaleFactor;
|
||||
orthographicHeight *= scaleFactor;
|
||||
}
|
||||
}
|
||||
|
||||
void Frustum::Transform(const Matrix4x4& transform) {
|
||||
assert(transform.Row(3).Equals(0,0,0,1));
|
||||
|
||||
assert(transform.HasUniformScale());
|
||||
|
||||
// TODO: This is incorrect. Technically we need only a mat3x4 to implement this operation.
|
||||
// But we choose to not implement this in our code, instead opting for only 3x3 and 4x4.
|
||||
// Care should be taken when using this, it may need to be edited for mathematical correctness
|
||||
Transform(transform.GetRotatePart());
|
||||
}
|
||||
|
||||
void Frustum::Transform(const Quaternion& transform) {
|
||||
Transform(transform.ToMatrix3x3());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Polyhedron Frustum::ToPolyhedron() const {
|
||||
// Note to maintainer: this function is an exact copy of AABB::ToPolyhedron() and OBB::ToPolyhedron().
|
||||
|
||||
@@ -234,6 +528,182 @@ namespace J3ML::Geometry
|
||||
return p;
|
||||
}
|
||||
|
||||
Matrix4x4 Frustum::ViewProjMatrix() const { return viewProjectionMatrix; }
|
||||
|
||||
Matrix4x4 Frustum::ComputeViewProjMatrix() const { return ComputeProjectionMatrix() * ComputeViewMatrix();}
|
||||
|
||||
Vector3 Frustum::Project(const Vector3 &point) const {
|
||||
Vector4 projectedPoint = ViewProjMatrix().Mul(Vector4(point, 1.f));
|
||||
projectedPoint.NormalizeW();
|
||||
return projectedPoint.XYZ();
|
||||
}
|
||||
|
||||
Matrix4x4 Frustum::WorldMatrix() const { return worldMatrix;}
|
||||
|
||||
Matrix4x4 Frustum::ComputeWorldMatrix() const {
|
||||
assert(pos.IsFinite());
|
||||
assert(up.IsNormalized(1e-3f));
|
||||
assert(front.IsNormalized(1e-3f));
|
||||
assert(up.IsPerpendicular(front));
|
||||
|
||||
Matrix4x4 m;
|
||||
m.SetCol3(0, WorldRight().Normalized());
|
||||
m.SetCol3(1, up);
|
||||
if (handedness == FrustumHandedness::Right)
|
||||
m.SetCol3(2, -front);
|
||||
else
|
||||
m.SetCol3(2, front);
|
||||
m.SetCol3(3, pos);
|
||||
assert(!m.HasNegativeScale());
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix4x4 Frustum::ViewMatrix() const { auto m = worldMatrix; m.InverseOrthonormal(); return m; }
|
||||
|
||||
Matrix4x4 Frustum::ComputeViewMatrix() const {
|
||||
Matrix4x4 world = ComputeWorldMatrix();
|
||||
world.InverseOrthonormal();
|
||||
return world;
|
||||
}
|
||||
|
||||
Matrix4x4 Frustum::ProjectionMatrix() const { return projectionMatrix;}
|
||||
|
||||
Matrix4x4 Frustum::ComputeProjectionMatrix() const {
|
||||
if (type == FrustumType::Invalid || projectiveSpace == FrustumProjectiveSpace::Invalid)
|
||||
return Matrix4x4::NaN;
|
||||
|
||||
assert(type == FrustumType::Perspective || type == FrustumType::Orthographic);
|
||||
assert(projectiveSpace == FrustumProjectiveSpace::GL || projectiveSpace == FrustumProjectiveSpace::D3D);
|
||||
assert(handedness == FrustumHandedness::Left || handedness == FrustumHandedness::Right);
|
||||
|
||||
if (type == FrustumType::Perspective) {
|
||||
if (projectiveSpace == FrustumProjectiveSpace::GL) {
|
||||
if (handedness == FrustumHandedness::Right)
|
||||
return Matrix4x4::OpenGLPerspProjRH(nearPlaneDistance, farPlaneDistance, NearPlaneWidth(), NearPlaneHeight());
|
||||
else
|
||||
return Matrix4x4::OpenGLPerspProjLH(nearPlaneDistance, farPlaneDistance, NearPlaneWidth(), NearPlaneHeight());
|
||||
|
||||
} else if (projectiveSpace == FrustumProjectiveSpace::D3D) {
|
||||
if (handedness == FrustumHandedness::Right)
|
||||
return Matrix4x4::D3DPerspProjRH(nearPlaneDistance, farPlaneDistance, NearPlaneWidth(), NearPlaneHeight());
|
||||
else
|
||||
return Matrix4x4::D3DPerspProjLH(nearPlaneDistance, farPlaneDistance, NearPlaneHeight(), NearPlaneHeight());
|
||||
}
|
||||
} else if (type == FrustumType::Orthographic) {
|
||||
if (projectiveSpace == FrustumProjectiveSpace::GL) {
|
||||
if (handedness == FrustumHandedness::Right)
|
||||
return Matrix4x4::OpenGLOrthoProjRH(nearPlaneDistance, farPlaneDistance, orthographicWidth, orthographicHeight);
|
||||
else if (handedness == FrustumHandedness::Left)
|
||||
return Matrix4x4::OpenGLOrthoProjLH(nearPlaneDistance, farPlaneDistance, orthographicWidth, orthographicHeight);
|
||||
|
||||
} else if (projectiveSpace == FrustumProjectiveSpace::D3D) {
|
||||
if (handedness == FrustumHandedness::Right)
|
||||
return Matrix4x4::D3DOrthoProjRH(nearPlaneDistance, farPlaneDistance, orthographicWidth, orthographicHeight);
|
||||
else
|
||||
return Matrix4x4::D3DOrthoProjLH(nearPlaneDistance, farPlaneDistance, orthographicWidth, orthographicHeight);
|
||||
}
|
||||
}
|
||||
assert(false && "Not all values of Frustum were initialized properly! Please initialize correctly before calling Frustum::ProjectionMatrix()!");
|
||||
return Matrix4x4::NaN;
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const Vector3 &point) const {
|
||||
const float eps = 1e-3f;
|
||||
const float position = 1.f + eps;
|
||||
const float neg = -position;
|
||||
Vector3 projected = Project(point);
|
||||
|
||||
if (projectiveSpace == FrustumProjectiveSpace::D3D) {
|
||||
return neg <= projected.x && projected.x <= position &&
|
||||
neg <= projected.y && projected.y <= position &&
|
||||
-eps <= projected.z && projected.z <= position;
|
||||
} else if (projectiveSpace == FrustumProjectiveSpace::GL) {
|
||||
return neg <= projected.x && projected.x <= position &&
|
||||
neg <= projected.y && projected.y <= position &&
|
||||
neg <= projected.z && projected.z <= position;
|
||||
} else {
|
||||
// TODO: Make Frustum::Contains agnostic of the projection settings.
|
||||
assert(false && "Not all values of Frustum were initialized properly! Please initialize correctly before calling Frustum::Contains()!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const LineSegment &lineSegment) const {
|
||||
return Contains(lineSegment.A) && Contains(lineSegment.B);
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const Triangle &triangle) const {
|
||||
return Contains(triangle.V0) && Contains(triangle.V1) && Contains(triangle.V2);
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const Polygon &polygon) const {
|
||||
for (int i = 0; i < polygon.NumVertices(); ++i)
|
||||
if (!Contains(polygon.Vertex(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const AABB &aabb) const {
|
||||
for (int i = 0; i < 8; ++i)
|
||||
if (!Contains(aabb.CornerPoint(i)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const OBB &obb) const {
|
||||
for (int i = 0; i < 8; ++i)
|
||||
if (!Contains(obb.CornerPoint(i)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const Frustum &frustum) const {
|
||||
for (int i = 0; i < 8; ++i)
|
||||
if (!Contains(frustum.CornerPoint(i)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Frustum::Contains(const Polyhedron &polyhedron) const {
|
||||
assert(polyhedron.IsClosed());
|
||||
|
||||
for (int i = 0; i < polyhedron.NumVertices(); ++i)
|
||||
if (!Contains(polyhedron.Vertex(i)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float Frustum::Distance(const Vector3 &point) const {
|
||||
Vector3 pt = ClosestPoint(point);
|
||||
return pt.Distance(point);
|
||||
}
|
||||
|
||||
Vector3 Frustum::ClosestPoint(const Vector3 &point) const {
|
||||
if (type == FrustumType::Orthographic) {
|
||||
float frontHalfSize = (farPlaneDistance - nearPlaneDistance) * 0.5f;
|
||||
float halfWidth = orthographicWidth * 0.5f;
|
||||
float halfHeight = orthographicHeight * 0.5f;
|
||||
|
||||
Vector3 frustumCenter = pos + (frontHalfSize + nearPlaneDistance) * front;
|
||||
Vector3 right = Vector3::Cross(front, up);
|
||||
assert(right.IsNormalized());
|
||||
Vector3 d = point - frustumCenter;
|
||||
Vector3 closestPoint = frustumCenter;
|
||||
|
||||
closestPoint += Math::Clamp(Vector3::Dot(d, front), -frontHalfSize, frontHalfSize) * front;
|
||||
closestPoint += Math::Clamp(Vector3::Dot(d, right), -halfWidth, halfWidth) * right;
|
||||
closestPoint += Math::Clamp(Vector3::Dot(d, up), -halfHeight, halfHeight) * up;
|
||||
|
||||
return closestPoint;
|
||||
} else {
|
||||
return ToPolyhedron().ClosestPoint(point);
|
||||
}
|
||||
}
|
||||
|
||||
bool Frustum::Intersects(const Ray &ray) const {
|
||||
return this->ToPolyhedron().Intersects(ray);
|
||||
}
|
||||
@@ -294,6 +764,22 @@ namespace J3ML::Geometry
|
||||
return this->ToPolyhedron().Intersects(polyhedron);
|
||||
}
|
||||
|
||||
void Frustum::WorldMatrixChanged() {
|
||||
worldMatrix = ComputeWorldMatrix();
|
||||
Matrix4x4 viewMatrix = worldMatrix;
|
||||
viewMatrix.InverseOrthonormal();
|
||||
viewProjectionMatrix = projectionMatrix * viewMatrix;
|
||||
}
|
||||
|
||||
void Frustum::ProjectionMatrixChanged() {
|
||||
projectionMatrix = ComputeProjectionMatrix();
|
||||
if (!Math::IsNotANumber(worldMatrix[0][0])) {
|
||||
Matrix4x4 viewMatrix = worldMatrix;
|
||||
viewMatrix.InverseOrthonormal();
|
||||
viewProjectionMatrix = projectionMatrix * viewMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
Frustum::Frustum()
|
||||
: type(FrustumType::Invalid),
|
||||
pos(Vector3::NaN),
|
||||
@@ -314,4 +800,6 @@ namespace J3ML::Geometry
|
||||
else
|
||||
return Vector3::Cross(up, front);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user