X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=r_shadow.c;h=b774a5c325cbe02b68643ac989a9f0329edb0e83;hp=ebb0e469f3700693210e2a11c9f76fbb64de3fcc;hb=05dbb25f75f5aeff3822a7feccad0e53a1d3c5be;hpb=1b5514b0efe6eb17ef86493eaedee1d553b08c80 diff --git a/r_shadow.c b/r_shadow.c index ebb0e469..b774a5c3 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -334,6 +334,13 @@ cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve perfor cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"}; cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"}; cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"}; +cvar_t r_shadow_culllights_pvs = {CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"}; +cvar_t r_shadow_culllights_trace = {CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"}; +cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"}; +cvar_t r_shadow_culllights_trace_enlarge = {CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0.1", "make light bounds bigger by *1.0+enlarge"}; +cvar_t r_shadow_culllights_trace_samples = {CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"}; +cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"}; +cvar_t r_shadow_culllights_trace_delay = {CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"}; cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"}; cvar_t r_shadow_bouncegrid_blur = {CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"}; cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"}; @@ -464,19 +471,19 @@ static void R_Shadow_SetShadowMode(void) { if (!r_fb.usedepthtextures) r_shadow_shadowmappcf = 1; - else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler) + else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler) { r_shadow_shadowmapsampler = true; r_shadow_shadowmappcf = 1; } else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) r_shadow_shadowmappcf = 1; - else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa")) + else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa")) r_shadow_shadowmappcf = 1; - else + else r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; } - else + else { r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; switch (r_shadow_shadowmapfilterquality) @@ -804,6 +811,13 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_polygonfactor); Cvar_RegisterVariable(&r_shadow_polygonoffset); Cvar_RegisterVariable(&r_shadow_texture3d); + Cvar_RegisterVariable(&r_shadow_culllights_pvs); + Cvar_RegisterVariable(&r_shadow_culllights_trace); + Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter); + Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge); + Cvar_RegisterVariable(&r_shadow_culllights_trace_samples); + Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples); + Cvar_RegisterVariable(&r_shadow_culllights_trace_delay); Cvar_RegisterVariable(&r_shadow_bouncegrid); Cvar_RegisterVariable(&r_shadow_bouncegrid_blur); Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse); @@ -1607,7 +1621,7 @@ static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float borde int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 }; float scale = (size - 2*border)/size, len; float bias = border / (float)(size - border), dp, dn, ap, an; - // check if cone enclosing side would cross frustum plane + // check if cone enclosing side would cross frustum plane scale = 2 / (scale*scale + 2); Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o); for (i = 0;i < 5;i++) @@ -2565,7 +2579,7 @@ static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value; // prevent any garbage in alignment padded areas as we'll be using memcmp - memset(settings, 0, sizeof(*settings)); + memset(settings, 0, sizeof(*settings)); // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters settings->staticmode = s; @@ -2846,12 +2860,26 @@ static void R_Shadow_BounceGrid_AssignPhotons(r_shadow_bouncegrid_settings_t *se w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale); if (!settings->staticmode) { - if (R_CullBox(cullmins, cullmaxs)) - continue; + // skip if the expanded light box does not touch any visible leafs if (r_refdef.scene.worldmodel - && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs - && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs)) + && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs + && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs)) continue; + // skip if the expanded light box is not visible to traceline + // note that PrepareLight already did this check but for a smaller box, so we + // end up casting more traces per frame per light when using bouncegrid, which + // is probably fine (and they use the same timer) + if (r_shadow_culllights_trace.integer) + { + if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs)) + rtlight->trace_timer = realtime; + if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value) + return; + } + // skip if expanded light box is offscreen + if (R_CullBox(cullmins, cullmaxs)) + continue; + // skip if overall light intensity is zero if (w * VectorLength2(rtlight->color) == 0.0f) continue; } @@ -4138,7 +4166,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) // this variable must be set for the CompileShadowVolume/CompileShadowMap code r_shadow_compilingrtlight = rtlight; R_FrameData_SetMark(); - model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL); + model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL, rtlight->shadow == 0); R_FrameData_ReturnToMark(); numleafpvsbytes = (model->brush.num_leafs + 7) >> 3; numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3; @@ -4656,7 +4684,7 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight) } */ - // if lightstyle is currently off, don't draw the light + // skip if lightstyle is currently off if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f)) return; @@ -4664,10 +4692,27 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight) if (nolight) return; - // if the light box is offscreen, skip it + // skip if the light box is not touching any visible leafs + if (r_shadow_culllights_pvs.integer + && r_refdef.scene.worldmodel + && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs + && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs)) + return; + + // skip if the light box is not visible to traceline + if (r_shadow_culllights_trace.integer) + { + if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs)) + rtlight->trace_timer = realtime; + if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value) + return; + } + + // skip if the light box is off screen if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs)) return; + // in the typical case this will be quickly replaced by GetLightInfo VectorCopy(rtlight->cullmins, rtlight->cached_cullmins); VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs); @@ -4694,7 +4739,7 @@ static void R_Shadow_PrepareLight(rtlight_t *rtlight) { // dynamic light, world available and can receive realtime lighting // calculate lit surfaces and leafs - r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes); + r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes, rtlight->shadow == 0); R_Shadow_ComputeShadowCasterCullingPlanes(rtlight); leaflist = r_shadow_buffer_leaflist; leafpvs = r_shadow_buffer_leafpvs; @@ -5646,7 +5691,7 @@ static void R_Shadow_DrawModelShadowMaps(void) VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin); dot1 = DotProduct(r_refdef.view.forward, shadowdir); dot2 = DotProduct(r_refdef.view.up, shadowdir); - if (fabs(dot1) <= fabs(dot2)) + if (fabs(dot1) <= fabs(dot2)) VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward); else VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward); @@ -5706,7 +5751,7 @@ static void R_Shadow_DrawModelShadowMaps(void) Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix); Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix); - Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); + Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias); Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix); Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix); @@ -5935,13 +5980,10 @@ static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale) { switch(vid.renderpath) { - case RENDERPATH_GL11: - case RENDERPATH_GL13: case RENDERPATH_GL20: case RENDERPATH_GLES1: case RENDERPATH_GLES2: #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2) - CHECKGLERROR // See if we can use the GPU-side method to prevent implicit sync if (vid.support.arb_query_buffer_object) { #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i))) @@ -5956,13 +5998,23 @@ static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale) qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4)); qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf); occlude = MATERIALFLAG_OCCLUDE; - } else { - qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels); - qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels); - if (visiblepixels < 1 || allpixels < 1) - return; - rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1); + cscale *= rtlight->corona_visibility; + CHECKGLERROR + break; } + // fallthrough +#else + return; +#endif + case RENDERPATH_GL11: + case RENDERPATH_GL13: +#if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2) + CHECKGLERROR + qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels); + qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels); + if (visiblepixels < 1 || allpixels < 1) + return; + rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1); cscale *= rtlight->corona_visibility; CHECKGLERROR break;