cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "3", "maximum number of bounces for a particle (minimum is 1)"};
-cvar_t r_shadow_bouncegrid_nolerpsplat = {CVAR_SAVE, "r_shadow_bouncegrid_nolerpsplat", "0", "enables slightly quicker (but worse looking) photon accumulation"};
cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "2", "brightness of particles contributing to bouncegrid texture"};
cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
static int r_shadow_bouncegridresolution[3];
static int r_shadow_bouncegridnumpixels;
static unsigned char *r_shadow_bouncegridpixels;
-static unsigned short *r_shadow_bouncegridhighpixels;
+static float *r_shadow_bouncegridhighpixels;
// note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
#define ATTENTABLESIZE 256
Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
- Cvar_RegisterVariable(&r_shadow_bouncegrid_nolerpsplat);
Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
dlight_t *light;
int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
int bouncecount;
- int c[3];
int hitsupercontentsmask;
int maxbounce;
int numpixels;
//trace_t cliptrace3;
unsigned char *pixel;
unsigned char *pixels;
- unsigned short *highpixel;
- unsigned short *highpixels;
+ float *highpixel;
+ float *highpixels;
unsigned int lightindex;
unsigned int range;
unsigned int range1;
vec_t photonscaling;
vec_t photonresidual;
float m[16];
- int texlerp[2][3];
- int splatcolor[3];
+ float texlerp[2][3];
+ float splatcolor[3];
+ float pixelweight[8];
int pixelindex[8];
- int pixelweight[8];
int corner;
+ int x, y, z;
qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
rtlight_t *rtlight;
if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
{
r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
- r_shadow_bouncegridhighpixels = (unsigned short *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(unsigned short[4]));
+ r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[3]));
}
r_shadow_bouncegridnumpixels = numpixels;
pixels = r_shadow_bouncegridpixels;
highpixels = r_shadow_bouncegridhighpixels;
memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
- memset(highpixels, 0, numpixels * sizeof(unsigned short[3]));
+ memset(highpixels, 0, numpixels * sizeof(float[3]));
// figure out what we want to interact with
if (r_shadow_bouncegrid_hitmodels.integer)
hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
if (!shootparticles)
continue;
photonresidual -= shootparticles;
- s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
+ s = r_shadow_bouncegrid_particleintensity.value / shootparticles;
VectorScale(lightcolor, s, baseshotcolor);
- if (VectorLength2(baseshotcolor) < 3.0f)
+ if (VectorLength2(baseshotcolor) == 0.0f)
break;
r_refdef.stats.bouncegrid_lights++;
r_refdef.stats.bouncegrid_particles += shootparticles;
{
r_refdef.stats.bouncegrid_splats++;
// figure out which texture pixel this is in
- texlerp[1][0] = (int)(((cliptrace.endpos[0] - mins[0]) * ispacing[0]) * 256.0f);
- texlerp[1][1] = (int)(((cliptrace.endpos[1] - mins[1]) * ispacing[1]) * 256.0f);
- texlerp[1][2] = (int)(((cliptrace.endpos[2] - mins[2]) * ispacing[2]) * 256.0f);
- tex[0] = texlerp[1][0] >> 8;
- tex[1] = texlerp[1][1] >> 8;
- tex[2] = texlerp[1][2] >> 8;
+ texlerp[1][0] = ((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
+ texlerp[1][1] = ((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
+ texlerp[1][2] = ((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
+ tex[0] = (int)floor(texlerp[1][0]);
+ tex[1] = (int)floor(texlerp[1][1]);
+ tex[2] = (int)floor(texlerp[1][2]);
if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2)
{
// it is within bounds...
- splatcolor[0] = (int)shotcolor[2];
- splatcolor[1] = (int)shotcolor[1];
- splatcolor[2] = (int)shotcolor[0];
+ splatcolor[0] = shotcolor[2] * 255.0f;
+ splatcolor[1] = shotcolor[1] * 255.0f;
+ splatcolor[2] = shotcolor[0] * 255.0f;
// calculate the lerp factors
- if (r_shadow_bouncegrid_nolerpsplat.integer)
+ texlerp[1][0] -= tex[0];
+ texlerp[1][1] -= tex[1];
+ texlerp[1][2] -= tex[2];
+ texlerp[0][0] = 1.0f - texlerp[1][0];
+ texlerp[0][1] = 1.0f - texlerp[1][1];
+ texlerp[0][2] = 1.0f - texlerp[1][2];
+ // calculate individual pixel indexes and weights
+ pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
+ pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
+ pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
+ pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]);
+ pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
+ pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]);
+ pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]);
+ pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]);
+ // update the 8 pixels...
+ for (corner = 0;corner < 8;corner++)
{
- pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );
- pixel = pixels + 4 * pixelindex[0];
- highpixel = highpixels + 3 * pixelindex[0];
+ pixel = pixels + 4 * pixelindex[corner];
+ highpixel = highpixels + 3 * pixelindex[corner];
// add to the high precision pixel color
- c[0] = highpixel[0] + splatcolor[0];
- c[1] = highpixel[1] + splatcolor[1];
- c[2] = highpixel[2] + splatcolor[2];
- highpixel[0] = (unsigned short)min(c[0], 65535);
- highpixel[1] = (unsigned short)min(c[1], 65535);
- highpixel[2] = (unsigned short)min(c[2], 65535);
- // update the low precision pixel color
- pixel[0] = highpixel[0] >> 8;
- pixel[1] = highpixel[1] >> 8;
- pixel[2] = highpixel[2] >> 8;
+ highpixel[0] += (splatcolor[0]*pixelweight[corner]);
+ highpixel[1] += (splatcolor[1]*pixelweight[corner]);
+ highpixel[2] += (splatcolor[2]*pixelweight[corner]);
+ // flag the low precision pixel as needing to be updated
pixel[3] = 255;
}
- else
- {
- texlerp[1][0] &= 0xFF;
- texlerp[1][1] &= 0xFF;
- texlerp[1][2] &= 0xFF;
- texlerp[0][0] = 256 - texlerp[1][0];
- texlerp[0][1] = 256 - texlerp[1][1];
- texlerp[0][2] = 256 - texlerp[1][2];
- // calculate individual pixel indexes and weights
- pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]) >> 16;
- pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]) >> 16;
- pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]) >> 16;
- pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]) >> 16;
- pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]) >> 16;
- pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]) >> 16;
- pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]) >> 16;
- pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]) >> 16;
- // update the 8 pixels...
- for (corner = 0;corner < 8;corner++)
- {
- pixel = pixels + 4 * pixelindex[corner];
- highpixel = highpixels + 3 * pixelindex[corner];
- // add to the high precision pixel color
- c[0] = highpixel[0] + ((splatcolor[0]*pixelweight[corner])>>8);
- c[1] = highpixel[1] + ((splatcolor[1]*pixelweight[corner])>>8);
- c[2] = highpixel[2] + ((splatcolor[2]*pixelweight[corner])>>8);
- highpixel[0] = (unsigned short)min(c[0], 65535);
- highpixel[1] = (unsigned short)min(c[1], 65535);
- highpixel[2] = (unsigned short)min(c[2], 65535);
- // update the low precision pixel color
- pixel[0] = highpixel[0] >> 8;
- pixel[1] = highpixel[1] >> 8;
- pixel[2] = highpixel[2] >> 8;
- pixel[3] = 255;
- }
- }
}
}
if (bouncecount >= maxbounce)
surfcolor[1] = min(surfcolor[1], 1.0f);
surfcolor[2] = min(surfcolor[2], 1.0f);
VectorMultiply(shotcolor, surfcolor, shotcolor);
- if (VectorLength2(shotcolor) < 3.0f)
+ if (VectorLength2(baseshotcolor) == 0.0f)
break;
r_refdef.stats.bouncegrid_bounces++;
if (r_shadow_bouncegrid_bounceanglediffuse.integer)
}
}
}
+ // generate pixels array from highpixels array
+ // skip first and last columns, rows, and layers as these are blank
+ // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
+ for (z = 1;z < resolution[2]-1;z++)
+ {
+ for (y = 1;y < resolution[1]-1;y++)
+ {
+ for (x = 1, pixelindex[0] = (resolution[1]*z+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 3*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 3)
+ {
+ // only convert pixels that were hit by photons
+ if (pixel[3])
+ {
+ pixel[0] = (unsigned char)min(highpixel[0], 255);
+ pixel[1] = (unsigned char)min(highpixel[1], 255);
+ pixel[2] = (unsigned char)min(highpixel[2], 255);
+ }
+ }
+ }
+ }
if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
else