/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #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) : mOrigin(org) , mDest(endPoint) , mDirection((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) : mOrigin(org) , mDest(endPoint) , mDirection(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) { mOrigin = org; mDest = endPoint; mDirection = (mDest - mOrigin).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) { mOrigin = org; mDirection = (mDest - mOrigin).GetNormalized(); } /** * Set the destination point of the ray. * @param dest The destination of the ray. */ MCORE_INLINE void SetDest(const AZ::Vector3& dest) { mDest = dest; mDirection = (mDest - mOrigin).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 mOrigin; } /** * 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 mDest; } /** * 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 mDirection; } /** * 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(mDest - mOrigin); } private: AZ::Vector3 mOrigin; /**< The origin of the ray. */ AZ::Vector3 mDest; /**< The destination of the ray. */ AZ::Vector3 mDirection; /**< The normalized direction vector of the ray. */ }; } // namespace MCore