// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Platform/Platform.h" #include "Vector3.h" #include "CollisionsHelper.h" struct Viewport; /// /// Represents a three dimensional line based on a point in space and a direction. /// API_STRUCT() struct FLAXENGINE_API Ray { DECLARE_SCRIPTING_TYPE_MINIMAL(Ray); public: /// /// The position in three dimensional space where the ray starts. /// API_FIELD() Vector3 Position; /// /// The normalized direction in which the ray points. /// API_FIELD() Vector3 Direction; public: /// /// Identity ray (at zero origin pointing forwards). /// static Ray Identity; public: /// /// Empty constructor. /// Ray() = default; /// /// Initializes a new instance of the struct. /// /// The ray origin position in 3D space. /// The normalized ray direction in 3D space. Ray(const Vector3& position, const Vector3& direction) : Position(position) , Direction(direction) { } public: String ToString() const; public: FORCE_INLINE bool operator==(const Ray& other) const { return Position == other.Position && Direction == other.Direction; } FORCE_INLINE bool operator!=(const Ray& other) const { return Position != other.Position || Direction != other.Direction; } static bool NearEqual(const Ray& a, const Ray& b) { return Vector3::NearEqual(a.Position, b.Position) && Vector3::NearEqual(a.Direction, b.Direction); } static bool NearEqual(const Ray& a, const Ray& b, Real epsilon) { return Vector3::NearEqual(a.Position, b.Position, epsilon) && Vector3::NearEqual(a.Direction, b.Direction, epsilon); } public: /// /// Gets a point at distance long ray. /// /// The distance from ray origin. /// The calculated point. Vector3 GetPoint(Real distance) const; /// /// Determines if there is an intersection between the current object and a point. /// /// The point to test. /// Whether the two objects intersected. bool Intersects(const Vector3& point) const { return CollisionsHelper::RayIntersectsPoint(*this, point); } /// /// Determines if there is an intersection between the current object and a . /// /// The ray to test. /// Whether the two objects intersected. bool Intersects(const Ray& ray) const { Vector3 point; return CollisionsHelper::RayIntersectsRay(*this, ray, point); } /// /// Determines if there is an intersection between the current object and a . /// /// The ray to test. /// When the method completes, contains the point of intersection, or if there was no intersection. /// /// Whether the two objects intersected. bool Intersects(const Ray& ray, Vector3& point) const { return CollisionsHelper::RayIntersectsRay(*this, ray, point); } /// /// Determines if there is an intersection between the current object and a . /// /// The plane to test /// Whether the two objects intersected. bool Intersects(const Plane& plane) const { Real distance; return CollisionsHelper::RayIntersectsPlane(*this, plane, distance); } /// /// Determines if there is an intersection between the current object and a . /// /// The plane to test. /// When the method completes, contains the distance of the intersection, or 0 if there was no intersection. /// Whether the two objects intersected. bool Intersects(const Plane& plane, Real& distance) const { return CollisionsHelper::RayIntersectsPlane(*this, plane, distance); } /// /// Determines if there is an intersection between the current object and a . /// /// The plane to test. /// When the method completes, contains the point of intersection, or if there was no intersection. /// Whether the two objects intersected. bool Intersects(const Plane& plane, Vector3& point) const { return CollisionsHelper::RayIntersectsPlane(*this, plane, point); } /// /// Determines if there is an intersection between the current object and a triangle. /// /// The first vertex of the triangle to test. /// The second vertex of the triangle to test. /// The third vertex of the triangle to test. /// Whether the two objects intersected. bool Intersects(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3) const { Real distance; return CollisionsHelper::RayIntersectsTriangle(*this, vertex1, vertex2, vertex3, distance); } /// /// Determines if there is an intersection between the current object and a triangle. /// /// The first vertex of the triangle to test. /// The second vertex of the triangle to test. /// The third vertex of the triangle to test. /// When the method completes, contains the distance of the intersection, or 0 if there was no intersection. /// Whether the two objects intersected. bool Intersects(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Real& distance) const { return CollisionsHelper::RayIntersectsTriangle(*this, vertex1, vertex2, vertex3, distance); } /// /// Determines if there is an intersection between the current object and a triangle. /// /// The first vertex of the triangle to test. /// The second vertex of the triangle to test. /// The third vertex of the triangle to test. /// When the method completes, contains the point of intersection, or if there was no intersection. /// Whether the two objects intersected. bool Intersects(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& point) const { return CollisionsHelper::RayIntersectsTriangle(*this, vertex1, vertex2, vertex3, point); } /// /// Determines if there is an intersection between the current object and a . /// /// The box to test. /// Whether the two objects intersected. bool Intersects(const BoundingBox& box) const { Real distance; return CollisionsHelper::RayIntersectsBox(*this, box, distance); } /// /// Determines if there is an intersection between the current object and a . /// /// The box to test. /// When the method completes, contains the distance of the intersection, or 0 if there was no intersection. /// Whether the two objects intersected. bool Intersects(const BoundingBox& box, Real& distance) const { return CollisionsHelper::RayIntersectsBox(*this, box, distance); } /// /// Determines if there is an intersection between the current object and a . /// /// The box to test. /// When the method completes, contains the point of intersection, or if there was no intersection. /// Whether the two objects intersected. bool Intersects(const BoundingBox& box, Vector3& point) const { return CollisionsHelper::RayIntersectsBox(*this, box, point); } /// /// Determines if there is an intersection between the current object and a . /// /// The sphere to test. /// Whether the two objects intersected. bool Intersects(const BoundingSphere& sphere) const { Real distance; return CollisionsHelper::RayIntersectsSphere(*this, sphere, distance); } /// /// Determines if there is an intersection between the current object and a . /// /// The sphere to test. /// When the method completes, contains the distance of the intersection, or 0 if there was no intersection. /// Whether the two objects intersected. bool Intersects(const BoundingSphere& sphere, Real& distance) const { return CollisionsHelper::RayIntersectsSphere(*this, sphere, distance); } /// /// Determines if there is an intersection between the current object and a . /// /// The sphere to test. /// When the method completes, contains the point of intersection, or if there was no intersection. /// Whether the two objects intersected. bool Intersects(const BoundingSphere& sphere, Vector3& point) const { return CollisionsHelper::RayIntersectsSphere(*this, sphere, point); } public: /// /// Calculates a world space ray from 2d screen coordinates. /// /// The X coordinate on 2d screen. /// The Y coordinate on 2d screen. /// The screen viewport. /// The View*Projection matrix. /// The resulting ray. static Ray GetPickRay(float x, float y, const Viewport& viewport, const Matrix& vp); }; template<> struct TIsPODType { enum { Value = true }; }; DEFINE_DEFAULT_FORMATTING(Ray, "Position:{0} Direction:{1}", v.Position, v.Direction);