You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/EMotionFX/Code/MCore/Source/Ray.h

172 lines
9.1 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
// include required headers
#include "StandardHeaders.h"
#include "Vector.h"
namespace MCore
{
// forward declarations
class PlaneEq;
class AABB;
class BoundingSphere;
/**
* The Ray template/class.
* A ray is normally an infinite line, starting at a given point (the origin) and heading into a given direction.
* However, this template does not represent an infinite line, but a finite line, since that will be a lot more useful.
* This means we have an origin, which is the starting point and a destination, which is the end point.
* This automatically gives us a direction vector too. So basically we now have a finite ray, which is just a 3D line.
* We can use rays mainly to perform intersection tests. This class provides you with methods to calculate interection information
* between the ray and bounding spheres, axis aligned bounding boxes, triangles and planes. More intersection tests might be added in a later stage.
* Or they have already been added, but this documentation should be updated :)
* Example fields where rays are (often) used are: collision and hit detection, raytracing images, global illumination, lightmap generation, pathtracing,
* real-time volumetric effects, lensflares, etc.
*/
class MCORE_API Ray
{
public:
/**
* Default constructor. Does NOT initialize any members. So this would not be a valid ray.
*/
MCORE_INLINE Ray() {}
/**
* Constructor which sets the start and end point of the ray.
* @param org The origin of the ray.
* @param endPoint The end (destination) point of the ray.
*/
MCORE_INLINE Ray(const AZ::Vector3& org, const AZ::Vector3& endPoint)
: m_origin(org)
, m_dest(endPoint)
, m_direction((endPoint - org).GetNormalized()) {}
/**
* Constructor which sets the origin, destination point and direction.
* @param org The origin of the ray, so where it starts.
* @param endPoint The destination point of the ray, so where it should end.
* @param dir The normalized direction vector of the ray, which should be (endPoint - startPoint).Normalize()
*/
MCORE_INLINE Ray(const AZ::Vector3& org, const AZ::Vector3& endPoint, const AZ::Vector3& dir)
: m_origin(org)
, m_dest(endPoint)
, m_direction(dir) {}
/**
* Set the origin and destination point (end point) of the ray.
* The direction vector will be calculated automatically.
* @param org The origin of the ray, so the start point.
* @param endPoint The destination of the ray, so the end point.
*/
MCORE_INLINE void Set(const AZ::Vector3& org, const AZ::Vector3& endPoint) { m_origin = org; m_dest = endPoint; m_direction = (m_dest - m_origin).GetNormalized(); }
/**
* Set the origin of the ray, so the start point. The direction will automatically be updated as well.
* @param org The origin.
*/
MCORE_INLINE void SetOrigin(const AZ::Vector3& org) { m_origin = org; m_direction = (m_dest - m_origin).GetNormalized(); }
/**
* Set the destination point of the ray.
* @param dest The destination of the ray.
*/
MCORE_INLINE void SetDest(const AZ::Vector3& dest) { m_dest = dest; m_direction = (m_dest - m_origin).GetNormalized(); }
/**
* Get the origin of the ray.
* @result The origin of the ray, so where it starts.
*/
MCORE_INLINE const AZ::Vector3& GetOrigin() const { return m_origin; }
/**
* Get the destination of the ray.
* @result The destination point of the ray, so where it ends.
*/
MCORE_INLINE const AZ::Vector3& GetDest() const { return m_dest; }
/**
* Get the direction of the ray.
* @result The normalized direction vector of the ray, so the direction its heading to.
*/
MCORE_INLINE const AZ::Vector3& GetDirection() const { return m_direction; }
/**
* Perform a ray/sphere intersection test.
* @param s The bounding sphere to test with.
* @param intersectA If not nullptr, the closest intersection point will be stored in this vector, in case of an intersection.
* @param intersectB If not nullptr, the farthest intersection point will be stored in this vector, in case of an intersection.
* @result Returns true when an intersection occured, otherwise false. If there is no intersection, 'intersectA' and 'intersectB' won't be changed.
*/
bool Intersects(const BoundingSphere& s, AZ::Vector3* intersectA = nullptr, AZ::Vector3* intersectB = nullptr) const;
/**
* Perform a ray/plane intersection test.
* @param p The plane to test with.
* @param intersect If not nullptr, the intersection point will be stored in this vector, in case of an intersection.
* @result Returns true when an intersection occured, otherwise false. If there is no intersection, 'intersect' will not be changed.
*/
bool Intersects(const PlaneEq& p, AZ::Vector3* intersect = nullptr) const;
/**
* Perform a ray/triangle intersection test.
* @param p1 The first point of the triangle.
* @param p2 The second point of the triangle.
* @param p3 The third point of the triangle.
* @param intersect If not nullptr, the intersection point will be stored in here, in case of an intersection.
* @param baryU If not nullptr, the 'u' barycentric coordinate will be stored in here.
* @param baryV If not nullptr, the 'v' barycentric coordinate will be stored in here.
* @result Returns true in case of an intersection, otherwise false. If there is no intersection, 'intersect', 'baryU' and 'baryV' will not be modified. You
* can calculate the uv or normal or whatsoever at the intersection point by using the baryU and baryV values.
*
* The calculation goes like:
*
* valueAtIntersectionPoint = (1-u-v)*A + u*B + v*C;
*
* Where u and v are the values written in baryU and baryV and A, B and C are the three 'attributes' on the 3 points of the triangle. For example the three
* vertex normals or uv coordinates or colors. Where A is the attribute linked with 'p1', B the attribute linked with 'p2' and C the attribute linked with 'p3'.
*
* To make it easy for you, we created a function caled BarycentricInterpolate() which takes the required parameters and returns the attribute value at the given
* barycentric coordinates for you. The usage would now be:
*
* valueAtIntersectionPoint = BarycentricInterpolate<Vector3>(u, v, A, B, C);
*
* Where A, B and C could be the vertex normals of the triangle for example.
* You can easily also calculate the intersection point yourself by using the u and v, by doing this:
*
* intersectionPoint = BarycentricInterpolate<Vector3>(u, v, p1, p2, p3);
*
* @see BarycentricInterpolate
*/
bool Intersects(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, AZ::Vector3* intersect = nullptr, float* baryU = nullptr, float* baryV = nullptr) const;
/**
* Perform a ray/AABB (Axis Aligned Bounding Box) intersection test.
* @param b The box to test with.
* @param intersectA If not nullptr, the closest intersection point will be stored in this vector, in case of an intersection.
* @param intersectB If not nullptr, the farthest intersection point will be stored in this vector, in case of an intersection.
* @result Returns true when an intersection occured, otherwise false. If there is no intersection, 'intersectA' and 'intersectB' won't be modified.
*/
bool Intersects(const AABB& b, AZ::Vector3* intersectA = nullptr, AZ::Vector3* intersectB = nullptr) const;
/**
* Calculates the length of the ray.
* @result The length of the ray.
*/
MCORE_INLINE float Length() const { return SafeLength(m_dest - m_origin); }
private:
AZ::Vector3 m_origin; /**< The origin of the ray. */
AZ::Vector3 m_dest; /**< The destination of the ray. */
AZ::Vector3 m_direction; /**< The normalized direction vector of the ray. */
};
} // namespace MCore