// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics) // SPDX-FileCopyrightText: 2021 Jorrit Rouwe // SPDX-License-Identifier: MIT #pragma once #include JPH_NAMESPACE_BEGIN /// Tests a ray starting at inRayOrigin and extending infinitely in inRayDirection against a sphere, /// @return FLT_MAX if there is no intersection, otherwise the fraction along the ray. /// @param inRayOrigin Ray origin. If the ray starts inside the sphere, the returned fraction will be 0. /// @param inRayDirection Ray direction. Does not need to be normalized. /// @param inSphereCenter Position of the center of the sphere /// @param inSphereRadius Radius of the sphere JPH_INLINE float RaySphere(Vec3Arg inRayOrigin, Vec3Arg inRayDirection, Vec3Arg inSphereCenter, float inSphereRadius) { // Solve: |RayOrigin + fraction * RayDirection - SphereCenter|^2 = SphereRadius^2 for fraction Vec3 center_origin = inRayOrigin - inSphereCenter; float a = inRayDirection.LengthSq(); float b = 2.0f * inRayDirection.Dot(center_origin); float c = center_origin.LengthSq() - inSphereRadius * inSphereRadius; float fraction1, fraction2; if (FindRoot(a, b, c, fraction1, fraction2) == 0) return c <= 0.0f? 0.0f : FLT_MAX; // Return if origin is inside the sphere // Sort so that the smallest is first if (fraction1 > fraction2) std::swap(fraction1, fraction2); // Test solution with lowest fraction, this will be the ray entering the sphere if (fraction1 >= 0.0f) return fraction1; // Sphere is before the ray start // Test solution with highest fraction, this will be the ray leaving the sphere if (fraction2 >= 0.0f) return 0.0f; // We start inside the sphere // No solution return FLT_MAX; } /// Tests a ray starting at inRayOrigin and extending infinitely in inRayDirection against a sphere. /// Outputs entry and exit points (outMinFraction and outMaxFraction) along the ray (which could be negative if the hit point is before the start of the ray). /// @param inRayOrigin Ray origin. If the ray starts inside the sphere, the returned fraction will be 0. /// @param inRayDirection Ray direction. Does not need to be normalized. /// @param inSphereCenter Position of the center of the sphere. /// @param inSphereRadius Radius of the sphere. /// @param outMinFraction Returned lowest intersection fraction /// @param outMaxFraction Returned highest intersection fraction /// @return The amount of intersections with the sphere. /// If 1 intersection is returned outMinFraction will be equal to outMaxFraction JPH_INLINE int RaySphere(Vec3Arg inRayOrigin, Vec3Arg inRayDirection, Vec3Arg inSphereCenter, float inSphereRadius, float &outMinFraction, float &outMaxFraction) { // Solve: |RayOrigin + fraction * RayDirection - SphereCenter|^2 = SphereRadius^2 for fraction Vec3 center_origin = inRayOrigin - inSphereCenter; float a = inRayDirection.LengthSq(); float b = 2.0f * inRayDirection.Dot(center_origin); float c = center_origin.LengthSq() - inSphereRadius * inSphereRadius; float fraction1, fraction2; switch (FindRoot(a, b, c, fraction1, fraction2)) { case 0: if (c <= 0.0f) { // Origin inside sphere outMinFraction = outMaxFraction = 0.0f; return 1; } else { // Origin outside of the sphere return 0; } break; case 1: // Ray is touching the sphere outMinFraction = outMaxFraction = fraction1; return 1; default: // Ray enters and exits the sphere // Sort so that the smallest is first if (fraction1 > fraction2) std::swap(fraction1, fraction2); outMinFraction = fraction1; outMaxFraction = fraction2; return 2; } } JPH_NAMESPACE_END