Quake II RTX doxygen  1.0 dev
light_lists.h File Reference

Go to the source code of this file.

Macros

#define MAX_BRUTEFORCE_SAMPLING   8
 

Functions

float projected_tri_area_simple (mat3 positions, vec3 p)
 
float projected_tri_area (mat3 positions, vec3 p, vec3 n, vec3 V, float phong_exp, float phong_scale, float phong_weight)
 
vec3 sample_projected_triangle (vec3 p, mat3 positions, vec2 rnd, out vec3 light_normal, out float projected_area)
 
uint get_light_stats_addr (uint cluster, uint light, uint side)
 
void sample_polygonal_lights (uint list_idx, vec3 p, vec3 n, vec3 gn, vec3 V, float phong_exp, float phong_scale, float phong_weight, bool is_gradient, out vec3 position_light, out vec3 light_color, out int light_index, out float projected_area, vec3 rng)
 
void sample_spherical_lights (vec3 p, vec3 n, vec3 gn, float max_solid_angle, out vec3 position_light, out vec3 light_color, vec3 rng)
 

Macro Definition Documentation

◆ MAX_BRUTEFORCE_SAMPLING

#define MAX_BRUTEFORCE_SAMPLING   8

Definition at line 23 of file light_lists.h.

Function Documentation

◆ get_light_stats_addr()

uint get_light_stats_addr ( uint  cluster,
uint  light,
uint  side 
)

Definition at line 96 of file light_lists.h.

97 {
98  uint addr = cluster;
99  addr = addr * global_ubo.num_static_lights + light;
100  addr = addr * 6 + side;
101  addr = addr * 2;
102  return addr;
103 }

Referenced by get_direct_illumination(), and sample_polygonal_lights().

◆ projected_tri_area()

float projected_tri_area ( mat3  positions,
vec3  p,
vec3  n,
vec3  V,
float  phong_exp,
float  phong_scale,
float  phong_weight 
)

Definition at line 41 of file light_lists.h.

42 {
43  positions[0] = positions[0] - p;
44  positions[1] = positions[1] - p;
45  positions[2] = positions[2] - p;
46 
47  vec3 g = cross(positions[1] - positions[0], positions[2] - positions[0]);
48  if ( dot(n, positions[0]) <= 0 && dot(n, positions[1]) <= 0 && dot(n, positions[2]) <= 0 )
49  return 0;
50  if ( dot(g, positions[0]) >= 0 && dot(g, positions[1]) >= 0 && dot(g, positions[2]) >= 0 )
51  return 0;
52 
53  vec3 L = normalize(positions * vec3(1.0 / 3.0));
54  float specular = phong(n, L, V, phong_exp) * phong_scale;
55  float brdf = mix(1.0, specular, phong_weight);
56 
57  positions[0] = normalize(positions[0]);
58  positions[1] = normalize(positions[1]);
59  positions[2] = normalize(positions[2]);
60 
61  vec3 a = cross(positions[1] - positions[0], positions[2] - positions[0]);
62  float pa = max(length(a) - 1e-5, 0.);
63  return pa * brdf;
64 }

Referenced by sample_polygonal_lights().

◆ projected_tri_area_simple()

float projected_tri_area_simple ( mat3  positions,
vec3  p 
)

Definition at line 26 of file light_lists.h.

27 {
28  positions[0] = positions[0] - p;
29  positions[1] = positions[1] - p;
30  positions[2] = positions[2] - p;
31 
32  positions[0] = normalize(positions[0]);
33  positions[1] = normalize(positions[1]);
34  positions[2] = normalize(positions[2]);
35 
36  vec3 a = cross(positions[1] - positions[0], positions[2] - positions[0]);
37  return length(a);
38 }

◆ sample_polygonal_lights()

void sample_polygonal_lights ( uint  list_idx,
vec3  p,
vec3  n,
vec3  gn,
vec3  V,
float  phong_exp,
float  phong_scale,
float  phong_weight,
bool  is_gradient,
out vec3  position_light,
out vec3  light_color,
out int  light_index,
out float  projected_area,
vec3  rng 
)

Definition at line 106 of file light_lists.h.

121 {
122  position_light = vec3(0);
123  light_index = -1;
124  light_color = vec3(0);
125  projected_area = 0;
126 
127  if(list_idx == ~0u)
128  return;
129 
130  uint list_start = get_light_list_offsets(list_idx);
131  uint list_end = get_light_list_offsets(list_idx + 1);
132 
133  float partitions = ceil(float(list_end - list_start) / float(MAX_BRUTEFORCE_SAMPLING));
134  rng.x *= partitions;
135  float fpart = min(floor(rng.x), partitions-1);
136  rng.x -= fpart;
137  list_start += int(fpart);
138  int stride = int(partitions);
139 
140  float mass = 0.;
141 
142  float light_masses[MAX_BRUTEFORCE_SAMPLING];
143 
144  #pragma unroll
145  for(uint i = 0, n_idx = list_start; i < MAX_BRUTEFORCE_SAMPLING; i++, n_idx += stride) {
146  if (n_idx >= list_end)
147  break;
148 
149  uint current_idx = get_light_list_lights(n_idx);
150 
151  if(current_idx == ~0u)
152  {
153  light_masses[i] = 0;
154  continue;
155  }
156 
157  LightPolygon light = get_light_polygon(current_idx);
158 
159  float m = projected_tri_area(light.positions, p, n, V, phong_exp, phong_scale, phong_weight);
160 
161  float light_lum = luminance(light.color);
162 
163  // Apply light style scaling.
164  // For gradient pixels, use the style from the previous frame here
165  // in order to keep the CDF consistent and make sure that the same light is picked,
166  // regardless of animations. This makes the image more stable around blinking lights,
167  // especially in shadowed areas.
168  light_lum *= is_gradient ? light.prev_style_scale : light.light_style_scale;
169 
170  if(light_lum < 0 && global_ubo.environment_type == ENVIRONMENT_DYNAMIC)
171  {
172  // Set limits on sky luminance to avoid oversampling the sky in shadowed areas, or undersampling at dusk and dawn.
173  // Note: the log -> linear conversion of the cvars happens on the CPU, in main.c
174  m *= clamp(sun_color_ubo.sky_luminance, global_ubo.pt_min_log_sky_luminance, global_ubo.pt_max_log_sky_luminance);
175  }
176  else
177  m *= abs(light_lum); // abs because sky lights have negative color
178 
179  // Apply CDF adjustment based on light shadowing statistics from one of the previous frames.
180  // See comments in function `get_direct_illumination` in `path_tracer_rgen.h`
181  if(global_ubo.pt_light_stats != 0
182  && m > 0
183  && current_idx < global_ubo.num_static_lights)
184  {
185  uint buffer_idx = global_ubo.current_frame_idx;
186  // Regular pixels get shadowing stats from the previous frame;
187  // Gradient pixels get the stats from two frames ago because they need to match
188  // the light sampling from the previous frame.
189  buffer_idx += is_gradient ? (NUM_LIGHT_STATS_BUFFERS - 2) : (NUM_LIGHT_STATS_BUFFERS - 1);
190  buffer_idx = buffer_idx % NUM_LIGHT_STATS_BUFFERS;
191 
192  uint addr = get_light_stats_addr(list_idx, current_idx, get_primary_direction(n));
193 
194  uint num_hits = light_stats_bufers[buffer_idx].stats[addr];
195  uint num_misses = light_stats_bufers[buffer_idx].stats[addr + 1];
196  uint num_total = num_hits + num_misses;
197 
198  if(num_total > 0)
199  {
200  // Adjust the mass, but set a lower limit on the factor to avoid
201  // extreme changes in the sampling.
202  m *= max(float(num_hits) / float(num_total), 0.1);
203  }
204  }
205 
206  mass += m;
207  light_masses[i] = m;
208  }
209 
210  if (mass <= 0)
211  return;
212 
213  rng.x *= mass;
214  int current_idx = -1;
215  mass *= partitions;
216  float pdf = 0;
217 
218  #pragma unroll
219  for(uint i = 0, n_idx = list_start; i < MAX_BRUTEFORCE_SAMPLING; i++, n_idx += stride) {
220  if (n_idx >= list_end)
221  break;
222  pdf = light_masses[i];
223  current_idx = int(n_idx);
224  rng.x -= pdf;
225 
226  if (rng.x <= 0)
227  break;
228  }
229 
230  if(rng.x > 0)
231  return;
232 
233  pdf /= mass;
234 
235  // assert: current_idx >= 0?
236  if (current_idx >= 0) {
237  current_idx = int(get_light_list_lights(current_idx));
238 
239  LightPolygon light = get_light_polygon(current_idx);
240 
241  vec3 light_normal;
242  position_light = sample_projected_triangle(p, light.positions, rng.yz, light_normal, projected_area);
243 
244  vec3 L = normalize(position_light - p);
245 
246  if(dot(L, gn) <= 0)
247  projected_area = 0;
248 
249  float LdotNL = max(0, -dot(light_normal, L));
250  float spotlight = sqrt(LdotNL);
251 
252  if(light.color.r >= 0)
253  {
254  light_color = light.color * (projected_area * spotlight * light.light_style_scale);
255  projected_area = 0; // disable MIS with indirect specular rays
256  }
257  else
258  light_color = env_map(L, true) * projected_area * global_ubo.pt_env_scale;
259 
260  light_index = current_idx;
261  }
262 
263  light_color /= pdf;
264 }

Referenced by get_direct_illumination().

◆ sample_projected_triangle()

vec3 sample_projected_triangle ( vec3  p,
mat3  positions,
vec2  rnd,
out vec3  light_normal,
out float  projected_area 
)

Definition at line 67 of file light_lists.h.

68 {
69  light_normal = cross(positions[1] - positions[0], positions[2] - positions[0]);
70  light_normal = normalize(light_normal);
71 
72  positions[0] = positions[0] - p;
73  positions[1] = positions[1] - p;
74  positions[2] = positions[2] - p;
75 
76  float o = dot(light_normal, positions[0]);
77 
78  positions[0] = normalize(positions[0]);
79  positions[1] = normalize(positions[1]);
80  positions[2] = normalize(positions[2]);
81 
82  vec3 projected_normal = cross(positions[1] - positions[0], positions[2] - positions[0]);
83 
84  vec3 direction = positions * sample_triangle(rnd);
85  float dl = length(direction);
86 
87  // n (p + d * t - p[i]) == 0
88  // -n (p - pi) / n d == o / n d == t
89  vec3 lo = direction * (o / dot(light_normal, direction));
90 
91  projected_area = length(projected_normal) * 0.5;
92 
93  return p + lo;
94 }

Referenced by sample_polygonal_lights().

◆ sample_spherical_lights()

void sample_spherical_lights ( vec3  p,
vec3  n,
vec3  gn,
float  max_solid_angle,
out vec3  position_light,
out vec3  light_color,
vec3  rng 
)

Definition at line 267 of file light_lists.h.

275 {
276  position_light = vec3(0);
277  light_color = vec3(0);
278 
279  if(global_ubo.num_sphere_lights == 0)
280  return;
281 
282  float random_light = rng.x * global_ubo.num_sphere_lights;
283  uint light_idx = min(global_ubo.num_sphere_lights - 1, uint(random_light));
284 
285  vec4 light_center_radius = global_ubo.sphere_light_data[light_idx * 2];
286  float sphere_radius = light_center_radius.w;
287 
288  light_color = global_ubo.sphere_light_data[light_idx * 2 + 1].rgb;
289 
290  vec3 c = light_center_radius.xyz - p;
291  float dist = length(c);
292  float rdist = 1.0 / dist;
293  vec3 L = c * rdist;
294 
295  float irradiance = 2 * (1 - sqrt(max(0, 1 - square(sphere_radius * rdist))));
296  irradiance = min(irradiance, max_solid_angle);
297  irradiance *= float(global_ubo.num_sphere_lights); // 1 / pdf
298 
299  mat3 onb = construct_ONB_frisvad(L);
300  vec3 diskpt;
301  diskpt.xy = sample_disk(rng.yz);
302  diskpt.z = sqrt(max(0, 1 - diskpt.x * diskpt.x - diskpt.y * diskpt.y));
303 
304  position_light = light_center_radius.xyz + (onb[0] * diskpt.x + onb[2] * diskpt.y - L * diskpt.z) * sphere_radius;
305  light_color *= irradiance;
306 
307  if(dot(position_light - p, gn) <= 0)
308  light_color = vec3(0);
309 }

Referenced by get_direct_illumination().

env_map
vec3 env_map(vec3 direction, bool remove_sun)
Definition: path_tracer_rgen.h:81
uint
uint32_t uint
Definition: global_ubo.h:233
sample_projected_triangle
vec3 sample_projected_triangle(vec3 p, mat3 positions, vec2 rnd, out vec3 light_normal, out float projected_area)
Definition: light_lists.h:67
projected_tri_area
float projected_tri_area(mat3 positions, vec3 p, vec3 n, vec3 V, float phong_exp, float phong_scale, float phong_weight)
Definition: light_lists.h:41
mix
static float mix(float a, float b, float s)
Definition: bloom.c:83
ENVIRONMENT_DYNAMIC
#define ENVIRONMENT_DYNAMIC
Definition: constants.h:100
m
static struct mdfour * m
Definition: mdfour.c:32
MAX_BRUTEFORCE_SAMPLING
#define MAX_BRUTEFORCE_SAMPLING
Definition: light_lists.h:23
NUM_LIGHT_STATS_BUFFERS
#define NUM_LIGHT_STATS_BUFFERS
Definition: constants.h:44
V
#define V(name)
Definition: g_save.c:48
c
statCounters_t c
Definition: main.c:30
sample_disk
static void sample_disk(float *u, float *v)
Definition: shadow_map.c:448
get_light_stats_addr
uint get_light_stats_addr(uint cluster, uint light, uint side)
Definition: light_lists.h:96
L
#define L(name)
Definition: g_save.c:47
int
CONST PIXELFORMATDESCRIPTOR int
Definition: wgl.c:26