Files
FlaxEngine/Source/Shaders/Collisions.hlsl
2020-12-07 23:40:54 +01:00

85 lines
4.0 KiB
HLSL

// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#ifndef __COLLISIONS__
#define __COLLISIONS__
bool RayHitSphere(float3 r, float3 sphereCenter, float sphereRadius)
{
float3 closestPointOnRay = max(0, dot(sphereCenter, r)) * r;
float3 centerToRay = closestPointOnRay - sphereCenter;
return dot(centerToRay, centerToRay) <= (sphereRadius * sphereRadius);
}
bool RayHitRect(float3 r, float3 rectCenter, float3 rectX, float3 rectY, float3 rectZ, float rectExtentX, float rectExtentY)
{
float3 pointOnPlane = r * max(0, dot(rectZ, rectCenter) / dot(rectZ, r));
bool inExtentX = abs(dot(rectX, pointOnPlane - rectCenter)) <= rectExtentX;
bool inExtentY = abs(dot(rectY, pointOnPlane - rectCenter)) <= rectExtentY;
return inExtentX && inExtentY;
}
// Computes where a ray hits a sphere (which is centered at the origin).
// \param[in] rayOrigin The start position of the ray.
// \param[in] rayDirection The normalized direction of the ray.
// \param[in] radius The radius of the sphere.
// \param[out] enter The ray parameter where the ray enters the sphere.
// 0 if the ray is already in the sphere.
// \param[out] exit The ray parameter where the ray exits the sphere.
// \return 0 or a positive value if the ray hits the sphere. A negative value
// if the ray does not touch the sphere.
float HitSphere(float3 rayOrigin, float3 rayDirection, float radius, out float enter, out float exit)
{
// Solve the equation: ||rayOrigin + distance * rayDirection|| = r
//
// This is a straight-forward quadratic equation:
// ||O + d * D|| = r
// => (O + d * D)2 = r2 where V2 means V.V
// => d2 * D2 + 2 * d * (O.D) + O2 - r2 = 0
// D2 is 1 because the rayDirection is normalized.
// => d = -O.D + sqrt((O.D)2 - O2 + r2)
float OD = dot(rayOrigin, rayDirection);
float OO = dot(rayOrigin, rayOrigin);
float radicand = OD * OD - OO + radius * radius;
enter = max(0, -OD - sqrt(radicand));
exit = -OD + sqrt(radicand);
// If radicand is negative then we do not have a result - no hit.
return radicand;
}
// Clips a ray to an AABB. Does not handle rays parallel to any of the planes.
//
// @param rayOrigin - The origin of the ray in world space.
// @param rayEnd - The end of the ray in world space.
// @param boxMin - The minimum extrema of the box.
// @param boxMax - The maximum extrema of the box.
// @return - Returns the closest intersection along the ray in x, and furthest in y.
// If the ray did not intersect the box, then the furthest intersection <= the closest intersection.
// The intersections will always be in the range [0,1], which corresponds to [rayOrigin, rayEnd] in worldspace.
// To find the world space position of either intersection, simply plug it back into the ray equation:
// WorldPos = RayOrigin + (rayEnd - RayOrigin) * Intersection;
float2 LineBoxIntersect(float3 rayOrigin, float3 rayEnd, float3 boxMin, float3 boxMax)
{
float3 invRayDir = 1.0f / (rayEnd - rayOrigin);
//find the ray intersection with each of the 3 planes defined by the minimum extrema.
float3 planeIntersections1 = (boxMin - rayOrigin) * invRayDir;
//find the ray intersection with each of the 3 planes defined by the maximum extrema.
float3 planeIntersections2 = (boxMax - rayOrigin) * invRayDir;
//get the closest of these intersections along the ray
float3 closestPlaneIntersections = min(planeIntersections1, planeIntersections2);
//get the furthest of these intersections along the ray
float3 furthestPlaneIntersections = max(planeIntersections1, planeIntersections2);
float2 boxIntersections;
//find the furthest near intersection
boxIntersections.x = max(closestPlaneIntersections.x, max(closestPlaneIntersections.y, closestPlaneIntersections.z));
//find the closest far intersection
boxIntersections.y = min(furthestPlaneIntersections.x, min(furthestPlaneIntersections.y, furthestPlaneIntersections.z));
//clamp the intersections to be between rayOrigin and RayEnd on the ray
return saturate(boxIntersections);
}
#endif