Path: blob/master/thirdparty/jolt_physics/Jolt/Geometry/RayAABox.h
9913 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56JPH_NAMESPACE_BEGIN78/// Helper structure holding the reciprocal of a ray for Ray vs AABox testing9class RayInvDirection10{11public:12/// Constructors13inline RayInvDirection() = default;14inline explicit RayInvDirection(Vec3Arg inDirection) { Set(inDirection); }1516/// Set reciprocal from ray direction17inline void Set(Vec3Arg inDirection)18{19// if (abs(inDirection) <= Epsilon) the ray is nearly parallel to the slab.20mIsParallel = Vec3::sLessOrEqual(inDirection.Abs(), Vec3::sReplicate(1.0e-20f));2122// Calculate 1 / direction while avoiding division by zero23mInvDirection = Vec3::sSelect(inDirection, Vec3::sOne(), mIsParallel).Reciprocal();24}2526Vec3 mInvDirection; ///< 1 / ray direction27UVec4 mIsParallel; ///< for each component if it is parallel to the coordinate axis28};2930/// Intersect AABB with ray, returns minimal distance along ray or FLT_MAX if no hit31/// Note: Can return negative value if ray starts in box32JPH_INLINE float RayAABox(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax)33{34// Constants35Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);36Vec3 flt_max = Vec3::sReplicate(FLT_MAX);3738// Test against all three axes simultaneously.39Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;40Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;4142// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't43// use the results from any directions parallel to the slab.44Vec3 t_min = Vec3::sSelect(Vec3::sMin(t1, t2), flt_min, inInvDirection.mIsParallel);45Vec3 t_max = Vec3::sSelect(Vec3::sMax(t1, t2), flt_max, inInvDirection.mIsParallel);4647// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);48t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());49t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());5051// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);52t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());53t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());5455// if (t_min > t_max) return FLT_MAX;56UVec4 no_intersection = Vec3::sGreater(t_min, t_max);5758// if (t_max < 0.0f) return FLT_MAX;59no_intersection = UVec4::sOr(no_intersection, Vec3::sLess(t_max, Vec3::sZero()));6061// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return FLT_MAX; else return t_min;62UVec4 no_parallel_overlap = UVec4::sOr(Vec3::sLess(inOrigin, inBoundsMin), Vec3::sGreater(inOrigin, inBoundsMax));63no_intersection = UVec4::sOr(no_intersection, UVec4::sAnd(inInvDirection.mIsParallel, no_parallel_overlap));64no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatY());65no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatZ());66return Vec3::sSelect(t_min, flt_max, no_intersection).GetX();67}6869/// Intersect 4 AABBs with ray, returns minimal distance along ray or FLT_MAX if no hit70/// Note: Can return negative value if ray starts in box71JPH_INLINE Vec4 RayAABox4(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ)72{73// Constants74Vec4 flt_min = Vec4::sReplicate(-FLT_MAX);75Vec4 flt_max = Vec4::sReplicate(FLT_MAX);7677// Origin78Vec4 originx = inOrigin.SplatX();79Vec4 originy = inOrigin.SplatY();80Vec4 originz = inOrigin.SplatZ();8182// Parallel83UVec4 parallelx = inInvDirection.mIsParallel.SplatX();84UVec4 parallely = inInvDirection.mIsParallel.SplatY();85UVec4 parallelz = inInvDirection.mIsParallel.SplatZ();8687// Inverse direction88Vec4 invdirx = inInvDirection.mInvDirection.SplatX();89Vec4 invdiry = inInvDirection.mInvDirection.SplatY();90Vec4 invdirz = inInvDirection.mInvDirection.SplatZ();9192// Test against all three axes simultaneously.93Vec4 t1x = (inBoundsMinX - originx) * invdirx;94Vec4 t1y = (inBoundsMinY - originy) * invdiry;95Vec4 t1z = (inBoundsMinZ - originz) * invdirz;96Vec4 t2x = (inBoundsMaxX - originx) * invdirx;97Vec4 t2y = (inBoundsMaxY - originy) * invdiry;98Vec4 t2z = (inBoundsMaxZ - originz) * invdirz;99100// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't101// use the results from any directions parallel to the slab.102Vec4 t_minx = Vec4::sSelect(Vec4::sMin(t1x, t2x), flt_min, parallelx);103Vec4 t_miny = Vec4::sSelect(Vec4::sMin(t1y, t2y), flt_min, parallely);104Vec4 t_minz = Vec4::sSelect(Vec4::sMin(t1z, t2z), flt_min, parallelz);105Vec4 t_maxx = Vec4::sSelect(Vec4::sMax(t1x, t2x), flt_max, parallelx);106Vec4 t_maxy = Vec4::sSelect(Vec4::sMax(t1y, t2y), flt_max, parallely);107Vec4 t_maxz = Vec4::sSelect(Vec4::sMax(t1z, t2z), flt_max, parallelz);108109// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);110Vec4 t_min = Vec4::sMax(Vec4::sMax(t_minx, t_miny), t_minz);111112// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);113Vec4 t_max = Vec4::sMin(Vec4::sMin(t_maxx, t_maxy), t_maxz);114115// if (t_min > t_max) return FLT_MAX;116UVec4 no_intersection = Vec4::sGreater(t_min, t_max);117118// if (t_max < 0.0f) return FLT_MAX;119no_intersection = UVec4::sOr(no_intersection, Vec4::sLess(t_max, Vec4::sZero()));120121// if bounds are invalid return FLOAT_MAX;122UVec4 bounds_invalid = UVec4::sOr(UVec4::sOr(Vec4::sGreater(inBoundsMinX, inBoundsMaxX), Vec4::sGreater(inBoundsMinY, inBoundsMaxY)), Vec4::sGreater(inBoundsMinZ, inBoundsMaxZ));123no_intersection = UVec4::sOr(no_intersection, bounds_invalid);124125// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return FLT_MAX; else return t_min;126UVec4 no_parallel_overlapx = UVec4::sAnd(parallelx, UVec4::sOr(Vec4::sLess(originx, inBoundsMinX), Vec4::sGreater(originx, inBoundsMaxX)));127UVec4 no_parallel_overlapy = UVec4::sAnd(parallely, UVec4::sOr(Vec4::sLess(originy, inBoundsMinY), Vec4::sGreater(originy, inBoundsMaxY)));128UVec4 no_parallel_overlapz = UVec4::sAnd(parallelz, UVec4::sOr(Vec4::sLess(originz, inBoundsMinZ), Vec4::sGreater(originz, inBoundsMaxZ)));129no_intersection = UVec4::sOr(no_intersection, UVec4::sOr(UVec4::sOr(no_parallel_overlapx, no_parallel_overlapy), no_parallel_overlapz));130return Vec4::sSelect(t_min, flt_max, no_intersection);131}132133/// Intersect AABB with ray, returns minimal and maximal distance along ray or FLT_MAX, -FLT_MAX if no hit134/// Note: Can return negative value for outMin if ray starts in box135JPH_INLINE void RayAABox(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax, float &outMin, float &outMax)136{137// Constants138Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);139Vec3 flt_max = Vec3::sReplicate(FLT_MAX);140141// Test against all three axes simultaneously.142Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;143Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;144145// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't146// use the results from any directions parallel to the slab.147Vec3 t_min = Vec3::sSelect(Vec3::sMin(t1, t2), flt_min, inInvDirection.mIsParallel);148Vec3 t_max = Vec3::sSelect(Vec3::sMax(t1, t2), flt_max, inInvDirection.mIsParallel);149150// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);151t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());152t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());153154// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);155t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());156t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());157158// if (t_min > t_max) return FLT_MAX;159UVec4 no_intersection = Vec3::sGreater(t_min, t_max);160161// if (t_max < 0.0f) return FLT_MAX;162no_intersection = UVec4::sOr(no_intersection, Vec3::sLess(t_max, Vec3::sZero()));163164// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return FLT_MAX; else return t_min;165UVec4 no_parallel_overlap = UVec4::sOr(Vec3::sLess(inOrigin, inBoundsMin), Vec3::sGreater(inOrigin, inBoundsMax));166no_intersection = UVec4::sOr(no_intersection, UVec4::sAnd(inInvDirection.mIsParallel, no_parallel_overlap));167no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatY());168no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatZ());169outMin = Vec3::sSelect(t_min, flt_max, no_intersection).GetX();170outMax = Vec3::sSelect(t_max, flt_min, no_intersection).GetX();171}172173/// Intersect AABB with ray, returns true if there is a hit closer than inClosest174JPH_INLINE bool RayAABoxHits(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax, float inClosest)175{176// Constants177Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);178Vec3 flt_max = Vec3::sReplicate(FLT_MAX);179180// Test against all three axes simultaneously.181Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;182Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;183184// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't185// use the results from any directions parallel to the slab.186Vec3 t_min = Vec3::sSelect(Vec3::sMin(t1, t2), flt_min, inInvDirection.mIsParallel);187Vec3 t_max = Vec3::sSelect(Vec3::sMax(t1, t2), flt_max, inInvDirection.mIsParallel);188189// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);190t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());191t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());192193// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);194t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());195t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());196197// if (t_min > t_max) return false;198UVec4 no_intersection = Vec3::sGreater(t_min, t_max);199200// if (t_max < 0.0f) return false;201no_intersection = UVec4::sOr(no_intersection, Vec3::sLess(t_max, Vec3::sZero()));202203// if (t_min > inClosest) return false;204no_intersection = UVec4::sOr(no_intersection, Vec3::sGreater(t_min, Vec3::sReplicate(inClosest)));205206// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return false; else return true;207UVec4 no_parallel_overlap = UVec4::sOr(Vec3::sLess(inOrigin, inBoundsMin), Vec3::sGreater(inOrigin, inBoundsMax));208no_intersection = UVec4::sOr(no_intersection, UVec4::sAnd(inInvDirection.mIsParallel, no_parallel_overlap));209210return !no_intersection.TestAnyXYZTrue();211}212213/// Intersect AABB with ray without hit fraction, based on separating axis test214/// @see http://www.codercorner.com/RayAABB.cpp215JPH_INLINE bool RayAABoxHits(Vec3Arg inOrigin, Vec3Arg inDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax)216{217Vec3 extents = inBoundsMax - inBoundsMin;218219Vec3 diff = 2.0f * inOrigin - inBoundsMin - inBoundsMax;220Vec3 abs_diff = diff.Abs();221222UVec4 no_intersection = UVec4::sAnd(Vec3::sGreater(abs_diff, extents), Vec3::sGreaterOrEqual(diff * inDirection, Vec3::sZero()));223224Vec3 abs_dir = inDirection.Abs();225Vec3 abs_dir_yzz = abs_dir.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z>();226Vec3 abs_dir_xyx = abs_dir.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_X>();227228Vec3 extents_yzz = extents.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z>();229Vec3 extents_xyx = extents.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_X>();230231Vec3 diff_yzx = diff.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>();232233Vec3 dir_yzx = inDirection.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>();234235no_intersection = UVec4::sOr(no_intersection, Vec3::sGreater((inDirection * diff_yzx - dir_yzx * diff).Abs(), extents_xyx * abs_dir_yzz + extents_yzz * abs_dir_xyx));236237return !no_intersection.TestAnyXYZTrue();238}239240JPH_NAMESPACE_END241242243