From 73045b6642348c8d2fd8b45cae305bbf0344d444 Mon Sep 17 00:00:00 2001 From: aura Date: Wed, 4 Mar 2026 18:58:21 +0100 Subject: more collision improv --- src/game/physics/movement.cpp | 10 +++++----- src/game/world/bsp.cpp | 16 +++++++++++++--- src/game/world/bsp.h | 10 ++++++++++ src/game/world/trace.cpp | 44 +++++++++++++++++++++---------------------- 4 files changed, 50 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/game/physics/movement.cpp b/src/game/physics/movement.cpp index fce9d73..0b174e0 100644 --- a/src/game/physics/movement.cpp +++ b/src/game/physics/movement.cpp @@ -186,9 +186,6 @@ void gmove_categorize_pos() { gmove->ground = objl->world; } } - - if( gmove->ground ) - gmove->velocity.z = 0.f; } VEC3 gmove_clip_velocity( VEC3 in, VEC3 norm, F32 overbounce ) { @@ -433,8 +430,8 @@ void gmove_stay_on_ground() { if( tr.frac > 0.f && tr.frac < 1.f && !tr.startsolid && tr.normal.z >= 0.7f ) { F32 delta = fabs( gmove->pos.z - tr.point.z ); - if( delta > BSP_TRACE_EPSILON ) { - gmove->pos = tr.point + tr.normal * BSP_TRACE_EPSILON * 2.f; + if( delta > BSP_TRACE_EPSILON * 0.5f ) { + gmove->pos = tr.point; gmove_check_stuck( &gmove->pos ); } } @@ -636,6 +633,9 @@ void gmove_full_walk_move() { gmove_categorize_pos(); gmove_end_gravity(); + if( gmove->ground ) + gmove->velocity.z = 0.f; + gmove_check_falling(); } diff --git a/src/game/world/bsp.cpp b/src/game/world/bsp.cpp index 7f72e52..c33cac1 100644 --- a/src/game/world/bsp.cpp +++ b/src/game/world/bsp.cpp @@ -417,6 +417,10 @@ I32 bsp_build_nodes( } U8 bsp_edge_is_shared( BSP* bsp, VEC3 edge1a, VEC3 edge1b, VEC3 center, VEC3 ecross, U32 facei ) { + BSP_FACE* face = &bsp->faces[facei]; + VEC3 n = bsp_face_get_normal( face ); + U8 aligned = bsp_face_is_axis_aligned( face ); + for( U32 i = 0; i < bsp->faces.size; ++i ) { if( facei == i ) continue; @@ -425,6 +429,12 @@ U8 bsp_edge_is_shared( BSP* bsp, VEC3 edge1a, VEC3 edge1b, VEC3 center, VEC3 ecr if( other->verts.size < 3 ) continue; + VEC3 othern = bsp_face_get_normal( face ); + F32 d = vec_dot( n, othern ); + // dont create edge planes for planes that are axis-aligned and directly perpendicular + if( aligned && (d < BSP_NORM_EPSILON || d > 1.f - BSP_NORM_EPSILON) ) + continue; + VEC3 otherc{}; for( U32 vi = 0; vi < other->verts.size; ++vi ) otherc += other->verts[vi].pos; @@ -487,9 +497,6 @@ void bsp_gen_leaf_edges( BSP* bsp, I32 leaf_idx ) { if( fabsf( vec_dot( cross, facen ) ) > 0.995f ) continue; - if( !bsp_edge_is_shared( bsp, a, b, center, cross, faceidx ) ) - continue; - F32 d = vec_dot( cross, a ); BSP_PLANE plane = { cross, d }; U8 dupe = 0; @@ -500,6 +507,9 @@ void bsp_gen_leaf_edges( BSP* bsp, I32 leaf_idx ) { if( dupe ) continue; + if( !bsp_edge_is_shared( bsp, a, b, center, cross, faceidx ) ) + continue; + BSP_EDGE e; e.plane = plane; e.face = faceidx; diff --git a/src/game/world/bsp.h b/src/game/world/bsp.h index 8892108..3b84e07 100644 --- a/src/game/world/bsp.h +++ b/src/game/world/bsp.h @@ -125,6 +125,16 @@ inline VEC3 bsp_face_get_normal( BSP_FACE* f ){ return vec_normalize( vec_cross( v1 - v0, v2 - v0 ) ); } +inline U8 bsp_face_is_axis_aligned( BSP_FACE* f ) { + VEC3 n = bsp_face_get_normal( f ); + for( U32 i = 0; i < 3; ++i ) { + if( n[i] && fabsf( n[i] ) != 1.f ) + return 0; + } + + return 1; +} + inline void bsp_face_calc_extents( BSP_FACE* f ) { VEC3 mins{ +INFINITY, +INFINITY, +INFINITY }, maxs{ -INFINITY, -INFINITY, -INFINITY }; for( U32 i = 0; i < f->verts.size; ++i ) { diff --git a/src/game/world/trace.cpp b/src/game/world/trace.cpp index 1d32afe..25c0477 100644 --- a/src/game/world/trace.cpp +++ b/src/game/world/trace.cpp @@ -226,9 +226,7 @@ U8 bsp_trace_sweep_aabb_to_face( if( face->verts.size < 3 ) return 0; - VEC3 hullv = hull.max - hull.min; - AABB fhull = { face->mins - hullv, face->maxs + hullv }; - AABB fhullh = { face->mins - hullv * 0.5f, face->maxs + hullv * 0.5f }; + VEC3 norm = bsp_face_get_normal( face ); F32 d = vec_dot( norm, face->verts[0].pos ); F32 radius = aabb_support_radius( hull, norm ); @@ -237,19 +235,19 @@ U8 bsp_trace_sweep_aabb_to_face( F32 s0 = vec_dot( norm, trace->in_start ) - d; F32 ndir = vec_dot( norm, dir ); - F32 tdot = vec_dot( dir, norm ); - if( tdot >= 0 ) // dont collide with rear side + if( ndir >= 0 ) // dont collide with rear side return 0; + VEC3 hullv = hull.max - hull.min; + for( U32 i = 0; i < 3; ++i ) hullv[i] += BSP_EDGE_TOLERANCE; + AABB fhullh = { face->mins - hullv * 0.5f, face->maxs + hullv * 0.5f }; + if( fabsf( s0 ) <= radius + BSP_TRACE_EPSILON ) { if( aabb_contains_point( fhullh, start ) && point_in_inflated_poly( start, face, hull, norm ) ) { trace->hit = 1; trace->frac = 0.f; trace->startsolid = 1; trace->point = start; - trace->point.x = m_clamp( trace->point.x, fhullh.min.x, fhullh.max.x ); - trace->point.y = m_clamp( trace->point.y, fhullh.min.y, fhullh.max.y ); - trace->point.z = m_clamp( trace->point.z, fhullh.min.z, fhullh.max.z ); trace->normal = norm; trace->propid = face->propid; trace->faceid = face_idx; @@ -266,16 +264,12 @@ U8 bsp_trace_sweep_aabb_to_face( F32 t = m_clamp( t_enter, 0.f, 1.f ); VEC3 step = trace->in_start + dir * t; - if( !aabb_contains_point( fhull, step ) ) + if( !aabb_contains_point( fhullh, step ) ) return 0; if( !point_in_inflated_poly( step, face, hull, norm ) ) return 0; - step.x = m_clamp( step.x, fhullh.min.x, fhullh.max.x ); - step.y = m_clamp( step.y, fhullh.min.y, fhullh.max.y ); - step.z = m_clamp( step.z, fhullh.min.z, fhullh.max.z ); - trace->hit = 1; trace->frac = t; trace->point = step; @@ -320,7 +314,7 @@ U8 bsp_trace_sweep_aabb_to_leaf_edges( F32 t_exit = (-r - s0) / ndir; if( t_enter > t_exit ) { F32 tmp = t_enter; t_enter = t_exit; t_exit = tmp; } - if( t_exit < -BSP_TRACE_EPSILON || t_enter > 1.f + BSP_TRACE_EPSILON ) + if( t_exit < 0.f || t_enter > 1.f ) continue; F32 t = m_clamp( t_enter, 0.f, 1.f ); @@ -335,12 +329,15 @@ U8 bsp_trace_sweep_aabb_to_leaf_edges( F32 along = vec_dot( step - e->v1, edir ); VEC3 proj = e->v1 + edir * m_clamp( along, 0.f, elen ); F32 dist = vec_dist( proj, step ); + VEC3 ec = vec_cross( edir, n ); + F32 nlen = vec_len( ec ); + if( nlen < 0.001f ) + continue; + ec *= (1.f / nlen); - F32 expand = aabb_support_radius( hull, n ); - if( dist > BSP_TRACE_EPSILON ) { - if( dist > expand - BSP_EDGE_TOLERANCE ) - continue; - } + F32 expand = aabb_support_radius( hull, ec ); + if( dist - expand > r * 0.5f ) + continue; if( t < best ) { best = t; @@ -397,17 +394,20 @@ U8 bsp_trace_sweep_aabb_to_leaf( } } + best = FLT_MAX; U8 ehit = bsp_trace_sweep_aabb_to_leaf_edges( bsp, &edgehit, hull, start, end, leaf_idx, &best ); - if( hit || ehit ) { if( ehit && !hit ) *trace = edgehit; else if( !ehit && hit ) *trace = besthit; - else if( edgehit.frac < besthit.frac ) + else if( edgehit.frac <= besthit.frac + BSP_TRACE_EPSILON ) *trace = edgehit; - else + else { *trace = besthit; + if( edgehit.normal.z > besthit.normal.z ) + trace->normal.z = edgehit.normal.z; + } trace->hit = 1; return 1; } -- cgit v1.2.3