1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
/**
* Final denoise step using a bilateral filter. Filter radius is controled by variance estimate.
*
* Inputs: Ray radiance (denoised), Mean hit depth, Extimated variance from ray reconstruction
* Outputs: Ray radiance (filtered).
*
* Linear depth is packed in ray_radiance for this step.
* Following "Stochastic All The Things: Raytracing in Hybrid Real-Time Rendering"
* by Tomasz Stachowiak
* https://www.ea.com/seed/news/seed-dd18-presentation-slides-raytracing
*/
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_bsdf_microfacet_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
#if defined(DIFFUSE)
# define RADIUS 4
#elif defined(REFRACTION)
# define RADIUS 1
#else
# define RADIUS 1
#endif
float normal_pdf(float x_sqr, float sigma_inv, float sigma_inv_sqr)
{
return exp(-0.5 * x_sqr * sigma_inv_sqr) * sigma_inv;
}
void main(void)
{
vec2 uv = uvcoordsvar.xy;
float ray_variance = texture(ray_variance_tx, uv).r;
vec4 ray_data = texture(ray_radiance_tx, uv);
float center_depth = ray_data.w;
vec2 texel_size = hiz_buf.pixel_to_ndc * 0.5;
out_combined = vec4(0.0);
out_diffuse = vec4(0.0);
out_specular = vec3(0.0);
#if defined(DIFFUSE)
ClosureDiffuse closure = gbuffer_load_diffuse_data(cl_color_tx, cl_normal_tx, cl_data_tx, uv);
if (closure.sss_radius.r < 0.0) {
return;
}
float sigma_pixel = 3.0;
#elif defined(REFRACTION)
ClosureRefraction closure = gbuffer_load_refraction_data(
cl_color_tx, cl_normal_tx, cl_data_tx, uv);
if (closure.ior == -1.0) {
return;
}
float sigma_pixel = 1.0;
#else
ClosureReflection closure = gbuffer_load_reflection_data(cl_color_tx, cl_normal_tx, uv);
float sigma_pixel = 1.0;
#endif
/* TODO(fclem): Sigma based on variance. */
float sigma_depth = 0.1; /* TODO user option? */
float px_sigma_inv = 1.0 / sigma_pixel;
float px_sigma_inv_sqr = sqr(px_sigma_inv);
float depth_sigma_inv = 1.0 / sigma_depth;
float depth_sigma_inv_sqr = sqr(depth_sigma_inv);
float weight_accum = normal_pdf(0.0, px_sigma_inv, px_sigma_inv_sqr);
vec3 radiance_accum = ray_data.rgb * weight_accum;
for (int x = -RADIUS; x <= RADIUS; x++) {
for (int y = -RADIUS; y <= RADIUS; y++) {
/* Skip center pixels. */
if (x == 0 && y == 0) {
continue;
}
vec2 sample_uv = uv + vec2(x, y) * texel_size;
vec4 ray_data = texture(ray_radiance_tx, sample_uv);
/* Skip unprocessed pixels. */
if (ray_data.w == 0.0) {
continue;
}
float delta_pixel_sqr = len_squared(vec2(x, y));
float delta_depth_sqr = sqr(abs(center_depth - ray_data.w));
/* TODO(fclem): OPTI might be a good idea to compare view normal to avoid one matrix mult. */
vec3 sample_N = gbuffer_decode_normal(texture(cl_normal_tx, sample_uv).xy);
/* Bilateral weight. */
float weight = saturate(dot(sample_N, closure.N)) *
normal_pdf(delta_pixel_sqr, px_sigma_inv, px_sigma_inv_sqr) *
normal_pdf(delta_depth_sqr, depth_sigma_inv, depth_sigma_inv_sqr);
radiance_accum += ray_data.rgb * weight;
weight_accum += weight;
}
}
radiance_accum *= safe_rcp(weight_accum);
radiance_accum *= closure.color;
out_combined = vec4(radiance_accum, 0.0);
#if defined(DIFFUSE)
out_diffuse.rgb = radiance_accum;
#else
out_specular = radiance_accum;
#endif
}
|