unevenly-scaled shape collisions working

This commit is contained in:
jacob 2024-10-10 16:43:31 -05:00
parent daf1a862f5
commit 31082916ad
5 changed files with 144 additions and 20 deletions

View File

@ -24,6 +24,7 @@ INTERNAL void _dbgbreakable(void)
struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir) struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir)
{ {
#if 0
struct v2 *points = a->points; struct v2 *points = a->points;
u32 count = a->count; u32 count = a->count;
f32 radius = a->radius; f32 radius = a->radius;
@ -46,6 +47,62 @@ struct v2 collider_support_point(struct collider_shape *a, struct xform xf, stru
} }
return furthest; return furthest;
#elif 0
struct v2 *points = a->points;
u32 count = a->count;
f32 radius = a->radius;
/* TODO: Could probably binary search for largest dot since shape is convex */
struct xform inv = xform_invert(xf);
dir = xform_basis_mul_v2(inv, dir);
struct v2 furthest = ZI;
f32 furthest_dot = -F32_INFINITY;
for (u32 i = 0; i < count; ++i) {
struct v2 p = points[i];
f32 dot = v2_dot(dir, p);
if (dot > furthest_dot) {
furthest = p;
furthest_dot = dot;
}
}
if (radius > 0.0) {
dir = v2_with_len(dir, radius);
furthest = v2_add(furthest, dir);
}
furthest = xform_mul_v2(xf, furthest);
return furthest;
#else
struct v2 *points = a->points;
u32 count = a->count;
f32 radius = a->radius;
dir = v2_rotated(dir, -xform_get_rotation(xf));
dir = v2_mul_v2(dir, xform_get_scale(xf));
struct v2 furthest = ZI;
f32 furthest_dot = -F32_INFINITY;
for (u32 i = 0; i < count; ++i) {
struct v2 p = points[i];
f32 dot = v2_dot(dir, p);
if (dot > furthest_dot) {
furthest = p;
furthest_dot = dot;
}
}
if (radius > 0.0) {
dir = v2_with_len(dir, radius);
furthest = v2_add(furthest, dir);
}
furthest = xform_mul_v2(xf, furthest);
return furthest;
#endif
} }
INTERNAL u32 collider_support_point_index(struct collider_shape *a, struct xform xf, struct v2 dir) INTERNAL u32 collider_support_point_index(struct collider_shape *a, struct xform xf, struct v2 dir)
@ -487,7 +544,7 @@ struct collider_collision_points_result collider_collision_points(struct collide
} }
} }
#if 1 #if 0
if (radius0 > 0.0) { if (radius0 > 0.0) {
struct v2 scale = xform_get_scale(xf0); struct v2 scale = xform_get_scale(xf0);
struct v2 normal_radius = v2_mul_v2(v2_mul(normal, radius0), scale); struct v2 normal_radius = v2_mul_v2(v2_mul(normal, radius0), scale);
@ -501,6 +558,24 @@ struct collider_collision_points_result collider_collision_points(struct collide
a1 = v2_sub(a1, normal_radius); a1 = v2_sub(a1, normal_radius);
b1 = v2_sub(b1, normal_radius); b1 = v2_sub(b1, normal_radius);
} }
#else
if (radius0 > 0.0) {
struct v2 radius_dir = v2_rotated(normal, -xform_get_rotation(xf0));
radius_dir = v2_mul_v2(radius_dir, xform_get_scale(xf0));
radius_dir = v2_with_len(radius_dir, radius0);
radius_dir = xform_basis_mul_v2(xf0, radius_dir);
a0 = v2_add(a0, radius_dir);
b0 = v2_add(b0, radius_dir);
}
if (radius1 > 0.0) {
struct v2 radius_dir = v2_rotated(normal, -xform_get_rotation(xf1));
radius_dir = v2_mul_v2(radius_dir, xform_get_scale(xf1));
radius_dir = v2_with_len(radius_dir, radius1);
radius_dir = xform_basis_mul_v2(xf1, radius_dir);
a1 = v2_sub(a1, radius_dir);
b1 = v2_sub(b1, radius_dir);
}
#endif #endif
f32 a0t = 0; f32 a0t = 0;
@ -571,10 +646,17 @@ struct collider_collision_points_result collider_collision_points(struct collide
point->point = contact_b; point->point = contact_b;
} }
#if 0
res.a0 = a0_clipped; res.a0 = a0_clipped;
res.a1 = a1_clipped; res.a1 = a1_clipped;
res.b0 = b0_clipped; res.b0 = b0_clipped;
res.b1 = b1_clipped; res.b1 = b1_clipped;
#else
res.a0 = a0;
res.a1 = a1;
res.b0 = b0;
res.b1 = b1;
#endif
} }
} }

View File

@ -38,7 +38,7 @@
#define GAME_PHYSICS_ENABLE_RELAXATION 1 #define GAME_PHYSICS_ENABLE_RELAXATION 1
#define GAME_PHYSICS_ENABLE_GROUND_FRICTION 0 #define GAME_PHYSICS_ENABLE_GROUND_FRICTION 0
#define GAME_SPAWN_LOTS 0 #define GAME_SPAWN_LOTS 1
#define GAME_MAX_LINEAR_VELOCITY 100 #define GAME_MAX_LINEAR_VELOCITY 100
#define GAME_MAX_ANGULAR_VELOCITY ((2 * PI) * 20) #define GAME_MAX_ANGULAR_VELOCITY ((2 * PI) * 20)

View File

@ -283,8 +283,16 @@ void draw_solid_collider_line(struct renderer_canvas *canvas, struct xform draw_
points[i] = p; points[i] = p;
} }
#if 1
struct v2_array poly = { .points = points, .count = detail }; struct v2_array poly = { .points = points, .count = detail };
draw_solid_poly_line(canvas, poly, true, thickness, color); draw_solid_poly_line(canvas, poly, true, thickness, color);
#else
for (u64 i = 0; i < detail; ++i) {
struct v2 point = points[i];
(UNUSED)thickness;
draw_solid_circle(canvas, point, 3, color, 10);
}
#endif
scratch_end(scratch); scratch_end(scratch);
} }

View File

@ -134,7 +134,7 @@ INTERNAL void spawn_test_entities(f32 offset)
//struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -10);
//struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -7);
//struct v2 pos = V2(0.25, -5.27); //struct v2 pos = V2(0.25, -5.27);
struct v2 pos = V2(0.25, -1); struct v2 pos = V2(0.5, -1);
//struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */ //struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */
//struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */ //struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */
//struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */
@ -143,14 +143,16 @@ INTERNAL void spawn_test_entities(f32 offset)
pos = v2_add(pos, V2(0, offset_all)); pos = v2_add(pos, V2(0, offset_all));
//struct v2 size = V2(1, 1); //struct v2 size = V2(1, 1);
struct v2 size = V2(0.5, 0.5); //struct v2 size = V2(0.5, 0.5);
struct v2 size = V2(1.0, 0.5);
//f32 r = PI; //f32 r = PI;
//f32 r = PI / 4; f32 r = PI / 4;
//f32 r = PI / 3; //f32 r = PI / 3;
//f32 r = 0.05; //f32 r = 0.05;
//f32 r = PI / 2; //f32 r = PI / 2;
f32 r = 0; //f32 r = 0;
//f32 skew = PI / 4; //f32 skew = PI / 4;
//f32 skew = 0.9f;
f32 skew = 0; f32 skew = 0;
struct entity *e = entity_alloc(root); struct entity *e = entity_alloc(root);
@ -166,9 +168,12 @@ INTERNAL void spawn_test_entities(f32 offset)
e->sprite_span_name = STR("idle.two_handed"); e->sprite_span_name = STR("idle.two_handed");
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
#if GAME_PHYSICS_ENABLE_GROUND_FRICTION
//e->control_force = 4500; //e->control_force = 4500;
//e->control_force = 1200; e->control_force = 1200;
#else
e->control_force = 250; e->control_force = 250;
#endif
e->control_torque = 10; e->control_torque = 10;
e->control.focus = V2(0, -1); e->control.focus = V2(0, -1);
@ -189,8 +194,7 @@ INTERNAL void spawn_test_entities(f32 offset)
//struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -10);
//struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -7);
//struct v2 pos = V2(0.25, -5.27); //struct v2 pos = V2(0.25, -5.27);
//struct v2 pos = V2(0.85, -2); struct v2 pos = V2(0.5, -1);
struct v2 pos = V2(0.25, -1);
//struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */ //struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */
//struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */ //struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */
//struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */
@ -199,13 +203,14 @@ INTERNAL void spawn_test_entities(f32 offset)
pos = v2_add(pos, V2(0, offset_all)); pos = v2_add(pos, V2(0, offset_all));
//struct v2 size = V2(1, 1); //struct v2 size = V2(1, 1);
struct v2 size = V2(0.5, 0.5); //struct v2 size = V2(0.5, 0.5);
struct v2 size = V2(1.0, 0.5);
//f32 r = PI; //f32 r = PI;
//f32 r = PI / 4; f32 r = PI / 4;
//f32 r = PI / 3; //f32 r = PI / 3;
//f32 r = 0.05; //f32 r = 0.05;
//f32 r = PI / 2; //f32 r = PI / 2;
f32 r = 0; //f32 r = 0;
//f32 skew = PI / 4; //f32 skew = PI / 4;
f32 skew = 0; f32 skew = 0;
@ -268,8 +273,11 @@ INTERNAL void spawn_test_entities(f32 offset)
//struct v2 pos = V2(0.5, 29); //struct v2 pos = V2(0.5, 29);
//struct v2 pos = V2(0.5, 24); //struct v2 pos = V2(0.5, 24);
//struct v2 pos = V2(1, -1); //struct v2 pos = V2(1, -1);
//struct v2 size = V2(1, 1); #if !GAME_SPAWN_LOTS
struct v2 size = V2(1, 1);
#else
struct v2 size = V2(500, 1); struct v2 size = V2(500, 1);
#endif
//f32 rot = PI / 4; //f32 rot = PI / 4;
f32 rot = 0; f32 rot = 0;
struct entity *e = entity_alloc(root); struct entity *e = entity_alloc(root);
@ -832,12 +840,21 @@ INTERNAL void integrate_positions_from_velocities(f32 dt)
ent->linear_velocity = v2_clamp_len(ent->linear_velocity, GAME_MAX_LINEAR_VELOCITY); ent->linear_velocity = v2_clamp_len(ent->linear_velocity, GAME_MAX_LINEAR_VELOCITY);
ent->angular_velocity = clamp_f32(ent->angular_velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY); ent->angular_velocity = clamp_f32(ent->angular_velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY);
#if 0
struct xform xf = entity_get_xform(ent); struct xform xf = entity_get_xform(ent);
struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt); struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt);
f32 tick_angular_velocity = ent->angular_velocity * dt; f32 tick_angular_velocity = ent->angular_velocity * dt;
xf.og = v2_add(xf.og, tick_linear_velocity); xf.og = v2_add(xf.og, tick_linear_velocity);
xf = xform_rotated(xf, tick_angular_velocity); xf = xform_rotated(xf, tick_angular_velocity);
entity_set_xform(ent, xf); entity_set_xform(ent, xf);
#else
struct xform xf = entity_get_xform(ent);
struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt);
f32 tick_angular_velocity = ent->angular_velocity * dt;
xf.og = v2_add(xf.og, tick_linear_velocity);
xf = xform_rotated_to(xf, xform_get_rotation(xf) + tick_angular_velocity);
entity_set_xform(ent, xf);
#endif
} }
} }
@ -1056,7 +1073,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
ent->local_collider.points[1] = V2(0, -0.5); ent->local_collider.points[1] = V2(0, -0.5);
ent->local_collider.count = 2; ent->local_collider.count = 2;
ent->local_collider.radius = 0.25; ent->local_collider.radius = 0.25;
#elif 1 #elif 0
#if 1 #if 1
/* "Bad" winding order */ /* "Bad" winding order */
ent->local_collider.points[0] = V2(-0.5, 0.5); ent->local_collider.points[0] = V2(-0.5, 0.5);
@ -1071,7 +1088,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
ent->local_collider.radius = 0.25; ent->local_collider.radius = 0.25;
//ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3); //ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3);
#else #else
ent->local_collider.radius = 0.25; ent->local_collider.radius = 0.5;
#endif #endif
} }
#endif #endif

View File

@ -998,17 +998,34 @@ INTERNAL void user_update(void)
struct collider_shape collider = ent->local_collider; struct collider_shape collider = ent->local_collider;
u32 color = ent->colliding > 0 ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(1, 1, 0, 0.25); u32 color = ent->colliding > 0 ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(1, 1, 0, 0.25);
f32 thickness = 2; f32 thickness = 2;
//u32 detail = 32; {
/* Draw collider using support points */
u32 detail = 512; u32 detail = 512;
draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail); draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail);
}
{
/* Draw collider shape points */
for (u32 i = 0; i < collider.count; ++i) {
struct v2 p = xform_mul_v2(xform_mul(G.world_view, xf), collider.points[i]);
draw_solid_circle(G.viewport_canvas, p, 3, COLOR_BLUE, 10);
}
}
if (collider.count == 1 && collider.radius > 0) { if (collider.count == 1 && collider.radius > 0) {
/* Draw upwards line for circle */ /* Draw upwards line for circle */
struct v2 start = xf.og; struct v2 start = xf.og;
struct v2 end = collider_support_point(&collider, xf, v2_neg(xf.by)); struct v2 end = collider_support_point(&collider, xf, xf.by);
start = xform_mul_v2(G.world_view, start); start = xform_mul_v2(G.world_view, start);
end = xform_mul_v2(G.world_view, end); end = xform_mul_v2(G.world_view, end);
draw_solid_line(G.viewport_canvas, start, end, thickness, color); draw_solid_line(G.viewport_canvas, start, end, thickness, color);
} }
#if 0
/* Draw support point at focus dir */
{
struct v2 p = collider_support_point(&collider, xf, ent->control.focus);
p = xform_mul_v2(G.world_view, p);
draw_solid_circle(G.viewport_canvas, p, 3, COLOR_RED, 10);
}
#endif
} }
/* Draw collision */ /* Draw collision */
@ -1144,7 +1161,7 @@ INTERNAL void user_update(void)
struct v2 end = xform_mul_v2(G.world_view, v2_add(point, v2_mul(v2_norm(ent->manifold_normal), len))); struct v2 end = xform_mul_v2(G.world_view, v2_add(point, v2_mul(v2_norm(ent->manifold_normal), len)));
draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color);
} }
#if 1 #if 0
/* Draw contact info */ /* Draw contact info */
{ {
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);