cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "0.25", "brightness of particles contributing to bouncegrid texture"};
cvar_t r_shadow_bouncegrid_sortlightpaths = {CVAR_SAVE, "r_shadow_bouncegrid_sortlightpaths", "1", "sort light paths before accumulating them into the bouncegrid texture, this reduces cpu cache misses"};
cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "1", "width of the light path for accumulation of light in the bouncegrid texture"};
+cvar_t r_shadow_bouncegrid_normalizevectors = { CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)" };
cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = { CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color" };
cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
+ Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_sortlightpaths);
settings->spacing[0] = spacing;
settings->spacing[1] = spacing;
settings->spacing[2] = spacing;
- settings->stablerandom = s ? 1 : r_shadow_bouncegrid_dynamic_stablerandom.integer;
+ settings->stablerandom = r_shadow_bouncegrid_dynamic_stablerandom.integer;
settings->bounceminimumintensity2 = bounceminimumintensity * bounceminimumintensity;
+ settings->normalizevectors = r_shadow_bouncegrid_normalizevectors.integer != 0;
// bound the values for sanity
settings->maxphotons = bound(1, settings->maxphotons, 25000000);
dlight_t *light;
rtlight_t *rtlight;
normalphotonscaling = 1.0f / max(0.0001f, settings->energyperphoton);
- for (lightindex = 0; lightindex < range2; lightindex++)
+ for (lightindex = 0;lightindex < range2;lightindex++)
{
if (lightindex < range)
{
if (R_CullBox(cullmins, cullmaxs))
continue;
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;
if (w * VectorLength2(rtlight->color) == 0.0f)
continue;
w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
// skip lights that will emit no photons
- if (VectorLength2(rtlight->bouncegrid_photoncolor) <= 0.0f)
+ if (!VectorLength2(rtlight->bouncegrid_photoncolor))
continue;
// shoot particles from this light
// use a calculation for the number of particles that will not
//trace_t cliptrace2;
//trace_t cliptrace3;
unsigned int lightindex;
- unsigned int seed = (unsigned int)(realtime * 1000.0f);
+ unsigned int seed;
randomseed_t randomseed;
vec3_t shotcolor;
vec3_t baseshotcolor;
vec_t radius;
vec_t s;
rtlight_t *rtlight;
+ union
+ {
+ unsigned int s[4];
+ double d;
+ }
+ rseed;
- Math_RandomSeed_FromInt(&randomseed, seed);
+ // compute a seed for the unstable random modes
+ memset(&rseed, 0, sizeof(rseed));
+ rseed.d = realtime;
+ Math_RandomSeed_FromInts(&randomseed, rseed.s[0], rseed.s[1], rseed.s[2], rseed.s[3]);
+ seed = rseed.s[0] ^ rseed.s[1] ^ rseed.s[2] ^ rseed.s[3];
r_shadow_bouncegrid_state.numsplatpaths = 0;
hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
else
hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
- skipsupercontentsmask = SUPERCONTENTS_SKY; // skipsurfaces with this contents, even if they also have SUPERCONTENTS_SOLID (basically this is for e1m5.bsp sky trick)
+ skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
maxbounce = settings.maxbounce;
for (lightindex = 0;lightindex < range2;lightindex++)
r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
// we stop caring about bounces once the brightness goes below this fraction of the original intensity
bounceminimumintensity2 = VectorLength(baseshotcolor) * settings.bounceminimumintensity2;
- switch (settings.stablerandom)
+
+ // for stablerandom we start the RNG with the position of the light
+ if (settings.stablerandom > 0)
{
- default:
- break;
- case 1:
- Math_RandomSeed_FromInt(&randomseed, lightindex * 11937);
- // prime the random number generator a bit
- Math_crandomf(&randomseed);
- break;
- case 2:
- seed = lightindex * 11937;
- // prime the random number generator a bit
- lhcheeserand(seed);
- break;
+ union
+ {
+ unsigned int i[4];
+ float f[4];
+ }
+ u;
+ u.f[0] = rtlight->shadoworigin[0];
+ u.f[1] = rtlight->shadoworigin[1];
+ u.f[2] = rtlight->shadoworigin[2];
+ u.f[3] = 1;
+ switch (settings.stablerandom)
+ {
+ default:
+ break;
+ case 1:
+ seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3];
+ break;
+ case 2:
+ Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3]);
+ break;
+ }
}
+
for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
{
VectorCopy(baseshotcolor, shotcolor);
break;
case -1:
case 1:
- VectorLehmerRandom(&randomseed, clipend);
+ VectorCheeseRandom(seed, clipend);
if (settings.bounceanglediffuse)
{
// we want random to be stable, so we still have to do all the random we would have done
for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
- VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
+ VectorCheeseRandom(seed, bouncerandom[bouncecount]);
}
break;
case -2:
case 2:
- VectorCheeseRandom(seed, clipend);
+ VectorLehmerRandom(&randomseed, clipend);
if (settings.bounceanglediffuse)
{
// we want random to be stable, so we still have to do all the random we would have done
for (bouncecount = 0; bouncecount < maxbounce; bouncecount++)
- VectorCheeseRandom(seed, bouncerandom[bouncecount]);
+ VectorLehmerRandom(&randomseed, bouncerandom[bouncecount]);
}
break;
}
+
+ // we want a uniform distribution spherically, not merely within the sphere
+ if (settings.normalizevectors)
+ VectorNormalize(clipend);
+
VectorMA(clipstart, radius, clipend, clipend);
for (bouncecount = 0;;bouncecount++)
{
else
{
// dynamic mode fires many rays and most will match the cache from the previous frame
- cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS, hitsupercontentsmask, skipsupercontentsmask);
+ cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
}
if (bouncecount > 0 || settings.includedirectlighting)
{
return;
x = vid_conwidth.value - 320;
y = 5;
- DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
+ DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
lightnumber = -1;
lightcount = 0;
range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked