collision: intersect moving sphere aabb

This commit is contained in:
Zack Buhman 2026-03-14 12:26:08 -05:00
parent 157f493167
commit ce2260e078
2 changed files with 64 additions and 20 deletions

View File

@ -174,28 +174,27 @@ namespace collision {
return true; return true;
} }
static inline bool intersect_moving_sphere_aabb(Sphere const & sphere, XMVECTOR const & direction, AABB const & aabb, float & t) static const float interval_epsilon = 0.02f;
{
AABB expand(expand.min - XMVectorReplicate(sphere.radius),
expand.max + XMVectorReplicate(sphere.radius));
// intersect ray against expand static inline bool intersect_moving_sphere_aabb(Sphere const & sphere, XMVECTOR const & direction,
XMVECTOR point; float t0, float t1, AABB const & aabb,
bool intersection = intersect_ray_aabb(sphere.center, direction, expand, t, point); float & t, XMVECTOR & point)
if (!intersection || t > 1.0f) {
float mid = (t0 + t1) * 0.5f;
XMVECTOR center = sphere.center + direction * mid;
float radius = (mid - t0) * XMVectorGetX(XMVector3Length(direction)) + sphere.radius;
Sphere bound(center, radius);
if (!test_sphere_aabb(bound, aabb, point))
return false; return false;
XMVECTOR lt = XMVectorLess(point, aabb.min); if (t1 - t0 < interval_epsilon) {
int u = 0; t = t0;
if (XMVectorGetX(lt) != 0) u |= 1; return true;
if (XMVectorGetY(lt) != 0) u |= 2; }
if (XMVectorGetZ(lt) != 0) u |= 4;
XMVECTOR gt = XMVectorGreater(point, aabb.max);
int v = 0;
if (XMVectorGetX(gt) != 0) v |= 1;
if (XMVectorGetY(gt) != 0) v |= 2;
if (XMVectorGetZ(gt) != 0) v |= 4;
int mask = u + v; if (intersect_moving_sphere_aabb(sphere, direction, t0, mid, aabb, t, point))
return true;
return intersect_moving_sphere_aabb(sphere, direction, mid, t1, aabb, t, point);
} }
} }

View File

@ -150,7 +150,7 @@ namespace collision_scene {
load_index_buffer(); load_index_buffer();
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
point_position[i] = XMVectorSet(0, 0, 0, 1); point_position[i] = XMVectorSet(-1, -1, 0, 1);
// ray buffer // ray buffer
glGenBuffers(1, &ray_vertex_buffer); glGenBuffers(1, &ray_vertex_buffer);
@ -252,6 +252,19 @@ namespace collision_scene {
draw_line(transform, a - pxabn * radius, b - pxabn * radius); draw_line(transform, a - pxabn * radius, b - pxabn * radius);
} }
void draw_cube(XMMATRIX const & transform, XMVECTOR const & position)
{
float cube_half = 0.5;
XMMATRIX cube_transform
= XMMatrixScaling(cube_half, cube_half, cube_half)
* XMMatrixTranslationFromVector(position)
* transform;
set_transform(cube_transform);
const int cube_base_vertex = 4;
const int cube_base_index = 0;
glDrawElementsBaseVertex(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, (void*)(cube_base_index), cube_base_vertex);
}
void draw() void draw()
{ {
glUseProgram(program); glUseProgram(program);
@ -267,6 +280,7 @@ namespace collision_scene {
XMMATRIX transform = view() * projection(); XMMATRIX transform = view() * projection();
// grid // grid
glLineWidth(1.0f);
set_transform(transform); set_transform(transform);
glUniform3f(location.uniform.base_color, 0, 1, 0); glUniform3f(location.uniform.base_color, 0, 1, 0);
glUniform1i(location.uniform.use_grid_transform, 1); glUniform1i(location.uniform.use_grid_transform, 1);
@ -274,6 +288,36 @@ namespace collision_scene {
glUniform1i(location.uniform.use_grid_transform, 0); glUniform1i(location.uniform.use_grid_transform, 0);
glLineWidth(3.0f);
glUniform3f(location.uniform.base_color, 0.5, 1.0, 0.0);
XMVECTOR cube_center = XMVectorSet(1, 1, 0, 1);
draw_cube(transform, cube_center);
glUniform3f(location.uniform.base_color, 0, 0.0, 1.0);
draw_sphere(transform, point_position[0], 0.5);
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
draw_sphere(transform, point_position[1], point_radius);
draw_line(transform, point_position[0], point_position[1]);
collision::Sphere sphere(point_position[0], 0.5);
XMVECTOR direction = point_position[1] - point_position[0];
collision::AABB aabb = collision::cube_aabb(cube_center, 0.5);
float t;
XMVECTOR intersection_point;
bool intersected = collision::intersect_moving_sphere_aabb(sphere, direction,
0, 1, aabb,
t, intersection_point);
if (intersected){
glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0);
XMVECTOR intersection_position = point_position[0] + direction * t;
draw_sphere(transform, intersection_position, 0.5);
glUniform3f(location.uniform.base_color, 1.0, 0.0, 0.0);
draw_sphere(transform, intersection_point, point_radius);
}
/*
// segments // segments
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0); glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
draw_line(transform, point_position[0], point_position[1]); draw_line(transform, point_position[0], point_position[1]);
@ -316,6 +360,7 @@ namespace collision_scene {
glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0); glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0);
draw_sphere(transform, c2_point, point_radius); draw_sphere(transform, c2_point, point_radius);
} }
*/
// cube // cube
/* /*