From a16877b21a3d5ddec652ce9ed030e7f32c3fc0e7 Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 20 Apr 2005 11:16:36 +0000 Subject: [PATCH] reimplemented rtlight portal culling (used for compiled rtlights, and can be used for dlights but that is often a major speed loss) added additional bounding box and triangle facing checks to rtlight compilation, triangles outside the box are no longer drawn git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5204 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_rsurf.c | 45 ++++++++++++++++++++++------- portals.c | 83 +++++++++++++++++++++++++++++++++++++++--------------- portals.h | 2 +- r_shadow.c | 3 ++ r_shadow.h | 1 + 5 files changed, 100 insertions(+), 34 deletions(-) diff --git a/gl_rsurf.c b/gl_rsurf.c index 16e50846..13b197a4 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "r_shadow.h" +#include "portals.h" #define MAX_LIGHTMAP_SIZE 256 @@ -1771,7 +1772,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; - if (info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + if (PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]) && info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) { SETPVSBIT(info->outsurfacepvs, surfaceindex); info->outsurfacelist[info->outnumsurfaces++] = surfaceindex; @@ -1820,25 +1821,29 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa else info.pvs = NULL; R_UpdateAllTextureInfo(ent); - /* if (r_shadow_compilingrtlight) { - Portal_Visibility(info.model, info.relativelightorigin, leafmark, surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs) + // use portal recursion for exact light volume culling, and exact surface checking + Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs); + } + else if (r_shadow_realtime_dlight_portalculling.integer) + { + // use portal recursion for exact light volume culling, but not the expensive exact surface checking + Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs); } else - */ { // use BSP recursion as lights are often small R_Q1BSP_RecursiveGetLightInfo(&info, info.model->brush.data_nodes); } // limit combined leaf box to light boundaries - outmins[0] = max(info.outmins[0], info.lightmins[0]); - outmins[1] = max(info.outmins[1], info.lightmins[1]); - outmins[2] = max(info.outmins[2], info.lightmins[2]); - outmaxs[0] = min(info.outmaxs[0], info.lightmaxs[0]); - outmaxs[1] = min(info.outmaxs[1], info.lightmaxs[1]); - outmaxs[2] = min(info.outmaxs[2], info.lightmaxs[2]); + outmins[0] = max(info.outmins[0] - 1, info.lightmins[0]); + outmins[1] = max(info.outmins[1] - 1, info.lightmins[1]); + outmins[2] = max(info.outmins[2] - 1, info.lightmins[2]); + outmaxs[0] = min(info.outmaxs[0] + 1, info.lightmaxs[0]); + outmaxs[1] = min(info.outmaxs[1] + 1, info.lightmaxs[1]); + outmaxs[2] = min(info.outmaxs[2] + 1, info.lightmaxs[2]); *outnumleafspointer = info.outnumleafs; *outnumsurfacespointer = info.outnumsurfaces; @@ -1889,7 +1894,27 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t // if compiling an rtlight, capture the mesh t = surface->texture; if ((t->basematerialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL) + { +#if 1 + int tri; + int *e; + float *lightmins, *lightmaxs, *v[3], *vertex3f; + e = surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle; + vertex3f = surface->groupmesh->data_vertex3f; + lightmins = r_shadow_compilingrtlight->cullmins; + lightmaxs = r_shadow_compilingrtlight->cullmaxs; + for (tri = 0;tri < surface->num_triangles;tri++, e += 3) + { + v[0] = vertex3f + e[0] * 3; + v[1] = vertex3f + e[1] * 3; + v[2] = vertex3f + e[2] * 3; + if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, 1, e); + } +#else Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)); +#endif + } } else if (ent != r_refdef.worldentity || r_worldsurfacevisible[surfacelist[surfacelistindex]]) { diff --git a/portals.c b/portals.c index 4f62b17e..d3df4481 100644 --- a/portals.c +++ b/portals.c @@ -325,8 +325,12 @@ typedef struct portalrecursioninfo_s int numfrustumplanes; vec3_t boxmins; vec3_t boxmaxs; - qbyte *surfacemark; - qbyte *leafmark; + int numsurfaces; + int *surfacelist; + qbyte *surfacepvs; + int numleafs; + int *leaflist; + qbyte *leafpvs; model_t *model; vec3_t eye; float *updateleafsmins; @@ -337,35 +341,39 @@ portalrecursioninfo_t; void Portal_RecursiveFlow_ExactLeafFaces(portalrecursioninfo_t *info, int *mark, int numleafsurfaces, int firstclipplane, int numclipplanes) { int i, j, *elements; + float *v[3], *vertex3f; vec3_t trimins, trimaxs; msurface_t *surface; for (i = 0;i < numleafsurfaces;i++, mark++) { - if (!info->surfacemark[*mark]) + if (!CHECKPVSBIT(info->surfacepvs, *mark)) { - // FIXME? this assumes q1bsp polygon surfaces surface = info->model->brush.data_surfaces + *mark; + if (!BoxesOverlap(surface->mins, surface->maxs, info->boxmins, info->boxmaxs)) + continue; + vertex3f = surface->groupmesh->data_vertex3f; for (j = 0, elements = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);j < surface->num_triangles;j++, elements += 3) { - VectorCopy((surface->groupmesh->data_vertex3f + elements[0] * 3), trianglepoints[0]); - VectorCopy((surface->groupmesh->data_vertex3f + elements[1] * 3), trianglepoints[1]); - VectorCopy((surface->groupmesh->data_vertex3f + elements[2] * 3), trianglepoints[2]); - if (PointInfrontOfTriangle(info->eye, trianglepoints[0], trianglepoints[1], trianglepoints[2])) + v[0] = vertex3f + elements[0] * 3; + v[1] = vertex3f + elements[1] * 3; + v[2] = vertex3f + elements[2] * 3; + if (PointInfrontOfTriangle(info->eye, v[0], v[1], v[2])) { - trimins[0] = min(trianglepoints[0][0], min(trianglepoints[1][0], trianglepoints[2][0])); - trimaxs[0] = max(trianglepoints[0][0], max(trianglepoints[1][0], trianglepoints[2][0])); - trimins[1] = min(trianglepoints[0][1], min(trianglepoints[1][1], trianglepoints[2][1])); - trimaxs[1] = max(trianglepoints[0][1], max(trianglepoints[1][1], trianglepoints[2][1])); - trimins[2] = min(trianglepoints[0][2], min(trianglepoints[1][2], trianglepoints[2][2])); - trimaxs[2] = max(trianglepoints[0][2], max(trianglepoints[1][2], trianglepoints[2][2])); + trimins[0] = min(v[0][0], min(v[1][0], v[2][0])); + trimaxs[0] = max(v[0][0], max(v[1][0], v[2][0])); + trimins[1] = min(v[0][1], min(v[1][1], v[2][1])); + trimaxs[1] = max(v[0][1], max(v[1][1], v[2][1])); + trimins[2] = min(v[0][2], min(v[1][2], v[2][2])); + trimaxs[2] = max(v[0][2], max(v[1][2], v[2][2])); if (BoxesOverlap(trimins, trimaxs, info->boxmins, info->boxmaxs)) - if (Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, trianglepoints[0], 3, &portaltemppoints2[0][0], 256) >= 3) + if (Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, v[0], 3, &portaltemppoints2[0][0], 256) >= 3) break; } } if (j == surface->num_triangles) continue; - info->surfacemark[*mark] = true; + SETPVSBIT(info->surfacepvs, *mark); + info->surfacelist[info->numsurfaces++] = *mark; } } } @@ -384,17 +392,38 @@ void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, int first if (info->updateleafsmaxs && info->updateleafsmaxs[i] < leaf->maxs[i]) info->updateleafsmaxs[i] = leaf->maxs[i]; } - if (info->leafmark) - info->leafmark[leaf - info->model->brush.data_leafs] = true; + + if (info->leafpvs) + { + int leafindex = leaf - info->model->brush.data_leafs; + if (!CHECKPVSBIT(info->leafpvs, leafindex)) + { + SETPVSBIT(info->leafpvs, leafindex); + info->leaflist[info->numleafs++] = leafindex; + } + } // mark surfaces in leaf that can be seen through portal - if (leaf->numleafsurfaces && info->surfacemark) + if (leaf->numleafsurfaces && info->surfacepvs) { if (info->exact) Portal_RecursiveFlow_ExactLeafFaces(info, leaf->firstleafsurface, leaf->numleafsurfaces, firstclipplane, numclipplanes); else + { for (i = 0;i < leaf->numleafsurfaces;i++) - info->surfacemark[leaf->firstleafsurface[i]] = true; + { + int surfaceindex = leaf->firstleafsurface[i]; + if (!CHECKPVSBIT(info->surfacepvs, surfaceindex)) + { + msurface_t *surface = info->model->brush.data_surfaces + surfaceindex; + if (BoxesOverlap(surface->mins, surface->maxs, info->boxmins, info->boxmaxs)) + { + SETPVSBIT(info->surfacepvs, surfaceindex); + info->surfacelist[info->numsurfaces++] = surfaceindex; + } + } + } + } } // follow portals into other leafs @@ -459,7 +488,7 @@ void Portal_RecursiveFindLeafForFlow(portalrecursioninfo_t *info, mnode_t *node) } } -void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte *surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs) +void Portal_Visibility(model_t *model, const vec3_t eye, int *leaflist, qbyte *leafpvs, int *numleafspointer, int *surfacelist, qbyte *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs) { int i; portalrecursioninfo_t info; @@ -492,8 +521,12 @@ void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte VectorCopy(boxmins, info.boxmins); VectorCopy(boxmaxs, info.boxmaxs); info.exact = exact; - info.surfacemark = surfacemark; - info.leafmark = leafmark; + info.numsurfaces = 0; + info.surfacelist = surfacelist; + info.surfacepvs = surfacepvs; + info.numleafs = 0; + info.leaflist = leaflist; + info.leafpvs = leafpvs; info.model = model; VectorCopy(eye, info.eye); info.numfrustumplanes = numfrustumplanes; @@ -506,5 +539,9 @@ void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte Con_Printf("Portal_RecursiveFlow: ran out of %d plane stack when recursing through portals\n", MAXRECURSIVEPORTALPLANES); if (ranoutofportals) Con_Printf("Portal_RecursiveFlow: ran out of %d portal stack when recursing through portals\n", MAXRECURSIVEPORTALS); + if (numsurfacespointer) + *numsurfacespointer = info.numsurfaces; + if (numleafspointer) + *numleafspointer = info.numleafs; } diff --git a/portals.h b/portals.h index 6e96ce01..416e431e 100644 --- a/portals.h +++ b/portals.h @@ -4,7 +4,7 @@ int Portal_CheckPolygon(model_t *model, vec3_t eye, float *polypoints, int numpoints); int Portal_CheckBox(model_t *model, vec3_t eye, vec3_t a, vec3_t b); -void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte *surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs); +void Portal_Visibility(model_t *model, const vec3_t eye, int *leaflist, qbyte *leafpvs, int *numleafspointer, int *surfacelist, qbyte *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs); #endif diff --git a/r_shadow.c b/r_shadow.c index 6edd54d6..379dd078 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -176,6 +176,7 @@ cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"}; cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"}; cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"}; cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"}; +cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"}; cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"}; cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"}; cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"}; @@ -560,6 +561,7 @@ void R_Shadow_Help_f(void) "r_shadow_projectdistance : shadow volume projection distance\n" "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n" "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n" +"r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n" "r_shadow_realtime_world : use high quality world lighting mode\n" "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n" "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n" @@ -599,6 +601,7 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_projectdistance); Cvar_RegisterVariable(&r_shadow_realtime_dlight); Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows); + Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling); Cvar_RegisterVariable(&r_shadow_realtime_world); Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows); Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps); diff --git a/r_shadow.h b/r_shadow.h index 571f81d1..99417461 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -16,6 +16,7 @@ extern cvar_t r_shadow_portallight; extern cvar_t r_shadow_projectdistance; extern cvar_t r_shadow_realtime_dlight; extern cvar_t r_shadow_realtime_dlight_shadows; +extern cvar_t r_shadow_realtime_dlight_portalculling; extern cvar_t r_shadow_realtime_world; extern cvar_t r_shadow_realtime_world_dlightshadows; extern cvar_t r_shadow_realtime_world_lightmaps; -- 2.39.2