Cleanup: misc spelling fixes
[blender.git] / source / blender / draw / engines / eevee / shaders / lightprobe_lib.glsl
1 /* ----------- Uniforms --------- */
2
3 uniform sampler2DArray probePlanars;
4 uniform sampler2DArray probeCubes;
5
6 /* ----------- Structures --------- */
7
8 struct CubeData {
9   vec4 position_type;
10   vec4 attenuation_fac_type;
11   mat4 influencemat;
12   mat4 parallaxmat;
13 };
14
15 #define PROBE_PARALLAX_BOX 1.0
16 #define PROBE_ATTENUATION_BOX 1.0
17
18 #define p_position position_type.xyz
19 #define p_parallax_type position_type.w
20 #define p_atten_fac attenuation_fac_type.x
21 #define p_atten_type attenuation_fac_type.y
22
23 struct PlanarData {
24   vec4 plane_equation;
25   vec4 clip_vec_x_fade_scale;
26   vec4 clip_vec_y_fade_bias;
27   vec4 clip_edges;
28   vec4 facing_scale_bias;
29   mat4 reflectionmat; /* transform world space into reflection texture space */
30   mat4 unused;
31 };
32
33 #define pl_plane_eq plane_equation
34 #define pl_normal plane_equation.xyz
35 #define pl_facing_scale facing_scale_bias.x
36 #define pl_facing_bias facing_scale_bias.y
37 #define pl_fade_scale clip_vec_x_fade_scale.w
38 #define pl_fade_bias clip_vec_y_fade_bias.w
39 #define pl_clip_pos_x clip_vec_x_fade_scale.xyz
40 #define pl_clip_pos_y clip_vec_y_fade_bias.xyz
41 #define pl_clip_edges clip_edges
42
43 struct GridData {
44   mat4 localmat;
45   ivec4 resolution_offset;
46   vec4 ws_corner_atten_scale;     /* world space corner position */
47   vec4 ws_increment_x_atten_bias; /* world space vector between 2 opposite cells */
48   vec4 ws_increment_y_lvl_bias;
49   vec4 ws_increment_z;
50   vec4 vis_bias_bleed_range;
51 };
52
53 #define g_corner ws_corner_atten_scale.xyz
54 #define g_atten_scale ws_corner_atten_scale.w
55 #define g_atten_bias ws_increment_x_atten_bias.w
56 #define g_level_bias ws_increment_y_lvl_bias.w
57 #define g_increment_x ws_increment_x_atten_bias.xyz
58 #define g_increment_y ws_increment_y_lvl_bias.xyz
59 #define g_increment_z ws_increment_z.xyz
60 #define g_resolution resolution_offset.xyz
61 #define g_offset resolution_offset.w
62 #define g_vis_bias vis_bias_bleed_range.x
63 #define g_vis_bleed vis_bias_bleed_range.y
64 #define g_vis_range vis_bias_bleed_range.z
65
66 #ifndef MAX_PROBE
67 #  define MAX_PROBE 1
68 #endif
69 #ifndef MAX_GRID
70 #  define MAX_GRID 1
71 #endif
72 #ifndef MAX_PLANAR
73 #  define MAX_PLANAR 1
74 #endif
75
76 #ifndef UTIL_TEX
77 #  define UTIL_TEX
78 uniform sampler2DArray utilTex;
79 #  define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
80 #endif /* UTIL_TEX */
81
82 layout(std140) uniform probe_block
83 {
84   CubeData probes_data[MAX_PROBE];
85 };
86
87 layout(std140) uniform grid_block
88 {
89   GridData grids_data[MAX_GRID];
90 };
91
92 layout(std140) uniform planar_block
93 {
94   PlanarData planars_data[MAX_PLANAR];
95 };
96
97 /* ----------- Functions --------- */
98
99 float probe_attenuation_cube(int pd_id, vec3 W)
100 {
101   vec3 localpos = transform_point(probes_data[pd_id].influencemat, W);
102
103   float probe_atten_fac = probes_data[pd_id].p_atten_fac;
104   float fac;
105   if (probes_data[pd_id].p_atten_type == PROBE_ATTENUATION_BOX) {
106     vec3 axes_fac = saturate(probe_atten_fac - probe_atten_fac * abs(localpos));
107     fac = min_v3(axes_fac);
108   }
109   else {
110     fac = saturate(probe_atten_fac - probe_atten_fac * length(localpos));
111   }
112
113   return fac;
114 }
115
116 float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness)
117 {
118   /* Normal Facing */
119   float fac = saturate(dot(pd.pl_normal, N) * pd.pl_facing_scale + pd.pl_facing_bias);
120
121   /* Distance from plane */
122   fac *= saturate(abs(dot(pd.pl_plane_eq, vec4(W, 1.0))) * pd.pl_fade_scale + pd.pl_fade_bias);
123
124   /* Fancy fast clipping calculation */
125   vec2 dist_to_clip;
126   dist_to_clip.x = dot(pd.pl_clip_pos_x, W);
127   dist_to_clip.y = dot(pd.pl_clip_pos_y, W);
128   /* compare and add all tests */
129   fac *= step(2.0, dot(step(pd.pl_clip_edges, dist_to_clip.xxyy), vec2(-1.0, 1.0).xyxy));
130
131   /* Decrease influence for high roughness */
132   fac *= saturate(1.0 - roughness * 10.0);
133
134   return fac;
135 }
136
137 float probe_attenuation_grid(GridData gd, mat4 localmat, vec3 W, out vec3 localpos)
138 {
139   localpos = transform_point(localmat, W);
140   vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0);
141   float fade = length(pos_to_edge);
142   return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias);
143 }
144
145 vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness)
146 {
147   /* Correct reflection ray using parallax volume intersection. */
148   vec3 localpos = transform_point(probes_data[pd_id].parallaxmat, W);
149   vec3 localray = transform_direction(probes_data[pd_id].parallaxmat, R);
150
151   float dist;
152   if (probes_data[pd_id].p_parallax_type == PROBE_PARALLAX_BOX) {
153     dist = line_unit_box_intersect_dist(localpos, localray);
154   }
155   else {
156     dist = line_unit_sphere_intersect_dist(localpos, localray);
157   }
158
159   /* Use Distance in WS directly to recover intersection */
160   vec3 intersection = W + R * dist - probes_data[pd_id].p_position;
161
162   /* From Frostbite PBR Course
163    * Distance based roughness
164    * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
165    */
166   float original_roughness = roughness;
167   float linear_roughness = sqrt(roughness);
168   float distance_roughness = saturate(dist * linear_roughness / length(intersection));
169   linear_roughness = mix(distance_roughness, linear_roughness, linear_roughness);
170   roughness = linear_roughness * linear_roughness;
171
172   float fac = saturate(original_roughness * 2.0 - 1.0);
173   R = mix(intersection, R, fac * fac);
174
175   return textureLod_octahedron(
176              probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax, prbLodCubeMax)
177       .rgb;
178 }
179
180 vec3 probe_evaluate_world_spec(vec3 R, float roughness)
181 {
182   return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax)
183       .rgb;
184 }
185
186 vec3 probe_evaluate_planar(
187     float id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness, inout float fade)
188 {
189   /* Find view vector / reflection plane intersection. */
190   vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
191
192   /* How far the pixel is from the plane. */
193   float ref_depth = 1.0; /* TODO parameter */
194
195   /* Compute distorded reflection vector based on the distance to the reflected object.
196    * In other words find intersection between reflection vector and the sphere center
197    * around point_on_plane. */
198   vec3 proj_ref = reflect(reflect(-V, N) * ref_depth, pd.pl_normal);
199
200   /* Final point in world space. */
201   vec3 ref_pos = point_on_plane + proj_ref;
202
203   /* Reproject to find texture coords. */
204   vec4 refco = ViewProjectionMatrix * vec4(ref_pos, 1.0);
205   refco.xy /= refco.w;
206
207   /* TODO: If we support non-ssr planar reflection, we should blur them with gaussian
208    * and chose the right mip depending on the cone footprint after projection */
209   /* NOTE: X is inverted here to compensate inverted drawing.  */
210   vec3 sample = textureLod(probePlanars, vec3(refco.xy * vec2(-0.5, 0.5) + 0.5, id), 0.0).rgb;
211
212   return sample;
213 }
214
215 void fallback_cubemap(vec3 N,
216                       vec3 V,
217                       vec3 W,
218                       vec3 viewPosition,
219                       float roughness,
220                       float roughnessSquared,
221                       inout vec4 spec_accum)
222 {
223   /* Specular probes */
224   vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
225
226 #ifdef SSR_AO
227   vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
228   vec3 bent_normal;
229   float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal);
230   final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
231 #else
232   const float final_ao = 1.0;
233 #endif
234
235   /* Starts at 1 because 0 is world probe */
236   for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) {
237     float fade = probe_attenuation_cube(i, W);
238
239     if (fade > 0.0) {
240       vec3 spec = final_ao * probe_evaluate_cube(i, W, spec_dir, roughness);
241       accumulate_light(spec, fade, spec_accum);
242     }
243   }
244
245   /* World Specular */
246   if (spec_accum.a < 0.999) {
247     vec3 spec = final_ao * probe_evaluate_world_spec(spec_dir, roughness);
248     accumulate_light(spec, 1.0, spec_accum);
249   }
250 }
251
252 #ifdef IRRADIANCE_LIB
253 vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
254 {
255   localpos = localpos * 0.5 + 0.5;
256   localpos = localpos * vec3(gd.g_resolution) - 0.5;
257
258   vec3 localpos_floored = floor(localpos);
259   vec3 trilinear_weight = fract(localpos);
260
261   float weight_accum = 0.0;
262   vec3 irradiance_accum = vec3(0.0);
263
264   /* For each neighbor cells */
265   for (int i = 0; i < 8; ++i) {
266     ivec3 offset = ivec3(i, i >> 1, i >> 2) & ivec3(1);
267     vec3 cell_cos = clamp(localpos_floored + vec3(offset), vec3(0.0), vec3(gd.g_resolution) - 1.0);
268
269     /* Keep in sync with update_irradiance_probe */
270     ivec3 icell_cos = ivec3(gd.g_level_bias * floor(cell_cos / gd.g_level_bias));
271     int cell = gd.g_offset + icell_cos.z + icell_cos.y * gd.g_resolution.z +
272                icell_cos.x * gd.g_resolution.z * gd.g_resolution.y;
273
274     vec3 color = irradiance_from_cell_get(cell, N);
275
276     /* We need this because we render probes in world space (so we need light vector in WS).
277      * And rendering them in local probe space is too much problem. */
278     vec3 ws_cell_location = gd.g_corner +
279                             (gd.g_increment_x * cell_cos.x + gd.g_increment_y * cell_cos.y +
280                              gd.g_increment_z * cell_cos.z);
281
282     vec3 ws_point_to_cell = ws_cell_location - W;
283     float ws_dist_point_to_cell = length(ws_point_to_cell);
284     vec3 ws_light = ws_point_to_cell / ws_dist_point_to_cell;
285
286     /* Smooth backface test */
287     float weight = saturate(dot(ws_light, N));
288
289     /* Precomputed visibility */
290     weight *= load_visibility_cell(
291         cell, ws_light, ws_dist_point_to_cell, gd.g_vis_bias, gd.g_vis_bleed, gd.g_vis_range);
292
293     /* Smoother transition */
294     weight += prbIrradianceSmooth;
295
296     /* Trilinear weights */
297     vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, offset);
298     weight *= trilinear.x * trilinear.y * trilinear.z;
299
300     /* Avoid zero weight */
301     weight = max(0.00001, weight);
302
303     weight_accum += weight;
304     irradiance_accum += color * weight;
305   }
306
307   return irradiance_accum / weight_accum;
308 }
309
310 vec3 probe_evaluate_world_diff(vec3 N)
311 {
312   return irradiance_from_cell_get(0, N);
313 }
314
315 #endif /* IRRADIANCE_LIB */