light: add new TraceFaces API which gives accurate info on the first hit face of a trace.

Need to use this for: dirtmapping, fence textures, GI
This commit is contained in:
Eric Wasylishen 2016-02-21 22:31:06 -07:00
parent 5a8c705e62
commit 4ed6db3020
3 changed files with 147 additions and 116 deletions

View File

@ -37,6 +37,15 @@
#define TRACE_HIT_LAVA (1 << 3)
#define TRACE_HIT_SKY (1 << 4)
typedef struct traceinfo_s {
vec3_t point;
const bsp2_dface_t *face;
} traceinfo_t;
bool TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end);
int Light_PointContents( const vec3_t point );
typedef struct {
@ -62,6 +71,12 @@ typedef struct {
*
* TraceLine will return a negative traceflag if the point 'start' resides
* inside a leaf with one of the contents types which stop the trace.
*
* ericw -- note, this should only be used for testing occlusion.
* the hitpoint is not accurate, imagine a solid cube floating in a room,
* only one of the 6 sides will be a node with a solid leaf child.
* Yet, which side is the node with the solid leaf child determines
* what the hit point will be.
*/
int TraceLine(const dmodel_t *model, const int traceflags,
const vec3_t start, const vec3_t end, tracepoint_t *hitpoint);

View File

@ -423,11 +423,11 @@ static int GetSurfaceVertex(const bsp2_t *bsp, const bsp2_dface_t *f, int v)
return bsp->dedges[-edge].v[1];
return bsp->dedges[edge].v[0];
}
static vec_t *GetSurfaceVertexPoint(const bsp2_t *bsp, const bsp2_dface_t *f, int v)
vec_t *GetSurfaceVertexPoint(const bsp2_t *bsp, const bsp2_dface_t *f, int v)
{
return bsp->dvertexes[GetSurfaceVertex(bsp, f, v)].point;
}
static vec_t *GetSurfaceVertexNormal(const bsp2_t *bsp, const bsp2_dface_t *f, int v)
vec_t *GetSurfaceVertexNormal(const bsp2_t *bsp, const bsp2_dface_t *f, int v)
{
return vertex_normals[GetSurfaceVertex(bsp, f, v)];
}

View File

@ -29,10 +29,16 @@ typedef struct tnode_s {
const bsp2_dnode_t *node;
} tnode_t;
typedef struct faceinfo_s {
plane_t *edgeplanes;
} faceinfo_t;
static tnode_t *tnodes;
static tnode_t *tnode_p;
static const bsp2_t *bsp_static;
static faceinfo_t *faceinfos;
// from hmap2
#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist)
@ -101,6 +107,46 @@ MakeTnodes_r(int nodenum, const bsp2_t *bsp)
}
}
vec_t *GetSurfaceVertexPoint(const bsp2_t *bsp, const bsp2_dface_t *f, int v);
static void GetFaceNormal(const bsp2_t *bsp, const bsp2_dface_t *face, plane_t *plane)
{
const dplane_t *dplane = &bsp->dplanes[face->planenum];
if (face->side) {
VectorSubtract(vec3_origin, dplane->normal, plane->normal);
plane->dist = -dplane->dist;
} else {
VectorCopy(dplane->normal, plane->normal);
plane->dist = dplane->dist;
}
}
void
MakeFaceInfo(const bsp2_t *bsp, const bsp2_dface_t *face, faceinfo_t *info)
{
info->edgeplanes = calloc(face->numedges, sizeof(plane_t));
plane_t surfplane;
GetFaceNormal(bsp, face, &surfplane);
for (int i=0; i<face->numedges; i++)
{
plane_t *dest = &info->edgeplanes[i];
const vec_t *v0 = GetSurfaceVertexPoint(bsp, face, i);
const vec_t *v1 = GetSurfaceVertexPoint(bsp, face, (i+1)%face->numedges);
vec3_t edgevec;
VectorSubtract(v1, v0, edgevec);
VectorNormalize(edgevec);
CrossProduct(edgevec, surfplane.normal, dest->normal);
dest->dist = DotProduct(dest->normal, v0);
}
}
void
MakeTnodes(const bsp2_t *bsp)
{
@ -109,6 +155,10 @@ MakeTnodes(const bsp2_t *bsp)
tnode_p = tnodes = malloc(bsp->numnodes * sizeof(tnode_t));
for (i = 0; i < bsp->nummodels; i++)
MakeTnodes_r(bsp->dmodels[i].headnode[0], bsp);
faceinfos = malloc(bsp->numfaces * sizeof(faceinfo_t));
for (i = 0; i < bsp->numfaces; i++)
MakeFaceInfo(bsp, &bsp->dfaces[i], &faceinfos[i]);
}
/*
@ -117,79 +167,6 @@ MakeTnodes(const bsp2_t *bsp)
* ============================================================================
*/
static qboolean
PointInTri(const vec3_t v0,
const vec3_t v1,
const vec3_t v2,
const vec3_t point,
const vec3_t facenormal)
{
vec3_t temp;
vec3_t normal[3];
vec_t dist[3];
VectorSubtract (v1, v0, temp);
VectorNormalize (temp);
CrossProduct (temp, facenormal, normal[0]);
dist[0] = DotProduct (v0, normal[0]);
VectorSubtract (v2, v1, temp);
VectorNormalize (temp);
CrossProduct (temp, facenormal, normal[1]);
dist[1] = DotProduct (v1, normal[1]);
VectorSubtract (v0, v2, temp);
VectorNormalize (temp);
CrossProduct (temp, facenormal, normal[2]);
dist[2] = DotProduct (v2, normal[2]);
// check each plane
if (DotProduct (normal[0], point) - dist[0] < 0) return false;
if (DotProduct (normal[1], point) - dist[1] < 0) return false;
if (DotProduct (normal[2], point) - dist[2] < 0) return false;
return true;
}
static qboolean
PointInFace(const bsp2_dface_t *face, const bsp2_t *bsp, const vec3_t point)
{
int i, edgenum;
dvertex_t *v0, *v1, *v2;
edgenum = bsp->dsurfedges[face->firstedge];
if (edgenum >= 0)
v0 = bsp->dvertexes + bsp->dedges[edgenum].v[0];
else
v0 = bsp->dvertexes + bsp->dedges[-edgenum].v[1];
for (i = 1; i < face->numedges - 1; i++) {
edgenum = bsp->dsurfedges[face->firstedge + i];
if (edgenum >= 0) {
v1 = bsp->dvertexes + bsp->dedges[edgenum].v[0];
v2 = bsp->dvertexes + bsp->dedges[edgenum].v[1];
} else {
v1 = bsp->dvertexes + bsp->dedges[-edgenum].v[1];
v2 = bsp->dvertexes + bsp->dedges[-edgenum].v[0];
}
vec3_t p0 = {v0->point[0], v0->point[1], v0->point[2]};
vec3_t p1 = {v1->point[0], v1->point[1], v1->point[2]};
vec3_t p2 = {v2->point[0], v2->point[1], v2->point[2]};
vec3_t facenormal;
VectorCopy(bsp->dplanes[face->planenum].normal, facenormal);
if (face->side) {
VectorSubtract(vec3_origin, facenormal, facenormal);
}
if (PointInTri(p0, p1, p2, point, facenormal)) return true;
}
return false;
}
static miptex_t *
MiptexForFace(const bsp2_dface_t *face, const bsp2_t *bsp)
{
@ -246,20 +223,23 @@ SampleTexture(const bsp2_dface_t *face, const bsp2_t *bsp, const vec3_t point)
return sample;
}
/* assumes point is on the same plane as face */
static qboolean
TestHitFace(bsp2_dface_t *face, const vec3_t point)
{
const dplane_t *plane;
vec_t d;
plane = &bsp_static->dplanes[face->planenum];
d = DotProduct(point, plane->normal) - plane->dist;
if (d >= -ON_EPSILON && d <= ON_EPSILON)
int facenum = face - bsp_static->dfaces;
const faceinfo_t *fi = &faceinfos[facenum];
for (int i=0; i<face->numedges; i++)
{
int val = PointInFace(face, bsp_static, point);
if (val)
return true;
/* faces toward the center of the face */
const plane_t *edgeplane = &fi->edgeplanes[i];
vec_t dist = DotProduct(point, edgeplane->normal) - edgeplane->dist;
if (dist < 0)
return false;
}
return false;
return true;
}
static bsp2_dface_t *
@ -271,8 +251,9 @@ SearchNodeForHitFace(const bsp2_dnode_t *bspnode, const vec3_t point)
{
bsp2_dface_t *face;
face = &bsp_static->dfaces[bspnode->firstface + i];
if (TestHitFace(face, point)) {
return face;
return face;
}
}
return NULL;
@ -311,14 +292,11 @@ TraceLine(const dmodel_t *model, const int traceflags,
tracestack_t *tstack, *crossnode;
tnode_t *tnode;
// const tracestack_t *const tstack_max = tracestack + MAX_TSTACK;
qboolean isbmodel;
if (traceflags <= 0)
Error("Internal error: %s - bad traceflags (%d)",
__func__, traceflags);
isbmodel = (model != tracelist[0]);
VectorCopy(start, front);
VectorCopy(stop, back);
@ -354,40 +332,17 @@ TraceLine(const dmodel_t *model, const int traceflags,
break;
}
if (tracehit != TRACE_HIT_NONE) {
qboolean done = true;
/* If we haven't crossed, start was inside flagged contents */
if (!crossnode)
return -tracehit;
if (isbmodel && testFenceTextures) {
const bsp2_dnode_t *bspnode = tnodes[crossnode->node].node;
bsp2_dface_t *face = SearchNodeForHitFace(bspnode, crossnode->front);
if (face) {
miptex_t *mt = MiptexForFace(face, bsp_static);
if (mt && mt->name[0] == '{') {
int sample = SampleTexture(face, bsp_static, crossnode->front);
done = (sample != 255);
} else {
/* Non-fence texture was hit, we are done */
done = true;
}
} else {
/* Continue tracing until we find the face we hit */
done = false;
}
if (hitpoint) {
hitpoint->dplane = crossnode->plane;
hitpoint->side = crossnode->side;
VectorCopy(crossnode->front, hitpoint->point);
}
if (done) {
if (hitpoint) {
hitpoint->dplane = crossnode->plane;
hitpoint->side = crossnode->side;
VectorCopy(crossnode->front, hitpoint->point);
}
return tracehit;
}
return tracehit;
}
/* If the stack is empty, no obstructions were hit */
@ -505,3 +460,64 @@ TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self)
return true;
}
/*
=============
TraceFaces
From lordhavoc, johnfitz (RecursiveLightPoint)
=============
*/
bool TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end)
{
float front, back, frac;
vec3_t mid;
tnode_t *tnode;
if (node < 0)
return false; // didn't hit anything
tnode = &tnodes[node]; //ericw
// calculate mid point
if (tnode->type < 3)
{
front = start[tnode->type] - tnode->dist;
back = end[tnode->type] - tnode->dist;
}
else
{
front = DotProduct(start, tnode->normal) - tnode->dist;
back = DotProduct(end, tnode->normal) - tnode->dist;
}
if ((back < 0) == (front < 0))
return TraceFaces (ti, tnode->children[front < 0], start, end);
frac = front / (front-back);
mid[0] = start[0] + (end[0] - start[0])*frac;
mid[1] = start[1] + (end[1] - start[1])*frac;
mid[2] = start[2] + (end[2] - start[2])*frac;
// go down front side
if (TraceFaces (ti, tnode->children[front < 0], start, mid))
return true; // hit something
else
{
// check for impact on this node
VectorCopy (mid, ti->point);
//ti->lightplane = tnode->plane;
bsp2_dface_t *face = SearchNodeForHitFace(tnode->node, mid);
if (face) {
ti->face = face;
return true;
}
//ericw -- no impact found on this node.
// go down back side
return TraceFaces (ti, tnode->children[front >= 0], mid, end);
}
}