Files
j3ml/include/J3ML/Geometry/Ray.hpp

167 lines
7.6 KiB
C++

/// Josh's 3D Math Library
/// A C++20 Library for 3D Math, Computer Graphics, and Scientific Computing.
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
/// Special Thanks to William Tomasine II and Maxine Hayes.
/// (c) 2024 Redacted Software
/// This work is dedicated to the public domain.
/// @file Ray.hpp
/// @desc The Ray geometry object. Used for Raycasting - intersection testing against geometric solids.
/// @edit 2024-07-06
#pragma once
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <vector>
#include "TriangleMesh.hpp"
#include "Frustum.hpp"
#include "OBB.hpp"
namespace J3ML::Geometry
{
using J3ML::LinearAlgebra::Vector3;
// RaycastResult structure containing the first object the ray collides with,
// the surface intersection point,
// and the surface normal at the point of intersection.
struct RaycastResult
{
Vector3 Intersection;
Vector3 SurfaceNormal;
bool Hit;
Shape* Target;
static RaycastResult NoHit() { return {Vector3::NaN, Vector3::NaN, false, nullptr};}
};
/// A ray in 3D space is a line that starts from an origin point and extends to infinity in one direction
class Ray
{
public: // Properties
// The position of this ray.
Vector3 Origin;
// The normalized direction vector of this ray.
// @note: For proper functionality, this direction vector needs to always be normalized
Vector3 Direction;
public: // Constructors
// The default constructor does not initialize any members of this class.
/** This means that the values of the members pos and dir are undefined after creating a new Ray using this
default constructor. Remember to assign to them before use.
@see pos, dir. */
Ray() = default;
/// Constructs a new ray by explicitly specifying the member variables.
/** @param pos The origin position of the ray.
@param dir The direction of the ray. This vector must be normalized, this function will not normalize
the vector for you (for performance reasons).
@see pos, dir. */
Ray(const Vector3& pos, const Vector3& dir);
/// Converts a Line to a Ray.
/** This conversion simply copies the members pos and dir over from the given Line to this Ray.
This meansthat the new ray starts at the same position, but only extends to one direction in space, instead of two.
@see class Line, ToLine() */
explicit Ray(const Line& line);
/// Converts a LineSegment to a Ray.
/** This constructor sets pos = lineSegment.a, and dir = (lineSegment.b - lineSegment.a).Normalized()
@see class LineSegment(), ToLineSegment() */
explicit Ray(const LineSegment& lineSegment);
public: // Methods
bool IsFinite() const;
/// Gets a point along the ray at the given distance.
/** Use this function to convert a 1D parametric point along the ray to a 3D point in the linear space.
@param distance The point to compute. GetPoint(0) will return pos. GetPoint(t) will return a point
at distance |t| from pos. Passing in negative values is allowed, but in that case, the
returned point does not actually lie on this Ray.
@return pos + distance * dir
@see pos, dir. */
Vector3 GetPoint(float distance) const;
void Translate(const Vector3& offset);
void Transform(const Matrix3x3& transform);
void Transform(const Matrix4x4& transform);
void Transform(const Quaternion& transform);
bool Contains(const Vector3& point, float distanceThreshold = 1e-3f) const;
bool Contains(const LineSegment& lineSegment, float distanceThreshhold = 1e-3f) const;
bool Equals(const Ray& otherRay, float epsilon = 1e-3f);
bool BitEquals(const Ray& other);
float Distance(const Ray& other) const;
float Distance(const Ray& other, float& d) const;
float Distance(const Ray& other, float&d, float& d2) const;
float Distance(const Line& other) const;
float Distance(const Line& other, float& d) const;
float Distance(const Line& other, float& d, float& d2) const;
float Distance(const LineSegment& other) const;
float Distance(const LineSegment& other, float& d) const;
float Distance(const LineSegment& other, float& d, float& d2) const;
float Distance(const Sphere& other) const;
float Distance(const Capsule& other) const;
Vector3 ClosestPoint(const Vector3& targetPoint) const;
Vector3 ClosestPoint(const Vector3 &targetPoint, float &d) const;
Vector3 ClosestPoint(const Ray& other) const;
Vector3 ClosestPoint(const Ray& other, float& d) const;
Vector3 ClosestPoint(const Ray& other, float& d, float& d2) const;
Vector3 ClosestPoint(const Line& other) const;
Vector3 ClosestPoint(const Line& other, float& d) const;
Vector3 ClosestPoint(const Line& other, float& d, float& d2) const;
Vector3 ClosestPoint(const LineSegment& other) const;
Vector3 ClosestPoint(const LineSegment& other, float& d) const;
Vector3 ClosestPoint(const LineSegment&, float &d, float &d2) const;
bool Intersects(const Triangle& triangle, float* d, Vector3* intersectionPoint) const;
bool Intersects(const Triangle& triangle) const;
bool Intersects(const Plane& plane, float* d);
bool Intersects(const Plane& plane) const;
bool Intersects(const Sphere& s, Vector3* intersectionPoint, Vector3* intersectionNormal, float* d) const;
bool Intersects(const Sphere& s) const;
bool Intersects(const AABB& aabb, float& dNear, float& dFar) const;
bool Intersects(const AABB& aabb) const;
bool Intersects(const OBB& aabb, float& dNear, float& dFar) const;
bool Intersects(const OBB& aabb) const;
bool Intersects(const Capsule& aabb) const;
bool Intersects(const Polygon& aabb) const;
bool Intersects(const Frustum& aabb) const;
bool Intersects(const Polyhedron& aabb) const;
Line ToLine() const;
LineSegment ToLineSegment(float d) const;
LineSegment ToLineSegment(float dStart, float dEnd) const;
RaycastResult Cast(const Triangle& target, float maxDistance = 99999999);
RaycastResult Cast(const Plane& target, float maxDistance = 99999999);
RaycastResult Cast(const AABB& target, float maxDistance = 99999999);
// https://gdbooks.gitbooks.io/3dcollisions/content/Chapter3/raycast_sphere.html
RaycastResult Cast(const Sphere& target, float maxDistance = 99999999);
RaycastResult Cast(const OBB& target, float maxDistance = 99999999);
RaycastResult Cast(const Capsule& target, float maxDistance = 99999999);
RaycastResult Cast(const Frustum& target, float maxDistance = 99999999);
RaycastResult Cast(const TriangleMesh& target, float maxDistance = 9999999);
// Returns a RaycastResult structure containing the first object the ray collides with,
// the surface intersection point,
// and the surface normal at the point of intersection.
RaycastResult Cast(std::vector<Shape> shapes, float maxDistance = 99999999);
void ProjectToAxis(const Vector3 &direction, float &outMin, float &outMax) const;
[[nodiscard]] std::string ToString() const {
return std::format("Ray(origin:[{}], direction:[{}])", Origin.ToString(), Direction.ToString());
}
};
inline std::ostream& operator << (std::ostream& o, const Ray& ray) {
o << ray.ToString();
return o;
}
}