You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
11 KiB
HLSL

/******************************************************************************/
/*
Project - MudBun
Publisher - Long Bunny Labs
http://LongBunnyLabs.com
Author - Ming-Lun "Allen" Chou
http://AllenChou.net
*/
/******************************************************************************/
#ifndef MUDBUN_AABB_TREE_FUNCS
#define MUDBUN_AABB_TREE_FUNCS
#include "AabbTreeDefs.cginc"
#include "Math/MathConst.cginc"
Aabb make_aabb(float3 boundsMin, float3 boundsMax)
{
Aabb aabb;
aabb.boundsMin = boundsMin;
aabb.boundsMax = boundsMax;
return aabb;
}
float3 aabb_center(Aabb aabb)
{
return 0.5f * (aabb.boundsMin + aabb.boundsMax);
}
float3 aabb_size(Aabb aabb)
{
return aabb.boundsMax - aabb.boundsMin;
}
float3 aabb_extents(Aabb aabb)
{
return 0.5f * (aabb.boundsMax - aabb.boundsMin);
}
bool aabb_intersects(Aabb a, Aabb b)
{
return all(a.boundsMin <= b.boundsMax && a.boundsMax >= b.boundsMin);
}
bool aabb_contains(Aabb aabb, float3 p)
{
return all(aabb.boundsMin <= p) && all(aabb.boundsMax >= p);
}
float aabb_ray_cast(Aabb aabb, float3 from, float3 to, out float3 normal)
{
float tMin = -kFltMax;
float tMax = +kFltMax;
float3 d = to - from;
float3 absD = abs(d);
bool3 isZero = absD < kEpsilon;
normal = 0.0f;
// parallel?
if (any(isZero && ((from < aabb.boundsMin) || (aabb.boundsMax < from))))
return -kFltMax;
float3 invD = sign(d) / max(kEpsilon, absD);
float3 t1 = (aabb.boundsMin - from) * invD;
float3 t2 = (aabb.boundsMax - from) * invD;
float3 minComps = isZero ? (-kFltMax) : min(t1, t2);
float3 maxComps = isZero ? (+kFltMax) : max(t1, t2);
tMin = max(minComps.x, max(minComps.y, minComps.z));
tMax = min(maxComps.x, min(maxComps.y, maxComps.z));
if (tMin > tMax)
return -kFltMax;
if (tMin > 1.0f)
return -kFltMax;
normal =
minComps.x > minComps.y
? minComps.x > minComps.z
? float3(1.0f, 0.0f, 0.0f)
: float3(0.0f, 0.0f, 1.0f)
: minComps.y > minComps.z
? float3(0.0f, 1.0f, 0.0f)
: float3(0.0f, 0.0f, 1.0f);
normal *= -sign(d);
return max(0.0f, tMin);
}
float aabb_ray_cast(Aabb aabb, float3 from, float3 to)
{
float3 n = 0.0f;
return aabb_ray_cast(aabb, from, to, n);
}
// stmt = statements processing "iData" of intersected leaf AABB nodes
// will gracefully handle maxed-out stacks
#define AABB_TREE_QUERY_AABB(tree, root, queryAabb, stmt) \
{ \
int stackTop = 0; \
int stack[kAabbTreeNodeStackSize]; \
stack[stackTop] = root; \
\
while (stackTop >= 0) \
{ \
int index = stack[stackTop--]; \
if (index < 0) \
continue; \
\
if (!aabb_intersects(tree[index].aabb, queryAabb)) \
continue; \
\
if (tree[index].iChildA < 0) \
{ \
const int iData = tree[index].iData; \
\
stmt \
} \
else \
{ \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildA; \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildB; \
} \
} \
}
// stmt = statements processing "iData" of hit leaf AABB nodes
// will gracefully handle maxed-out stacks
#define AABB_TREE_QUERY_POINT(tree, root, p, stmt) \
{ \
int stackTop = 0; \
int stack[kAabbTreeNodeStackSize]; \
stack[stackTop] = root; \
\
int numIters = 0; \
while (stackTop >= 0 && numIters < 128 /* safeguard */) \
{ \
int index = stack[stackTop--]; \
if (index < 0) \
continue; \
\
if (!aabb_contains(tree[index].aabb, p)) \
continue; \
\
if (tree[index].iChildA < 0) \
{ \
int iData = tree[index].iData; \
\
stmt \
} \
else \
{ \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildA; \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildB; \
} \
} \
}
// stmt = statements processing "iData" of hit leaf AABB nodes
// will gracefully handle maxed-out stacks
#define AABB_TREE_RAY_CAST(tree, root, rayFrom, rayTo, stmt) \
{ \
float3 rayDir = normalize_safe(rayTo - rayFrom, kUnitZ); \
float3 rayDirOrtho = normalize_safe(find_ortho(rayDir), kUnitX); \
float3 rayDirOrthoAbs = abs(rayDirOrtho); \
\
Aabb rayBounds; \
rayBounds.boundsMin = min(rayFrom, rayTo); \
rayBounds.boundsMax = max(rayFrom, rayTo); \
\
int stackTop = 0; \
int stack[kAabbTreeNodeStackSize]; \
stack[stackTop] = root; \
\
int numIters = 0; \
while (stackTop >= 0 && numIters < 128 /* safeguard */) \
{ \
int index = stack[stackTop--]; \
if (index < 0) \
continue; \
\
if (!aabb_intersects(tree[index].aabb, rayBounds)) \
continue; \
\
float3 aabbCenter = aabb_center(tree[index].aabb); \
float3 aabbHalfExtents = aabb_extents(tree[index].aabb); \
float separation = \
abs(dot(rayDirOrtho, rayFrom - aabbCenter)) \
- dot(rayDirOrthoAbs, aabbHalfExtents); \
if (separation > 0.0f) \
continue; \
\
float t = aabb_ray_cast(tree[index].aabb, rayFrom, rayTo); \
if (t < 0.0f) \
continue; \
\
if (tree[index].iChildA < 0) \
{ \
int iData = tree[index].iData; \
\
stmt \
} \
else \
{ \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildA; \
stackTop = min(stackTop + 1, kAabbTreeNodeStackSize - 1); \
stack[stackTop] = tree[index].iChildB; \
} \
} \
}
#endif