rtx: attenuate lights based on solid angle, not distance and area, #145

breaks previous tuning
This commit is contained in:
Ivan Avdeev 2021-12-05 13:38:16 -08:00
parent de2a52dd71
commit e3e8693b13
3 changed files with 65 additions and 30 deletions

View File

@ -9,9 +9,9 @@
// FIXME what should these be?
const float shadow_offset_fudge = .1;
const float pdf_culling_threshold = 100.;
const float color_factor = 600.;
const float color_culling_threshold = 600./color_factor;
const float pdf_culling_threshold = 1e6;//100.;
const float color_factor = 1.;
const float color_culling_threshold = 1e-6;//600./color_factor;
const float throughput_threshold = 1e-3;
layout (constant_id = 4) const float LIGHT_GRID_CELL_SIZE = 256.;
@ -103,6 +103,16 @@ void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3
#endif
}
float triangleSolidAngle(vec3 p, vec3 a, vec3 b, vec3 c) {
a = normalize(a - p);
b = normalize(b - p);
c = normalize(c - p);
const float tanHalfOmega = dot(a, cross(b,c)) / (1. + dot(b,c) + dot(c,a) + dot(a,b));
return atan(tanHalfOmega) * 2.;
}
void sampleSurfaceTriangle(
vec3 color, vec3 view_dir, MaterialProperties material /* TODO BrdfData instead is supposedly more efficient */,
mat4x3 emissive_transform, mat3 emissive_transform_normal,
@ -145,9 +155,10 @@ void sampleSurfaceTriangle(
#endif
// TODO emissive normals and areas can be precomputed
const float area = .5 * length(cross(v1 - v2, v1 - v3));
const float area = 1.;//.5 * length(cross(v1 - v2, v1 - v3));
const float light_dist2 = dot(light_dir, light_dir);
float pdf = light_dist2 / (area * light_dot);
//float pdf = /*light_dist2 */ 1./ (area * light_dot);
float pdf = TWO_PI / triangleSolidAngle(payload_opaque.hit_pos_t.xyz, v1, v2, v3);
if (pdf > pdf_culling_threshold)
#ifdef DEBUG_LIGHT_CULLING
@ -203,6 +214,8 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
const bool not_environment = (lights.point_lights[i].environment == 0);
const vec3 light_dir = not_environment ? (origin_r.xyz - payload_opaque.hit_pos_t.xyz) : -dir; // TODO need to randomize sampling direction for environment soft shadow
const float radius = origin_r.w;
const vec3 light_dir_norm = normalize(light_dir);
const float light_dot = dot(light_dir_norm, payload_opaque.normal);
if (light_dot < 1e-5)
@ -216,27 +229,34 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
if (spot_dot < stopdot)
spot_attenuation = (spot_dot - stopdot2) / (stopdot - stopdot2);
float fdist = 1.f;
float light_dist = 1e4; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too?
//float fdist = 1.f;
float light_dist = 1e5; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too?
const float d2 = dot(light_dir, light_dir);
const float r2 = origin_r.w * origin_r.w;
if (not_environment) {
#if 1
const float d2 = dot(light_dir, light_dir);
const float r2 = origin_r.w * origin_r.w;
//light_dist = sqrt(d2);
light_dist = sqrt(d2) - origin_r.w;
fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
#else
const float d2 = dot(light_dir, light_dir);
//const float r2 = origin_r.w * origin_r.w;
light_dist = sqrt(d2);
//const float fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
//const float fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
fdist = (light_dist > 1.) ? 1.f / d2 : 1.f; // qrad workaround
#endif
}
const float pdf = 1.f / (fdist * light_dot * spot_attenuation);
if (radius < 1e-3)
continue;
const float dist = length(light_dir);
if (radius > dist)
continue;
#if 1
//light_dist = sqrt(d2);
light_dist = dist - radius;
//fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
#else
light_dist = dist;
//const float fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
//const float fdist = 2.f / (r2 + d2 + light_dist * sqrt(d2 + r2));
//fdist = (light_dist > 1.) ? 1.f / d2 : 1.f; // qrad workaround
#endif
//const float pdf = 1.f / (fdist * light_dot * spot_attenuation);
//const float pdf = TWO_PI / asin(radius / dist);
const float pdf = 1. / ((1. - sqrt(d2 - r2) / dist) * spot_attenuation);
color /= pdf;
}
color /= pdf;
// if (dot(color,color) < color_culling_threshold)
// continue;

View File

@ -839,21 +839,35 @@ static int addSpotLight( const vk_light_entity_t *le, float radius, int lightsty
return index;
}
static float sphereSolidAngleFromDistDiv2Pi(float r, float d) {
return 1. - sqrt(d*d - r*r)/d;
}
static void addDlight( const dlight_t *dlight ) {
const float scaler = 1.f; //dlight->radius / 255.f;
const float k_light_radius = 2.f;
const float k_threshold = 2.f;
float max_comp;
vec3_t color;
int index;
float scaler;
if( !dlight || dlight->die < gpGlobals->time || !dlight->radius )
return;
max_comp = Q_max(dlight->color.r, Q_max(dlight->color.g, dlight->color.b));
if (max_comp < k_threshold || dlight->radius <= k_light_radius)
return;
scaler = k_threshold / (max_comp * sphereSolidAngleFromDistDiv2Pi(k_light_radius, dlight->radius));
VectorSet(
color,
dlight->color.r * scaler,
dlight->color.g * scaler,
dlight->color.b * scaler);
index = addPointLight(dlight->origin, color, dlight->radius, -1, 1e5f);
index = addPointLight(dlight->origin, color, k_light_radius, -1, 1.f);
if (index < 0)
return;
@ -869,9 +883,9 @@ static void processStaticPointLights( void ) {
for (int i = 0; i < g_map_entities.num_lights; ++i) {
const vk_light_entity_t *le = g_map_entities.lights + i;
const float default_radius = 2.f; // FIXME tune
const float hack_attenuation = 100.f; // FIXME tune
const float hack_attenuation_spot = 100.f; // FIXME tune
float radius = le->radius > 0.f ? le->radius : default_radius;
const float hack_attenuation = 1.f; // FIXME tune
const float hack_attenuation_spot = 1.f; // FIXME tune
const float radius = le->radius > 0.f ? le->radius : default_radius;
int index;
switch (le->type) {

View File

@ -193,7 +193,7 @@ static void fillLightFromProps( vk_light_entity_t *le, const entity_props_t *pro
weirdGoldsrcLightScaling(le->color);
}
gEngine.Con_Reportf("%s light %d (ent=%d): %s targetname=%s color=(%f %f %f) origin=(%f %f %f) style=%d dir=(%f %f %f) stopdot=(%f %f)\n",
gEngine.Con_Reportf("%s light %d (ent=%d): %s targetname=%s color=(%f %f %f) origin=(%f %f %f) style=%d R=%f dir=(%f %f %f) stopdot=(%f %f)\n",
patch ? "Patch" : "Added",
g_map_entities.num_lights, entity_index,
le->type == LightTypeEnvironment ? "environment" : le->type == LightTypeSpot ? "spot" : "point",
@ -201,6 +201,7 @@ static void fillLightFromProps( vk_light_entity_t *le, const entity_props_t *pro
le->color[0], le->color[1], le->color[2],
le->origin[0], le->origin[1], le->origin[2],
le->style,
le->radius,
le->dir[0], le->dir[1], le->dir[2],
le->stopdot, le->stopdot2);
}