Path: blob/master/thirdparty/jolt_physics/Jolt/Geometry/RayCylinder.h
9913 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Math/FindRoot.h>78JPH_NAMESPACE_BEGIN910/// Tests a ray starting at inRayOrigin and extending infinitely in inRayDirection11/// against an infinite cylinder centered along the Y axis12/// @return FLT_MAX if there is no intersection, otherwise the fraction along the ray.13/// @param inRayDirection Direction of the ray. Does not need to be normalized.14/// @param inRayOrigin Origin of the ray. If the ray starts inside the cylinder, the returned fraction will be 0.15/// @param inCylinderRadius Radius of the infinite cylinder16JPH_INLINE float RayCylinder(Vec3Arg inRayOrigin, Vec3Arg inRayDirection, float inCylinderRadius)17{18// Remove Y component of ray to see of ray intersects with infinite cylinder19UVec4 mask_y = UVec4(0, 0xffffffff, 0, 0);20Vec3 origin_xz = Vec3::sSelect(inRayOrigin, Vec3::sZero(), mask_y);21float origin_xz_len_sq = origin_xz.LengthSq();22float r_sq = Square(inCylinderRadius);23if (origin_xz_len_sq > r_sq)24{25// Ray starts outside of the infinite cylinder26// Solve: |RayOrigin_xz + fraction * RayDirection_xz|^2 = r^2 to find fraction27Vec3 direction_xz = Vec3::sSelect(inRayDirection, Vec3::sZero(), mask_y);28float a = direction_xz.LengthSq();29float b = 2.0f * origin_xz.Dot(direction_xz);30float c = origin_xz_len_sq - r_sq;31float fraction1, fraction2;32if (FindRoot(a, b, c, fraction1, fraction2) == 0)33return FLT_MAX; // No intersection with infinite cylinder3435// Get fraction corresponding to the ray entering the circle36float fraction = min(fraction1, fraction2);37if (fraction >= 0.0f)38return fraction;39}40else41{42// Ray starts inside the infinite cylinder43return 0.0f;44}4546// No collision47return FLT_MAX;48}4950/// Test a ray against a cylinder centered around the origin with its axis along the Y axis and half height specified.51/// @return FLT_MAX if there is no intersection, otherwise the fraction along the ray.52/// @param inRayDirection Ray direction. Does not need to be normalized.53/// @param inRayOrigin Origin of the ray. If the ray starts inside the cylinder, the returned fraction will be 0.54/// @param inCylinderRadius Radius of the cylinder55/// @param inCylinderHalfHeight Distance from the origin to the top (or bottom) of the cylinder56JPH_INLINE float RayCylinder(Vec3Arg inRayOrigin, Vec3Arg inRayDirection, float inCylinderHalfHeight, float inCylinderRadius)57{58// Test infinite cylinder59float fraction = RayCylinder(inRayOrigin, inRayDirection, inCylinderRadius);60if (fraction == FLT_MAX)61return FLT_MAX;6263// If this hit is in the finite cylinder we have our fraction64if (abs(inRayOrigin.GetY() + fraction * inRayDirection.GetY()) <= inCylinderHalfHeight)65return fraction;6667// Check if ray could hit the top or bottom plane of the cylinder68float direction_y = inRayDirection.GetY();69if (direction_y != 0.0f)70{71// Solving line equation: x = ray_origin + fraction * ray_direction72// and plane equation: plane_normal . x + plane_constant = 073// fraction = (-plane_constant - plane_normal . ray_origin) / (plane_normal . ray_direction)74// when the ray_direction.y < 0:75// plane_constant = -cylinder_half_height, plane_normal = (0, 1, 0)76// else77// plane_constant = -cylinder_half_height, plane_normal = (0, -1, 0)78float origin_y = inRayOrigin.GetY();79float plane_fraction;80if (direction_y < 0.0f)81plane_fraction = (inCylinderHalfHeight - origin_y) / direction_y;82else83plane_fraction = -(inCylinderHalfHeight + origin_y) / direction_y;8485// Check if the hit is in front of the ray86if (plane_fraction >= 0.0f)87{88// Test if this hit is inside the cylinder89Vec3 point = inRayOrigin + plane_fraction * inRayDirection;90float dist_sq = Square(point.GetX()) + Square(point.GetZ());91if (dist_sq <= Square(inCylinderRadius))92return plane_fraction;93}94}9596// No collision97return FLT_MAX;98}99100JPH_NAMESPACE_END101102103