Quake II RTX doxygen  1.0 dev
path_tracer_rgen.h
Go to the documentation of this file.
1 /*
2 Copyright (C) 2018 Christoph Schied
3 Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include "path_tracer.h"
21 #include "utils.glsl"
22 
23 #define RAY_GEN_DESCRIPTOR_SET_IDX 0
24 layout(set = RAY_GEN_DESCRIPTOR_SET_IDX, binding = 0)
25 uniform accelerationStructureNV topLevelAS;
26 
27 #define GLOBAL_TEXTURES_DESC_SET_IDX 2
28 #include "global_textures.h"
29 
30 #define VERTEX_BUFFER_DESC_SET_IDX 3
31 #define VERTEX_READONLY 1
32 #include "vertex_buffer.h"
33 
34 #include "read_visbuf.glsl"
35 #include "asvgf.glsl"
36 #include "brdf.glsl"
37 #include "water.glsl"
38 
39 #define DESATURATE_ENVIRONMENT_MAP 1
40 
41 #define RNG_PRIMARY_OFF_X 0
42 #define RNG_PRIMARY_OFF_Y 1
43 #define RNG_PRIMARY_APERTURE_X 2
44 #define RNG_PRIMARY_APERTURE_Y 3
45 
46 #define RNG_NEE_LIGHT_SELECTION(bounce) (4 + 0 + 9 * bounce)
47 #define RNG_NEE_TRI_X(bounce) (4 + 1 + 9 * bounce)
48 #define RNG_NEE_TRI_Y(bounce) (4 + 2 + 9 * bounce)
49 #define RNG_NEE_LIGHT_TYPE(bounce) (4 + 3 + 9 * bounce)
50 #define RNG_BRDF_X(bounce) (4 + 4 + 9 * bounce)
51 #define RNG_BRDF_Y(bounce) (4 + 5 + 9 * bounce)
52 #define RNG_BRDF_FRESNEL(bounce) (4 + 6 + 9 * bounce)
53 #define RNG_SUNLIGHT_X(bounce) (4 + 7 + 9 * bounce)
54 #define RNG_SUNLIGHT_Y(bounce) (4 + 8 + 9 * bounce)
55 
56 #define PRIMARY_RAY_CULL_MASK (AS_FLAG_EVERYTHING & ~(AS_FLAG_VIEWER_MODELS | AS_FLAG_CUSTOM_SKY))
57 #define REFLECTION_RAY_CULL_MASK (AS_FLAG_OPAQUE | AS_FLAG_PARTICLES | AS_FLAG_EXPLOSIONS | AS_FLAG_SKY)
58 #define BOUNCE_RAY_CULL_MASK (AS_FLAG_OPAQUE | AS_FLAG_SKY | AS_FLAG_CUSTOM_SKY)
59 #define SHADOW_RAY_CULL_MASK (AS_FLAG_OPAQUE)
60 
61 /* no BRDF sampling in last bounce */
62 #define NUM_RNG_PER_FRAME (RNG_NEE_STATIC_DYNAMIC(1) + 1)
63 
64 #define BOUNCE_SPECULAR 1
65 
66 #define MAX_OUTPUT_VALUE 1000
67 
68 #define RT_PAYLOAD_SHADOW 0
69 #define RT_PAYLOAD_BRDF 1
70 layout(location = RT_PAYLOAD_SHADOW) rayPayloadNV RayPayloadShadow ray_payload_shadow;
71 layout(location = RT_PAYLOAD_BRDF) rayPayloadNV RayPayload ray_payload_brdf;
72 
74 
75 struct Ray {
77  float t_min, t_max;
78 };
79 
80 vec3
81 env_map(vec3 direction, bool remove_sun)
82 {
83  direction = (global_ubo.environment_rotation_matrix * vec4(direction, 0)).xyz;
84 
85  vec3 envmap = vec3(0);
86  if (global_ubo.environment_type == ENVIRONMENT_DYNAMIC)
87  {
88  envmap = textureLod(TEX_PHYSICAL_SKY, direction.xzy, 0).rgb;
89 
90  if(remove_sun)
91  {
92  // roughly remove the sun from the env map
93  envmap = min(envmap, vec3((1 - dot(direction, global_ubo.sun_direction_envmap)) * 200));
94  }
95  }
96  else if (global_ubo.environment_type == ENVIRONMENT_STATIC)
97  {
98  envmap = textureLod(TEX_ENVMAP, direction.xzy, 0).rgb;
99 #if DESATURATE_ENVIRONMENT_MAP
100  float avg = (envmap.x + envmap.y + envmap.z) / 3.0;
101  envmap = mix(envmap, avg.xxx, 0.1) * 0.5;
102 #endif
103  }
104  return envmap;
105 }
106 
107 // depends on env_map
108 #include "light_lists.h"
109 
111 {
112  ivec2 pos;
113 
114  bool is_even_checkerboard = push_constants.gpu_index == 0 || push_constants.gpu_index < 0 && gl_LaunchIDNV.z == 0;
115  if(global_ubo.pt_swap_checkerboard != 0)
116  is_even_checkerboard = !is_even_checkerboard;
117 
118  if (is_even_checkerboard) {
119  pos.x = int(gl_LaunchIDNV.x * 2) + int(gl_LaunchIDNV.y & 1);
120  } else {
121  pos.x = int(gl_LaunchIDNV.x * 2 + 1) - int(gl_LaunchIDNV.y & 1);
122  }
123 
124  pos.y = int(gl_LaunchIDNV.y);
125  return pos;
126 }
127 
129 {
130  return ivec2(global_ubo.width, global_ubo.height);
131 }
132 
133 bool
135 {
136  return rp.instance_prim != ~0u;
137 }
138 
139 bool
141 {
142  return (rp.instance_prim & INSTANCE_SKY_FLAG) != 0;
143 }
144 
145 bool
147 {
148  return (pay_load.instance_prim & INSTANCE_DYNAMIC_FLAG) > 0;
149 }
150 
151 uint
153 {
154  return pay_load.instance_prim & PRIM_ID_MASK;
155 }
156 
157 Triangle
159 {
160  uint prim = get_primitive(rp);
161 
162  return is_dynamic_instance(rp)
163  ? get_instanced_triangle(prim)
164  : get_bsp_triangle(prim);
165 }
166 
167 vec3
169 {
170  vec3 bary;
171  bary.yz = rp.barycentric;
172  bary.x = 1.0 - bary.y - bary.z;
173  return bary;
174 }
175 
176 float
178 {
179  uvec3 p = uvec3(rng_seed, rng_seed >> 10, rng_seed >> 20);
180  p.z = (p.z + idx);
181  p &= uvec3(BLUE_NOISE_RES - 1, BLUE_NOISE_RES - 1, NUM_BLUE_NOISE_TEX - 1);
182 
183  return min(texelFetch(TEX_BLUE_NOISE, ivec3(p), 0).r, 0.9999999999999);
184  //return fract(vec2(get_rng_uint(idx)) / vec2(0xffffffffu));
185 }
186 
187 bool
188 is_water(uint material)
189 {
190  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_WATER;
191 }
192 
193 bool
194 is_slime(uint material)
195 {
196  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_SLIME;
197 }
198 
199 bool
200 is_lava(uint material)
201 {
202  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_LAVA;
203 }
204 
205 bool
206 is_glass(uint material)
207 {
208  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_GLASS;
209 }
210 
211 bool
213 {
214  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_TRANSPARENT;
215 }
216 
217 bool
218 is_chrome(uint material)
219 {
220  uint kind = material & MATERIAL_KIND_MASK;
221  return kind == MATERIAL_KIND_CHROME || kind == MATERIAL_KIND_CHROME_MODEL;
222 }
223 
224 bool
225 is_screen(uint material)
226 {
227  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_SCREEN;
228 }
229 
230 bool
231 is_camera(uint material)
232 {
233  return (material & MATERIAL_KIND_MASK) == MATERIAL_KIND_CAMERA;
234 }
235 
236 vec3
237 correct_albedo(vec3 albedo)
238 {
239  return max(vec3(0), pow(albedo, vec3(ALBEDO_TRANSFORM_POWER)) * ALBEDO_TRANSFORM_SCALE + vec3(ALBEDO_TRANSFORM_BIAS));
240 }
241 
242 vec3
243 correct_emissive(uint material_id, vec3 emissive)
244 {
245  return max(vec3(0), emissive.rgb + vec3(EMISSIVE_TRANSFORM_BIAS));
246 }
247 
248 void
249 trace_ray(Ray ray, bool cull_back_faces, int instance_mask)
250 {
251  uint rayFlags = 0;
252  if(cull_back_faces)
253  rayFlags |=gl_RayFlagsCullBackFacingTrianglesNV;
254 
255  ray_payload_brdf.transparency = uvec2(0);
256  ray_payload_brdf.hit_distance = 0;
257  ray_payload_brdf.max_transparent_distance = 0;
258 
259  traceNV( topLevelAS, rayFlags, instance_mask,
260  SBT_RCHIT_OPAQUE /*sbtRecordOffset*/, 0 /*sbtRecordStride*/, SBT_RMISS_PATH_TRACER /*missIndex*/,
261  ray.origin, ray.t_min, ray.direction, ray.t_max, RT_PAYLOAD_BRDF);
262 }
263 
264 Ray get_shadow_ray(vec3 p1, vec3 p2, float tmin)
265 {
266  vec3 l = p2 - p1;
267  float dist = length(l);
268  l /= dist;
269 
270  Ray ray;
271  ray.origin = p1 + l * tmin;
272  ray.t_min = 0;
273  ray.t_max = dist - tmin - 0.01;
274  ray.direction = l;
275 
276  return ray;
277 }
278 
279 float
280 trace_shadow_ray(Ray ray, int cull_mask)
281 {
282  const uint rayFlags = gl_RayFlagsOpaqueNV | gl_RayFlagsTerminateOnFirstHitNV;
283 
284  ray_payload_shadow.missed = 0;
285 
286  traceNV( topLevelAS, rayFlags, cull_mask,
287  SBT_RCHIT_EMPTY /*sbtRecordOffset*/, 0 /*sbtRecordStride*/, SBT_RMISS_SHADOW /*missIndex*/,
288  ray.origin, ray.t_min, ray.direction, ray.t_max, RT_PAYLOAD_SHADOW);
289 
290  return float(ray_payload_shadow.missed);
291 }
292 
293 vec3
294 trace_caustic_ray(Ray ray, int surface_medium)
295 {
296  ray_payload_brdf.hit_distance = -1;
297 
298  traceNV(topLevelAS, gl_RayFlagsCullBackFacingTrianglesNV, AS_FLAG_TRANSPARENT,
300  ray.origin, ray.t_min, ray.direction, ray.t_max, RT_PAYLOAD_BRDF);
301 
302  float extinction_distance = ray.t_max - ray.t_min;
303  vec3 throughput = vec3(1);
304 
305  if(found_intersection(ray_payload_brdf))
306  {
307  Triangle triangle = get_hit_triangle(ray_payload_brdf);
308 
309  vec3 geo_normal = triangle.normals[0];
310  bool is_vertical = abs(geo_normal.z) < 0.1;
311 
312  if((is_water(triangle.material_id) || is_slime(triangle.material_id)) && !is_vertical)
313  {
314  vec3 position = ray.origin + ray.direction * ray_payload_brdf.hit_distance;
315  vec3 w = get_water_normal(triangle.material_id, geo_normal, triangle.tangent, position, true);
316 
317  float caustic = clamp((1 - pow(clamp(1 - length(w.xz), 0, 1), 2)) * 100, 0, 8);
318  caustic = mix(1, caustic, clamp(ray_payload_brdf.hit_distance * 0.02, 0, 1));
319  throughput = vec3(caustic);
320 
321  if(surface_medium != MEDIUM_NONE)
322  {
323  extinction_distance = ray_payload_brdf.hit_distance;
324  }
325  else
326  {
327  if(is_water(triangle.material_id))
328  surface_medium = MEDIUM_WATER;
329  else
330  surface_medium = MEDIUM_SLIME;
331 
332  extinction_distance = max(0, ray.t_max - ray_payload_brdf.hit_distance);
333  }
334  }
335  else if(is_glass(triangle.material_id) || is_water(triangle.material_id) && is_vertical)
336  {
337  vec3 bary = get_hit_barycentric(ray_payload_brdf);
338  vec2 tex_coord = triangle.tex_coords * bary;
339 
340  MaterialInfo minfo = get_material_info(triangle.material_id);
341 
342  vec3 albedo = global_textureLod(minfo.diffuse_texture, tex_coord, 2).rgb;
343 
344  if((triangle.material_id & MATERIAL_FLAG_CORRECT_ALBEDO) != 0)
345  albedo = correct_albedo(albedo);
346 
347  throughput = albedo;
348  }
349  }
350 
351  //return vec3(caustic);
352  return extinction(surface_medium, extinction_distance) * throughput;
353 }
354 
355 vec3 rgbToNormal(vec3 rgb, out float len)
356 {
357  vec3 n = vec3(rgb.xy * 2 - 1, rgb.z);
358 
359  len = length(n);
360  return len > 0 ? n / len : vec3(0);
361 }
362 
363 
364 float
365 AdjustRoughnessToksvig(float roughness, float normalMapLen, float mip_level)
366 {
367  float effect = global_ubo.pt_toksvig * clamp(mip_level, 0, 1);
368  float shininess = RoughnessSquareToSpecPower(roughness) * effect; // not squaring the roughness here - looks better this way
369  float ft = normalMapLen / mix(shininess, 1.0f, normalMapLen);
370  ft = max(ft, 0.01f);
371  return SpecPowerToRoughnessSquare(ft * shininess / effect);
372 }
373 
374 void
376  vec3 position,
377  vec3 normal,
378  vec3 geo_normal,
379  uint cluster_idx,
380  uint material_id,
381  int shadow_cull_mask,
382  vec3 view_direction,
383  float roughness,
384  int surface_medium,
385  bool enable_caustics,
386  float surface_specular,
387  float direct_specular_weight,
388  bool enable_polygonal,
389  bool enable_spherical,
390  bool is_gradient,
391  int bounce,
392  out vec3 diffuse,
393  out vec3 specular)
394 {
395  diffuse = vec3(0);
396  specular = vec3(0);
397 
398  vec3 pos_on_light_polygonal;
399  vec3 pos_on_light_spherical;
400 
401  vec3 contrib_polygonal = vec3(0);
402  vec3 contrib_spherical = vec3(0);
403 
404  float alpha = square(roughness);
405  float phong_exp = RoughnessSquareToSpecPower(alpha);
406  float phong_scale = min(100, 1 / (M_PI * square(alpha)));
407  float phong_weight = clamp(surface_specular * direct_specular_weight, 0, 0.9);
408 
409  int polygonal_light_index = -1;
410  float polygonal_light_area = 0;
411 
412  vec3 rng = vec3(
414  get_rng(RNG_NEE_TRI_X(bounce)),
415  get_rng(RNG_NEE_TRI_Y(bounce)));
416 
417  /* polygonal light illumination */
418  if(enable_polygonal)
419  {
421  cluster_idx,
422  position,
423  normal,
424  geo_normal,
425  view_direction,
426  phong_exp,
427  phong_scale,
428  phong_weight,
429  is_gradient,
430  pos_on_light_polygonal,
431  contrib_polygonal,
432  polygonal_light_index,
433  polygonal_light_area,
434  rng);
435  }
436 
437  bool is_polygonal = true;
438  float vis = 1;
439 
440  /* spherical light illumination */
441  if(enable_spherical)
442  {
443  // Limit the solid angle of sphere lights for indirect lighting
444  // in order to kill some fireflies in locations with many sphere lights.
445  // Example: green wall-lamp corridor in the "train" map.
446  float max_solid_angle = (bounce == 0) ? 2 * M_PI : 0.02;
447 
449  position,
450  normal,
451  geo_normal,
452  max_solid_angle,
453  pos_on_light_spherical,
454  contrib_spherical,
455  rng);
456  }
457 
458  float spec_polygonal = phong(normal, normalize(pos_on_light_polygonal - position), view_direction, phong_exp) * phong_scale;
459  float spec_spherical = phong(normal, normalize(pos_on_light_spherical - position), view_direction, phong_exp) * phong_scale;
460 
461  float l_polygonal = luminance(abs(contrib_polygonal)) * mix(1, spec_polygonal, phong_weight);
462  float l_spherical = luminance(abs(contrib_spherical)) * mix(1, spec_spherical, phong_weight);
463  float l_sum = l_polygonal + l_spherical;
464 
465  bool null_light = (l_sum == 0);
466 
467  float w = null_light ? 0.5 : l_polygonal / (l_polygonal + l_spherical);
468 
469  float rng2 = get_rng(RNG_NEE_LIGHT_TYPE(bounce));
470  is_polygonal = (rng2 < w);
471  vis = is_polygonal ? (1 / w) : (1 / (1 - w));
472  vec3 pos_on_light = null_light ? position : (is_polygonal ? pos_on_light_polygonal : pos_on_light_spherical);
473  vec3 contrib = is_polygonal ? contrib_polygonal : contrib_spherical;
474 
475  Ray shadow_ray = get_shadow_ray(position - view_direction * 0.001, pos_on_light, 0);
476 
477  vis *= trace_shadow_ray(shadow_ray, null_light ? 0 : shadow_cull_mask);
478 #ifdef ENABLE_SHADOW_CAUSTICS
479  if(enable_caustics)
480  {
481  contrib *= trace_caustic_ray(shadow_ray, surface_medium);
482  }
483 #endif
484 
485  /*
486  Accumulate light shadowing statistics to guide importance sampling on the next frame.
487  Inspired by paper called "Adaptive Shadow Testing for Ray Tracing" by G. Ward, EUROGRAPHICS 1994.
488 
489  The algorithm counts the shadowed and unshadowed rays towards each light, per cluster,
490  per surface orientation in each cluster. Orientation helps improve accuracy in cases
491  when a single cluster has different parts which have the same light mostly shadowed and
492  mostly unshadowed.
493 
494  On the next frame, the light CDF is built using the counts from this frame, or the frame
495  before that in case of gradient rays. See light_lists.h for more info.
496 
497  Only applies to polygonal polygon lights (i.e. no model or beam lights) because the spherical
498  polygon lights do not have polygonal indices, and it would be difficult to map them
499  between frames.
500  */
501  if(global_ubo.pt_light_stats != 0
502  && is_polygonal
503  && !null_light
504  && polygonal_light_index >= 0
505  && polygonal_light_index < global_ubo.num_static_lights)
506  {
507  uint addr = get_light_stats_addr(cluster_idx, polygonal_light_index, get_primary_direction(normal));
508 
509  // Offset 0 is unshadowed rays,
510  // Offset 1 is shadowed rays
511  if(vis == 0) addr += 1;
512 
513  // Increment the ray counter
514  atomicAdd(light_stats_bufers[global_ubo.current_frame_idx % NUM_LIGHT_STATS_BUFFERS].stats[addr], 1);
515  }
516 
517  if(null_light)
518  return;
519 
520  diffuse = vis * contrib;
521 
522  if(is_polygonal && direct_specular_weight > 0)
523  {
524  // MIS with direct specular and indirect specular.
525  // Only applied to sky lights, for two reasons:
526  // 1) Non-sky lights are trimmed to match the light texture, and indirect rays don't see that;
527  // 2) Non-sky lights are usually away from walls, so the direct sampling issue is not as pronounced.
528  direct_specular_weight *= 1.0 - smoothstep(
529  global_ubo.pt_direct_area_threshold,
530  global_ubo.pt_direct_area_threshold * 2,
531  polygonal_light_area);
532  }
533 
534  if(vis > 0 && direct_specular_weight > 0)
535  {
536  specular = diffuse * (GGX(view_direction, normalize(pos_on_light - position), normal, roughness, 0.0) * direct_specular_weight);
537  }
538 
539  vec3 L = pos_on_light - position;
540  L = normalize(L);
541 
542  float NdotL = max(0, dot(normal, L));
543 
544  diffuse *= NdotL / M_PI;
545 }
546 
547 void
549  uint cluster_idx,
550  uint material_id,
551  vec3 position,
552  vec3 normal,
553  vec3 geo_normal,
554  vec3 view_direction,
555  float roughness,
556  int surface_medium,
557  bool enable_caustics,
558  out vec3 diffuse,
559  out vec3 specular,
560  int shadow_cull_mask)
561 {
562  diffuse = vec3(0);
563  specular = vec3(0);
564 
565  if(global_ubo.sun_visible == 0)
566  return;
567 
568  bool visible = (cluster_idx == ~0u) || (get_sky_visibility(cluster_idx >> 5) & (1 << (cluster_idx & 31))) != 0;
569 
570  if(!visible)
571  return;
572 
573  vec2 rng3 = vec2(get_rng(RNG_SUNLIGHT_X(0)), get_rng(RNG_SUNLIGHT_Y(0)));
574  vec2 disk = sample_disk(rng3);
575  disk.xy *= global_ubo.sun_tan_half_angle;
576 
577  vec3 direction = normalize(global_ubo.sun_direction + global_ubo.sun_tangent * disk.x + global_ubo.sun_bitangent * disk.y);
578 
579  float NdotL = dot(direction, normal);
580  float GNdotL = dot(direction, geo_normal);
581 
582  if(NdotL <= 0 || GNdotL <= 0)
583  return;
584 
585  Ray shadow_ray = get_shadow_ray(position - view_direction * 0.001, position + direction * 10000, 0);
586 
587  float vis = trace_shadow_ray(shadow_ray, shadow_cull_mask);
588 
589  if(vis == 0)
590  return;
591 
592 #ifdef ENABLE_SUN_SHAPE
593  // Fetch the sun color from the environment map.
594  // This allows us to get properly shaped shadows from the sun that is partially occluded
595  // by clouds or landscape.
596 
597  vec3 envmap_direction = (global_ubo.environment_rotation_matrix * vec4(direction, 0)).xyz;
598 
599  vec3 envmap = textureLod(TEX_PHYSICAL_SKY, envmap_direction.xzy, 0).rgb;
600 
601  diffuse = (global_ubo.sun_solid_angle * global_ubo.pt_env_scale) * envmap;
602 #else
603  // Fetch the average sun color from the resolved UBO - it's faster.
604 
605  diffuse = sun_color_ubo.sun_color;
606 #endif
607 
608 #ifdef ENABLE_SHADOW_CAUSTICS
609  if(enable_caustics)
610  {
611  diffuse *= trace_caustic_ray(shadow_ray, surface_medium);
612  }
613 #endif
614 
615  if(global_ubo.pt_sun_specular > 0)
616  {
617  float NoH_offset = 0.5 * square(global_ubo.sun_tan_half_angle);
618  specular = diffuse * GGX(view_direction, global_ubo.sun_direction, normal, roughness, NoH_offset);
619  }
620 
621  diffuse *= NdotL / M_PI;
622 }
623 
624 vec3 clamp_output(vec3 c)
625 {
626  if(any(isnan(c)) || any(isinf(c)))
627  return vec3(0);
628  else
629  return clamp(c, vec3(0), vec3(MAX_OUTPUT_VALUE));
630 }
631 
632 vec3
633 sample_emissive_texture(uint material_id, MaterialInfo minfo, vec2 tex_coord, vec2 tex_coord_x, vec2 tex_coord_y, float mip_level)
634 {
635  if (minfo.emissive_texture != 0)
636  {
637  vec4 image3;
638  if (mip_level >= 0)
639  image3 = global_textureLod(minfo.emissive_texture, tex_coord, mip_level);
640  else
641  image3 = global_textureGrad(minfo.emissive_texture, tex_coord, tex_coord_x, tex_coord_y);
642 
643  vec3 corrected = correct_emissive(material_id, image3.rgb);
644 
645  return corrected * minfo.emissive_scale;
646  }
647 
648  return vec3(0);
649 }
650 
651 vec2
652 lava_uv_warp(vec2 uv)
653 {
654  // Lava UV warp that (hopefully) matches the warp in the original Quake 2.
655  // Relevant bits of the original rasterizer:
656 
657  // #define AMP 8*0x10000
658  // #define SPEED 20
659  // #define CYCLE 128
660  // sintable[i] = AMP + sin(i * M_PI * 2 / CYCLE) * AMP;
661  // #define TURB_SIZE 64 // base turbulent texture size
662  // #define TURB_MASK (TURB_SIZE - 1)
663  // turb_s = ((s + turb[(t >> 16) & (CYCLE - 1)]) >> 16) & TURB_MASK;
664  // turb_t = ((t + turb[(s >> 16) & (CYCLE - 1)]) >> 16) & TURB_MASK;
665 
666  return uv.xy + sin(fract(uv.yx * 0.5 + global_ubo.time * 20 / 128) * 2 * M_PI) * 0.125;
667 }
668 
669 vec3 get_emissive_shell(uint material_id)
670 {
671  vec3 c = vec3(0);
672 
674  {
675  if((material_id & MATERIAL_FLAG_SHELL_RED) != 0) c.r += 1;
676  if((material_id & MATERIAL_FLAG_SHELL_GREEN) != 0) c.g += 1;
677  if((material_id & MATERIAL_FLAG_SHELL_BLUE) != 0) c.b += 1;
678 
679  if((material_id & MATERIAL_FLAG_WEAPON) != 0) c *= 0.2;
680  }
681 
682  if(tonemap_buffer.adapted_luminance > 0)
683  c.rgb *= tonemap_buffer.adapted_luminance * 100;
684 
685  return c;
686 }
687 
688 bool get_is_gradient(ivec2 ipos)
689 {
690  if(global_ubo.flt_enable != 0)
691  {
692  uint u = texelFetch(TEX_ASVGF_GRAD_SMPL_POS_A, ipos / GRAD_DWN, 0).r;
693 
694  ivec2 grad_strata_pos = ivec2(
695  u >> (STRATUM_OFFSET_SHIFT * 0),
696  u >> (STRATUM_OFFSET_SHIFT * 1)) & STRATUM_OFFSET_MASK;
697 
698  return (u > 0 && all(equal(grad_strata_pos, ipos % GRAD_DWN)));
699  }
700 
701  return false;
702 }
703 
704 
705 void
706 get_material(Triangle triangle, vec2 tex_coord, vec2 tex_coord_x, vec2 tex_coord_y, float mip_level, vec3 geo_normal,
707  out vec3 albedo, out vec3 normal, out float metallic, out float specular, out float roughness, out vec3 emissive)
708 {
709  if((triangle.material_id & MATERIAL_FLAG_FLOWING) != 0)
710  {
711  tex_coord.x -= global_ubo.time * 0.5;
712  }
713 
714  if((triangle.material_id & MATERIAL_FLAG_WARP) != 0)
715  {
716  tex_coord = lava_uv_warp(tex_coord);
717  }
718 
719 
720  MaterialInfo minfo = get_material_info(triangle.material_id);
721 
722 
723  vec4 image1;
724  if (mip_level >= 0)
725  image1 = global_textureLod(minfo.diffuse_texture, tex_coord, mip_level);
726  else
727  image1 = global_textureGrad(minfo.diffuse_texture, tex_coord, tex_coord_x, tex_coord_y);
728 
729  if((triangle.material_id & MATERIAL_FLAG_CORRECT_ALBEDO) != 0)
730  albedo = correct_albedo(image1.rgb);
731  else
732  albedo = image1.rgb;
733 
734  normal = geo_normal;
735  metallic = 0;
736  specular = 0;
737  roughness = 1;
738 
739  if (minfo.normals_texture != 0)// && dot(triangle.tangent, triangle.tangent) > 0)
740  {
741  vec4 image2;
742  if (mip_level >= 0)
743  image2 = global_textureLod(minfo.normals_texture, tex_coord, mip_level);
744  else
745  image2 = global_textureGrad(minfo.normals_texture, tex_coord, tex_coord_x, tex_coord_y);
746 
747  float normalMapLen;
748  vec3 local_normal = rgbToNormal(image2.rgb, normalMapLen);
749 
750  if(dot(triangle.tangent, triangle.tangent) > 0)
751  {
752  vec3 tangent = triangle.tangent,
753  bitangent = cross(geo_normal, tangent);
754 
755  if((triangle.material_id & MATERIAL_FLAG_HANDEDNESS) != 0)
756  bitangent = -bitangent;
757 
758  normal = tangent * local_normal.x + bitangent * local_normal.y + geo_normal * local_normal.z;
759 
760  float bump_scale = global_ubo.pt_bump_scale * minfo.bump_scale;
761  if(is_glass(triangle.material_id))
762  bump_scale *= 0.2;
763 
764  normal = normalize(mix(geo_normal, normal, bump_scale));
765  }
766 
767  metallic = clamp(image2.a * minfo.specular_scale, 0, 1);
768 
769  if(minfo.roughness_override >= 0)
770  roughness = max(image1.a, minfo.roughness_override);
771  else
772  roughness = image1.a;
773 
774  roughness = clamp(roughness, 0, 1);
775 
776  float effective_mip = mip_level;
777 
778  if (effective_mip < 0)
779  {
780  ivec2 texSize = global_textureSize(minfo.normals_texture, 0);
781  vec2 tx = tex_coord_x * texSize;
782  vec2 ty = tex_coord_y * texSize;
783  float d = max(dot(tx, tx), dot(ty, ty));
784  effective_mip = 0.5 * log2(d);
785  }
786 
787  bool is_mirror = (roughness < MAX_MIRROR_ROUGHNESS) && (is_chrome(triangle.material_id) || is_screen(triangle.material_id));
788 
789  if (normalMapLen > 0 && global_ubo.pt_toksvig > 0 && effective_mip > 0 && !is_mirror)
790  {
791  roughness = AdjustRoughnessToksvig(roughness, normalMapLen, effective_mip);
792  }
793  }
794 
795  if(global_ubo.pt_roughness_override >= 0) roughness = global_ubo.pt_roughness_override;
796  if(global_ubo.pt_metallic_override >= 0) metallic = global_ubo.pt_metallic_override;
797 
798  specular = mix(0.05, 1.0, metallic);
799 
800  emissive = sample_emissive_texture(triangle.material_id, minfo, tex_coord, tex_coord_x, tex_coord_y, mip_level);
801 
802  emissive += get_emissive_shell(triangle.material_id) * albedo * (1 - metallic * 0.9);
803 }
804 
805 bool get_camera_uv(vec2 tex_coord, out vec2 cameraUV)
806 {
807  const vec2 minUV = vec2(11.0 / 256.0, 14.0 / 256.0);
808  const vec2 maxUV = vec2(245.0 / 256.0, 148.0 / 256.0);
809 
810  tex_coord = fract(tex_coord);
811  cameraUV = (tex_coord - minUV) / (maxUV - minUV);
812 
813  //vec2 resolution = vec2(7, 4) * 50;
814  //cameraUV = (floor(cameraUV * resolution) + vec2(0.5)) / resolution;
815 
816  return all(greaterThan(cameraUV, vec2(0))) && all(lessThan(cameraUV, vec2(1)));
817 }
MATERIAL_KIND_TRANSPARENT
#define MATERIAL_KIND_TRANSPARENT
Definition: constants.h:68
get_direct_illumination
void get_direct_illumination(vec3 position, vec3 normal, vec3 geo_normal, uint cluster_idx, uint material_id, int shadow_cull_mask, vec3 view_direction, float roughness, int surface_medium, bool enable_caustics, float surface_specular, float direct_specular_weight, bool enable_polygonal, bool enable_spherical, bool is_gradient, int bounce, out vec3 diffuse, out vec3 specular)
Definition: path_tracer_rgen.h:375
MAX_MIRROR_ROUGHNESS
#define MAX_MIRROR_ROUGHNESS
Definition: constants.h:37
MATERIAL_FLAG_SHELL_GREEN
#define MATERIAL_FLAG_SHELL_GREEN
Definition: constants.h:81
MEDIUM_SLIME
#define MEDIUM_SLIME
Definition: constants.h:94
PRIM_ID_MASK
#define PRIM_ID_MASK
Definition: path_tracer.h:120
get_material
void get_material(Triangle triangle, vec2 tex_coord, vec2 tex_coord_x, vec2 tex_coord_y, float mip_level, vec3 geo_normal, out vec3 albedo, out vec3 normal, out float metallic, out float specular, out float roughness, out vec3 emissive)
Definition: path_tracer_rgen.h:706
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: light_lists.h:106
RNG_SUNLIGHT_Y
#define RNG_SUNLIGHT_Y(bounce)
Definition: path_tracer_rgen.h:54
MATERIAL_FLAG_CORRECT_ALBEDO
#define MATERIAL_FLAG_CORRECT_ALBEDO
Definition: constants.h:74
MATERIAL_KIND_LAVA
#define MATERIAL_KIND_LAVA
Definition: constants.h:62
trace_caustic_ray
vec3 trace_caustic_ray(Ray ray, int surface_medium)
Definition: path_tracer_rgen.h:294
env_map
vec3 env_map(vec3 direction, bool remove_sun)
Definition: path_tracer_rgen.h:81
vertex_buffer.h
AdjustRoughnessToksvig
float AdjustRoughnessToksvig(float roughness, float normalMapLen, float mip_level)
Definition: path_tracer_rgen.h:365
BLUE_NOISE_RES
#define BLUE_NOISE_RES
Definition: constants.h:42
RayPayloadShadow
Definition: path_tracer.h:139
uint
uint32_t uint
Definition: global_ubo.h:233
ALBEDO_TRANSFORM_SCALE
#define ALBEDO_TRANSFORM_SCALE
Definition: constants.h:31
MATERIAL_FLAG_WARP
#define MATERIAL_FLAG_WARP
Definition: constants.h:77
trace_shadow_ray
float trace_shadow_ray(Ray ray, int cull_mask)
Definition: path_tracer_rgen.h:280
MATERIAL_FLAG_FLOWING
#define MATERIAL_FLAG_FLOWING
Definition: constants.h:78
get_image_position
ivec2 get_image_position()
Definition: path_tracer_rgen.h:110
MATERIAL_KIND_CHROME_MODEL
#define MATERIAL_KIND_CHROME_MODEL
Definition: constants.h:71
MATERIAL_FLAG_HANDEDNESS
#define MATERIAL_FLAG_HANDEDNESS
Definition: constants.h:75
trace_ray
void trace_ray(Ray ray, bool cull_back_faces, int instance_mask)
Definition: path_tracer_rgen.h:249
global_textures.h
SBT_RMISS_SHADOW
#define SBT_RMISS_SHADOW
Definition: constants.h:129
get_emissive_shell
vec3 get_emissive_shell(uint material_id)
Definition: path_tracer_rgen.h:669
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: light_lists.h:267
is_screen
bool is_screen(uint material)
Definition: path_tracer_rgen.h:225
get_sunlight
void get_sunlight(uint cluster_idx, uint material_id, vec3 position, vec3 normal, vec3 geo_normal, vec3 view_direction, float roughness, int surface_medium, bool enable_caustics, out vec3 diffuse, out vec3 specular, int shadow_cull_mask)
Definition: path_tracer_rgen.h:548
RAY_GEN_DESCRIPTOR_SET_IDX
#define RAY_GEN_DESCRIPTOR_SET_IDX
Definition: path_tracer_rgen.h:23
RayPayload::instance_prim
uint instance_prim
Definition: path_tracer.h:133
light_lists.h
MATERIAL_FLAG_WEAPON
#define MATERIAL_FLAG_WEAPON
Definition: constants.h:76
RNG_NEE_LIGHT_TYPE
#define RNG_NEE_LIGHT_TYPE(bounce)
Definition: path_tracer_rgen.h:49
Ray::origin
vec3 origin
Definition: path_tracer_rgen.h:76
INSTANCE_DYNAMIC_FLAG
#define INSTANCE_DYNAMIC_FLAG
Definition: path_tracer.h:118
Ray::t_min
float t_min
Definition: path_tracer_rgen.h:77
MATERIAL_FLAG_SHELL_BLUE
#define MATERIAL_FLAG_SHELL_BLUE
Definition: constants.h:82
is_dynamic_instance
bool is_dynamic_instance(RayPayload pay_load)
Definition: path_tracer_rgen.h:146
is_glass
bool is_glass(uint material)
Definition: path_tracer_rgen.h:206
RayPayload::barycentric
vec2 barycentric
Definition: path_tracer.h:132
SBT_RCHIT_EMPTY
#define SBT_RCHIT_EMPTY
Definition: constants.h:135
RNG_NEE_LIGHT_SELECTION
#define RNG_NEE_LIGHT_SELECTION(bounce)
Definition: path_tracer_rgen.h:46
mix
static float mix(float a, float b, float s)
Definition: bloom.c:83
Ray::t_max
float t_max
Definition: path_tracer_rgen.h:77
ENVIRONMENT_DYNAMIC
#define ENVIRONMENT_DYNAMIC
Definition: constants.h:100
is_transparent
bool is_transparent(uint material)
Definition: path_tracer_rgen.h:212
ALBEDO_TRANSFORM_POWER
#define ALBEDO_TRANSFORM_POWER
Definition: constants.h:33
RNG_SUNLIGHT_X
#define RNG_SUNLIGHT_X(bounce)
Definition: path_tracer_rgen.h:53
rgbToNormal
vec3 rgbToNormal(vec3 rgb, out float len)
Definition: path_tracer_rgen.h:355
push_constants
push_constants
Definition: path_tracer.h:129
get_shadow_ray
Ray get_shadow_ray(vec3 p1, vec3 p2, float tmin)
Definition: path_tracer_rgen.h:264
MATERIAL_KIND_MASK
#define MATERIAL_KIND_MASK
Definition: constants.h:57
is_slime
bool is_slime(uint material)
Definition: path_tracer_rgen.h:194
NUM_BLUE_NOISE_TEX
#define NUM_BLUE_NOISE_TEX
Definition: constants.h:41
INSTANCE_SKY_FLAG
#define INSTANCE_SKY_FLAG
Definition: path_tracer.h:119
MATERIAL_KIND_CHROME
#define MATERIAL_KIND_CHROME
Definition: constants.h:60
MATERIAL_FLAG_SHELL_RED
#define MATERIAL_FLAG_SHELL_RED
Definition: constants.h:80
get_image_size
ivec2 get_image_size()
Definition: path_tracer_rgen.h:128
path_tracer.h
NUM_LIGHT_STATS_BUFFERS
#define NUM_LIGHT_STATS_BUFFERS
Definition: constants.h:44
is_camera
bool is_camera(uint material)
Definition: path_tracer_rgen.h:231
ENVIRONMENT_STATIC
#define ENVIRONMENT_STATIC
Definition: constants.h:99
RNG_NEE_TRI_X
#define RNG_NEE_TRI_X(bounce)
Definition: path_tracer_rgen.h:47
SBT_RMISS_PATH_TRACER
#define SBT_RMISS_PATH_TRACER
Definition: constants.h:128
MEDIUM_WATER
#define MEDIUM_WATER
Definition: constants.h:93
is_sky
bool is_sky(RayPayload rp)
Definition: path_tracer_rgen.h:140
get_camera_uv
bool get_camera_uv(vec2 tex_coord, out vec2 cameraUV)
Definition: path_tracer_rgen.h:805
get_hit_barycentric
vec3 get_hit_barycentric(RayPayload rp)
Definition: path_tracer_rgen.h:168
c
statCounters_t c
Definition: main.c:30
MATERIAL_KIND_CAMERA
#define MATERIAL_KIND_CAMERA
Definition: constants.h:70
rng_seed
uint rng_seed
Definition: path_tracer_rgen.h:73
Ray
Definition: path_tracer_rgen.h:75
sample_emissive_texture
vec3 sample_emissive_texture(uint material_id, MaterialInfo minfo, vec2 tex_coord, vec2 tex_coord_x, vec2 tex_coord_y, float mip_level)
Definition: path_tracer_rgen.h:633
MATERIAL_KIND_SLIME
#define MATERIAL_KIND_SLIME
Definition: constants.h:63
visible
qboolean visible(edict_t *self, edict_t *other)
Definition: g_ai.c:268
Ray::direction
vec3 direction
Definition: path_tracer_rgen.h:76
EMISSIVE_TRANSFORM_BIAS
#define EMISSIVE_TRANSFORM_BIAS
Definition: constants.h:35
sample_disk
static void sample_disk(float *u, float *v)
Definition: shadow_map.c:448
correct_albedo
vec3 correct_albedo(vec3 albedo)
Definition: path_tracer_rgen.h:237
SBT_RCHIT_OPAQUE
#define SBT_RCHIT_OPAQUE
Definition: constants.h:130
get_is_gradient
bool get_is_gradient(ivec2 ipos)
Definition: path_tracer_rgen.h:688
get_light_stats_addr
uint get_light_stats_addr(uint cluster, uint light, uint side)
Definition: light_lists.h:96
RT_PAYLOAD_SHADOW
#define RT_PAYLOAD_SHADOW
Definition: path_tracer_rgen.h:68
L
#define L(name)
Definition: g_save.c:47
ALBEDO_TRANSFORM_BIAS
#define ALBEDO_TRANSFORM_BIAS
Definition: constants.h:32
MATERIAL_KIND_SCREEN
#define MATERIAL_KIND_SCREEN
Definition: constants.h:69
correct_emissive
vec3 correct_emissive(uint material_id, vec3 emissive)
Definition: path_tracer_rgen.h:243
found_intersection
bool found_intersection(RayPayload rp)
Definition: path_tracer_rgen.h:134
is_chrome
bool is_chrome(uint material)
Definition: path_tracer_rgen.h:218
is_water
bool is_water(uint material)
Definition: path_tracer_rgen.h:188
RayPayload
Definition: path_tracer.h:131
RNG_NEE_TRI_Y
#define RNG_NEE_TRI_Y(bounce)
Definition: path_tracer_rgen.h:48
get_rng
float get_rng(uint idx)
Definition: path_tracer_rgen.h:177
int
CONST PIXELFORMATDESCRIPTOR int
Definition: wgl.c:26
AS_FLAG_TRANSPARENT
#define AS_FLAG_TRANSPARENT
Definition: constants.h:108
MATERIAL_KIND_WATER
#define MATERIAL_KIND_WATER
Definition: constants.h:61
get_primitive
uint get_primitive(RayPayload pay_load)
Definition: path_tracer_rgen.h:152
clamp_output
vec3 clamp_output(vec3 c)
Definition: path_tracer_rgen.h:624
MAX_OUTPUT_VALUE
#define MAX_OUTPUT_VALUE
Definition: path_tracer_rgen.h:66
get_hit_triangle
Triangle get_hit_triangle(RayPayload rp)
Definition: path_tracer_rgen.h:158
layout
layout(set=RAY_GEN_DESCRIPTOR_SET_IDX, binding=0) uniform accelerationStructureNV topLevelAS
is_lava
bool is_lava(uint material)
Definition: path_tracer_rgen.h:200
RT_PAYLOAD_BRDF
#define RT_PAYLOAD_BRDF
Definition: path_tracer_rgen.h:69
MEDIUM_NONE
#define MEDIUM_NONE
Definition: constants.h:92
MATERIAL_KIND_GLASS
#define MATERIAL_KIND_GLASS
Definition: constants.h:64
lava_uv_warp
vec2 lava_uv_warp(vec2 uv)
Definition: path_tracer_rgen.h:652
GRAD_DWN
#define GRAD_DWN
Definition: constants.h:22