cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
-cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
+cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes"};
cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
-cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "4096", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
+cvar_t r_shadow_shadowmapping_texturesize = { CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
//cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
//cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
{
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)
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++)
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;
// calculate texture size enclosing entire world bounds at the spacing
if (r_refdef.scene.worldmodel)
{
- VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
- VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
+ int lightindex;
+ int range;
+ qboolean bounds_set = false;
+ dlight_t *light;
+ rtlight_t *rtlight;
+
+ // calculate bounds enclosing world lights as they should be noticably tighter
+ // than the world bounds on maps with unlit monster containers (see e1m7 etc)
+ range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+ for (lightindex = 0;lightindex < range;lightindex++)
+ {
+ const vec_t *rtlmins, *rtlmaxs;
+
+ light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ if (!light)
+ continue;
+
+ rtlight = &light->rtlight;
+ rtlmins = rtlight->cullmins;
+ rtlmaxs = rtlight->cullmaxs;
+
+ if (!bounds_set)
+ {
+ VectorCopy(rtlmins, mins);
+ VectorCopy(rtlmaxs, maxs);
+ bounds_set = true;
+ }
+ else
+ {
+ mins[0] = min(mins[0], rtlmins[0]);
+ mins[1] = min(mins[1], rtlmins[1]);
+ mins[2] = min(mins[2], rtlmins[2]);
+ maxs[0] = max(maxs[0], rtlmaxs[0]);
+ maxs[1] = max(maxs[1], rtlmaxs[1]);
+ maxs[2] = max(maxs[2], rtlmaxs[2]);
+ }
+ }
+
+ // limit to no larger than the world bounds
+ mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
+ mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
+ mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
+ maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
+ maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
+ maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
+
+ VectorMA(mins, -2.0f, spacing, mins);
+ VectorMA(maxs, 2.0f, spacing, maxs);
}
else
{
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);
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);
{
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)))
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;