Use faster SV_RecursiveHullCheck

This commit is contained in:
Steam Deck User 2023-02-12 19:54:42 -05:00
parent 5b00aecb8c
commit d6ed5b3866
7 changed files with 169 additions and 120 deletions

View file

@ -58,7 +58,7 @@ void TraceLine (vec3_t start, vec3_t end, vec3_t impact)
trace_t trace; trace_t trace;
memset (&trace, 0, sizeof(trace)); memset (&trace, 0, sizeof(trace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, start, end, &trace);
VectorCopy (trace.endpos, impact); VectorCopy (trace.endpos, impact);
} }

View file

@ -365,7 +365,7 @@ qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
trace_t trace; trace_t trace;
memset (&trace, 0, sizeof(trace)); memset (&trace, 0, sizeof(trace));
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace)) if (!SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, start, end, &trace))
{ {
if (trace.fraction < 1) if (trace.fraction < 1)
{ {
@ -454,7 +454,7 @@ void CL_UpdateTEnts (void)
VectorAdd(org, forward, b->end); VectorAdd(org, forward, b->end);
memset (&trace, 0, sizeof(trace_t)); memset (&trace, 0, sizeof(trace_t));
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, org, b->end, &trace)) if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, org, b->end, &trace))
VectorCopy(trace.endpos, b->end); VectorCopy(trace.endpos, b->end);
} }
} }

View file

@ -82,7 +82,7 @@ extern int nanmask;
#define VectorNegate(a, b) ((b)[0] = -(a)[0], (b)[1] = -(a)[1], (b)[2] = -(a)[2]) #define VectorNegate(a, b) ((b)[0] = -(a)[0], (b)[1] = -(a)[1], (b)[2] = -(a)[2])
#define VectorSet(v, x, y, z) ((v)[0] = (x), (v)[1] = (y), (v)[2] = (z)) #define VectorSet(v, x, y, z) ((v)[0] = (x), (v)[1] = (y), (v)[2] = (z))
#define VectorRandom(v) {do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1);} #define VectorRandom(v) {do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1);}
#define DoublePrecisionDotProduct(x,y) ((double)(x)[0]*(y)[0]+(double)(x)[1]*(y)[1]+(double)(x)[2]*(y)[2])
#define VSM(a,b,c) {c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;} #define VSM(a,b,c) {c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;}
#define VectorNormalizeFast( v ){float ilength = (float)rsqrt(DotProduct(v,v));v[0] *= ilength;v[1] *= ilength;v[2] *= ilength; } #define VectorNormalizeFast( v ){float ilength = (float)rsqrt(DotProduct(v,v));v[0] *= ilength;v[1] *= ilength;v[2] *= ilength; }

View file

@ -3140,7 +3140,7 @@ void QMB_LaserSight (void)
memset (&trace, 0, sizeof(trace_t)); memset (&trace, 0, sizeof(trace_t));
trace.fraction = 1; trace.fraction = 1;
SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, dest, &trace); SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, start, dest, &trace);
start[2]+=cl.crouch; start[2]+=cl.crouch;
AddParticle (p_streaktrail, start, 1, 2, 0.02, color, trace.endpos);// draw the line AddParticle (p_streaktrail, start, 1, 2, 0.02, color, trace.endpos);// draw the line
@ -3203,7 +3203,7 @@ void QMB_LightningBeam (vec3_t start, vec3_t end)
if (qmb_initialized && r_part_sparks.value) if (qmb_initialized && r_part_sparks.value)
{ {
memset (&trace, 0, sizeof(trace_t)); memset (&trace, 0, sizeof(trace_t));
if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace)) if (!SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, start, end, &trace))
{ {
if (trace.fraction < 1) if (trace.fraction < 1)
{ {

View file

@ -1334,7 +1334,7 @@ void GL_DrawAliasBlendedShadow (aliashdr_t *paliashdr, int pose1, int pose2, ent
VectorCopy (e->origin, downmove); VectorCopy (e->origin, downmove);
downmove[2] = downmove[2] - 4096; downmove[2] = downmove[2] - 4096;
memset (&downtrace, 0, sizeof(downtrace)); memset (&downtrace, 0, sizeof(downtrace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, e->origin, downmove, &downtrace);
#ifdef PSP_VFPU #ifdef PSP_VFPU
s1 = vfpu_sinf( e->angles[1]/180*M_PI); s1 = vfpu_sinf( e->angles[1]/180*M_PI);
@ -1711,7 +1711,7 @@ void GL_DrawQ2AliasShadow (entity_t *e, md2_t *pheader, int lastpose, int pose,
VectorCopy (e->origin, downmove); VectorCopy (e->origin, downmove);
downmove[2] = downmove[2] - 4096; downmove[2] = downmove[2] - 4096;
memset (&downtrace, 0, sizeof(downtrace)); memset (&downtrace, 0, sizeof(downtrace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, e->origin, downmove, &downtrace);
#ifdef PSP_VFPU #ifdef PSP_VFPU
s1 = vfpu_sinf( e->angles[1]/180*M_PI); s1 = vfpu_sinf( e->angles[1]/180*M_PI);
@ -1853,7 +1853,7 @@ void R_SetupQ2AliasFrame (entity_t *e, md2_t *pheader)
downmove[2] = downmove[2] - 4096; downmove[2] = downmove[2] - 4096;
memset (&downtrace, 0, sizeof(downtrace)); memset (&downtrace, 0, sizeof(downtrace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, e->origin, downmove, &downtrace);
sceGuDisable (GU_TEXTURE_2D); sceGuDisable (GU_TEXTURE_2D);
sceGuEnable (GU_BLEND); sceGuEnable (GU_BLEND);
@ -3362,7 +3362,7 @@ void R_DrawQ3Model (entity_t *ent)
VectorCopy (ent->origin, downmove); VectorCopy (ent->origin, downmove);
downmove[2] -= farclip; downmove[2] -= farclip;
memset (&downtrace, 0, sizeof(downtrace)); memset (&downtrace, 0, sizeof(downtrace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, ent->origin, downmove, &downtrace); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, ent->origin, downmove, &downtrace);
lheight = ent->origin[2] - lightspot[2]; lheight = ent->origin[2] - lightspot[2];

View file

@ -591,30 +591,165 @@ LINE TESTING IN HULLS
=============================================================================== ===============================================================================
*/ */
enum
{
rht_solid,
rht_empty,
rht_impact
};
struct rhtctx_s
{
unsigned int hitcontents;
vec3_t start, end;
dclipnode_t *clipnodes;
mplane_t *planes;
};
// 1/32 epsilon to keep floating point happy // 1/32 epsilon to keep floating point happy
#define DIST_EPSILON (0.03125) #define DIST_EPSILON (0.03125)
/*
==================
Q1BSP_RecursiveHullTrace
This does the core traceline/tracebox logic.
This version is from FTE and attempts to be more numerically stable than vanilla.
This is achieved by recursing at the actual decision points instead of vanilla's habit of vanilla's habit of using points that are outside of the child's volume.
It also uses itself to test solidity on the other side of the node, which ensures consistent precision.
The actual collision point is (still) biased by an epsilon, so the end point shouldn't be inside walls either way.
FTE's version 'should' be more compatible with vanilla than DP's (which doesn't take care with allsolid).
ezQuake also has a version of this logic, but I trust mine more.
==================
*/
static int Q1BSP_RecursiveHullTrace (struct rhtctx_s *ctx, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
{
dclipnode_t *node;
mplane_t *plane;
float t1, t2;
vec3_t mid;
int side;
float midf;
int rht;
reenter:
if (num < 0)
{
/*hit a leaf*/
if (num == CONTENTS_SOLID)
{
if (trace->allsolid)
trace->startsolid = true;
return rht_solid;
}
else
{
trace->allsolid = false;
if (num == CONTENTS_EMPTY)
trace->inopen = true;
else if (num != CONTENTS_SOLID)
trace->inwater = true;
return rht_empty;
}
}
/*its a node*/
/*get the node info*/
node = ctx->clipnodes + num;
plane = ctx->planes + node->planenum;
if (plane->type < 3)
{
t1 = p1[plane->type] - plane->dist;
t2 = p2[plane->type] - plane->dist;
}
else
{
t1 = DoublePrecisionDotProduct (plane->normal, p1) - plane->dist;
t2 = DoublePrecisionDotProduct (plane->normal, p2) - plane->dist;
}
/*if its completely on one side, resume on that side*/
if (t1 >= 0 && t2 >= 0)
{
//return Q1BSP_RecursiveHullTrace (hull, node->children[0], p1f, p2f, p1, p2, trace);
num = node->children[0];
goto reenter;
}
if (t1 < 0 && t2 < 0)
{
//return Q1BSP_RecursiveHullTrace (hull, node->children[1], p1f, p2f, p1, p2, trace);
num = node->children[1];
goto reenter;
}
if (plane->type < 3)
{
t1 = ctx->start[plane->type] - plane->dist;
t2 = ctx->end[plane->type] - plane->dist;
}
else
{
t1 = DotProduct (plane->normal, ctx->start) - plane->dist;
t2 = DotProduct (plane->normal, ctx->end) - plane->dist;
}
side = t1 < 0;
midf = t1 / (t1 - t2);
if (midf < p1f) midf = p1f;
if (midf > p2f) midf = p2f;
VectorInterpolate(ctx->start, midf, ctx->end, mid);
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side], p1f, midf, p1, mid, trace);
if (rht != rht_empty && !trace->allsolid)
return rht;
rht = Q1BSP_RecursiveHullTrace(ctx, node->children[side^1], midf, p2f, mid, p2, trace);
if (rht != rht_solid)
return rht;
if (side)
{
/*we impacted the back of the node, so flip the plane*/
trace->plane.dist = -plane->dist;
VectorNegate(plane->normal, trace->plane.normal);
midf = (t1 + DIST_EPSILON) / (t1 - t2);
}
else
{
/*we impacted the front of the node*/
trace->plane.dist = plane->dist;
VectorCopy(plane->normal, trace->plane.normal);
midf = (t1 - DIST_EPSILON) / (t1 - t2);
}
t1 = DoublePrecisionDotProduct (trace->plane.normal, ctx->start) - trace->plane.dist;
t2 = DoublePrecisionDotProduct (trace->plane.normal, ctx->end) - trace->plane.dist;
midf = (t1 - DIST_EPSILON) / (t1 - t2);
midf = CLAMP(0, midf, 1);
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
VectorInterpolate(ctx->start, midf, ctx->end, trace->endpos);
return rht_impact;
}
/* /*
================== ==================
SV_RecursiveHullCheck SV_RecursiveHullCheck
================== ==================
*/ */
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) qboolean SV_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, trace_t *trace)
{ {
dclipnode_t *node; if (p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2])
mplane_t *plane;
float t1, t2;
float frac;
int i;
vec3_t mid;
int side;
float midf;
// check for empty
if (num < 0)
{ {
if (num != CONTENTS_SOLID) /*points cannot cross planes, so do it faster*/
int c = SV_HullPointContents(hull, hull->firstclipnode, p1);
//trace->contents = c;
if (c != CONTENTS_SOLID)
{ {
trace->allsolid = false; trace->allsolid = false;
if (num == CONTENTS_EMPTY) if (num == CONTENTS_EMPTY)
@ -624,103 +759,17 @@ qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec
} }
else else
trace->startsolid = true; trace->startsolid = true;
return true; // empty return true;
}
if (num < hull->firstclipnode || num > hull->lastclipnode)
Sys_Error ("SV_RecursiveHullCheck: bad node number");
//
// find the point distances
//
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
if (plane->type < 3)
{
t1 = p1[plane->type] - plane->dist;
t2 = p2[plane->type] - plane->dist;
} }
else else
{ {
t1 = DotProduct (plane->normal, p1) - plane->dist; struct rhtctx_s ctx;
t2 = DotProduct (plane->normal, p2) - plane->dist; VectorCopy(p1, ctx.start);
VectorCopy(p2, ctx.end);
ctx.clipnodes = hull->clipnodes;
ctx.planes = hull->planes;
return Q1BSP_RecursiveHullTrace(&ctx, hull->firstclipnode, 0, 1, p1, p2, trace) != rht_impact;
} }
#if 1
if (t1 >= 0 && t2 >= 0)
return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
if (t1 < 0 && t2 < 0)
return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
#else
if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
#endif
// put the crosspoint DIST_EPSILON pixels on the near side
if (t1 < 0)
frac = (t1 + DIST_EPSILON)/(t1-t2);
else
frac = (t1 - DIST_EPSILON)/(t1-t2);
if (frac < 0)
frac = 0;
if (frac > 1)
frac = 1;
midf = p1f + (p2f - p1f)*frac;
for (i=0 ; i<3 ; i++)
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
side = (t1 < 0);
// move up to the node
if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
return false;
if (SV_HullPointContents (hull, node->children[side^1], mid)
!= CONTENTS_SOLID)
// go past the node
return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
if (trace->allsolid)
return false; // never got out of the solid area
//==================
// the other side of the node is solid, this is the impact point
//==================
if (!side)
{
VectorCopy (plane->normal, trace->plane.normal);
trace->plane.dist = plane->dist;
}
else
{
VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
trace->plane.dist = -plane->dist;
}
while (SV_HullPointContents (hull, hull->firstclipnode, mid)
== CONTENTS_SOLID)
{ // shouldn't really happen, but does occasionally
frac -= 0.1;
if (frac < 0)
{
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
Con_DPrintf ("backup past 0\n");
return false;
}
midf = p1f + (p2f - p1f)*frac;
for (i=0 ; i<3 ; i++)
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
}
trace->fraction = midf;
VectorCopy (mid, trace->endpos);
return false;
} }
/* /*
@ -844,8 +893,9 @@ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t max
} }
// trace a line through the apropriate clipping hull // trace a line through the apropriate clipping hull
SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); //(hull_t *hull, int num, vec3_t p1, vec3_t p2, trace_t *trace)
SV_RecursiveHullCheck (hull, hull->firstclipnode, start_l, end_l, &trace);
if( trace.fraction != 1.0f ) if( trace.fraction != 1.0f )
{ {

View file

@ -65,8 +65,7 @@ int SV_TruePointContents (vec3_t p);
#define check_angles( x ) ( (int)x == 90 || (int)x == 180 || (int)x == 270 || (int)x == -90 || (int)x == -180 || (int)x == -270 ) #define check_angles( x ) ( (int)x == 90 || (int)x == 180 || (int)x == 270 || (int)x == -90 || (int)x == -180 || (int)x == -270 )
edict_t *SV_TestEntityPosition (edict_t *ent); edict_t *SV_TestEntityPosition (edict_t *ent);
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace); qboolean SV_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, trace_t *trace);
int SV_HullPointContents (hull_t *hull, int num, vec3_t p); int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict); trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict);