a27dc011ac2da61ecf57b350ec70e70f2f243137
[blender.git] / source / blender / draw / engines / eevee / shaders / raytrace_lib.glsl
1 #define MAX_STEP 256
2
3 float sample_depth(vec2 uv, int index, float lod)
4 {
5 #ifdef PLANAR_PROBE_RAYTRACE
6   if (index > -1) {
7     return textureLod(planarDepth, vec3(uv, index), 0.0).r;
8   }
9   else {
10 #endif
11     /* Correct UVs for mipmaping mis-alignment */
12     uv *= mipRatio[int(lod) + hizMipOffset];
13     return textureLod(maxzBuffer, uv, lod).r;
14 #ifdef PLANAR_PROBE_RAYTRACE
15   }
16 #endif
17 }
18
19 vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod)
20 {
21   vec4 depths;
22 #ifdef PLANAR_PROBE_RAYTRACE
23   if (index > -1) {
24     depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r;
25     depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r;
26     depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r;
27     depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r;
28   }
29   else {
30 #endif
31     depths.x = textureLod(maxzBuffer, uv1.xy, lod).r;
32     depths.y = textureLod(maxzBuffer, uv1.zw, lod).r;
33     depths.z = textureLod(maxzBuffer, uv2.xy, lod).r;
34     depths.w = textureLod(maxzBuffer, uv2.zw, lod).r;
35 #ifdef PLANAR_PROBE_RAYTRACE
36   }
37 #endif
38   return depths;
39 }
40
41 float refine_isect(float prev_delta, float curr_delta)
42 {
43   /**
44    * Simplification of 2D intersection :
45    * r0 = (0.0, prev_ss_ray.z);
46    * r1 = (1.0, curr_ss_ray.z);
47    * d0 = (0.0, prev_hit_depth_sample);
48    * d1 = (1.0, curr_hit_depth_sample);
49    * vec2 r = r1 - r0;
50    * vec2 d = d1 - d0;
51    * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d);
52    *
53    * We only want isect.x to know how much stride we need. So it simplifies :
54    *
55    * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d);
56    * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d);
57    */
58   return saturate(prev_delta / (prev_delta - curr_delta));
59 }
60
61 void prepare_raycast(vec3 ray_origin,
62                      vec3 ray_dir,
63                      float thickness,
64                      int index,
65                      out vec4 ss_step,
66                      out vec4 ss_ray,
67                      out float max_time)
68 {
69   /* Negate the ray direction if it goes towards the camera.
70    * This way we don't need to care if the projected point
71    * is behind the near plane. */
72   float z_sign = -sign(ray_dir.z);
73   vec3 ray_end = ray_origin + z_sign * ray_dir;
74
75   /* Project into screen space. */
76   vec4 ss_start, ss_end;
77   ss_start.xyz = project_point(ProjectionMatrix, ray_origin);
78   ss_end.xyz = project_point(ProjectionMatrix, ray_end);
79
80   /* We interpolate the ray Z + thickness values to check if depth is within threshold. */
81   ray_origin.z -= thickness;
82   ray_end.z -= thickness;
83   ss_start.w = project_point(ProjectionMatrix, ray_origin).z;
84   ss_end.w = project_point(ProjectionMatrix, ray_end).z;
85
86   /* XXX This is a hack. A better method is welcome! */
87   /* We take the delta between the offseted depth and the depth and substract it from the ray
88    * depth. This will change the world space thickness appearance a bit but we can have negative
89    * values without worries. We cannot do this in viewspace because of the perspective division. */
90   ss_start.w = 2.0 * ss_start.z - ss_start.w;
91   ss_end.w = 2.0 * ss_end.z - ss_end.w;
92
93   ss_step = ss_end - ss_start;
94   max_time = length(ss_step.xyz);
95   ss_step = z_sign * ss_step / length(ss_step.xyz);
96
97   /* If the line is degenerate, make it cover at least one pixel
98    * to not have to handle zero-pixel extent as a special case later */
99   ss_step.xy += vec2((dot(ss_step.xy, ss_step.xy) < 0.00001) ? 0.001 : 0.0);
100
101   /* Make ss_step cover one pixel. */
102   ss_step /= max(abs(ss_step.x), abs(ss_step.y));
103   ss_step *= (abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y;
104
105   /* Clip to segment's end. */
106   max_time /= length(ss_step.xyz);
107
108   /* Clipping to frustum sides. */
109   max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz));
110
111   /* Convert to texture coords. Z component included
112    * since this is how it's stored in the depth buffer.
113    * 4th component how far we are on the ray */
114 #ifdef PLANAR_PROBE_RAYTRACE
115   /* Planar Reflections have X mirrored. */
116   vec2 m = (index > -1) ? vec2(-0.5, 0.5) : vec2(0.5);
117 #else
118   const vec2 m = vec2(0.5);
119 #endif
120   ss_ray = ss_start * m.xyyy + 0.5;
121   ss_step *= m.xyyy;
122
123   ss_ray.xy += m * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */
124 }
125
126 /* See times_and_deltas. */
127 #define curr_time times_and_deltas.x
128 #define prev_time times_and_deltas.y
129 #define curr_delta times_and_deltas.z
130 #define prev_delta times_and_deltas.w
131
132 // #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */
133 /* Return the hit position, and negate the z component (making it positive) if not hit occurred. */
134 /* __ray_dir__ is the ray direction premultiplied by it's maximum length */
135 vec3 raycast(int index,
136              vec3 ray_origin,
137              vec3 ray_dir,
138              float thickness,
139              float ray_jitter,
140              float trace_quality,
141              float roughness,
142              const bool discard_backface)
143 {
144   vec4 ss_step, ss_start;
145   float max_time;
146   prepare_raycast(ray_origin, ray_dir, thickness, index, ss_step, ss_start, max_time);
147
148   float max_trace_time = max(0.01, max_time - 0.01);
149
150 #ifdef GROUPED_FETCHES
151   ray_jitter *= 0.25;
152 #endif
153
154   /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */
155   vec4 times_and_deltas = vec4(0.0);
156
157   float ray_time = 0.0;
158   float depth_sample = sample_depth(ss_start.xy, index, 0.0);
159   curr_delta = depth_sample - ss_start.z;
160
161   float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4);
162   bool hit = false;
163   float iter;
164   for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) {
165     /* Minimum stride of 2 because we are using half res minmax zbuffer. */
166     float stride = max(1.0, iter * trace_quality) * 2.0;
167     float lod = log2(stride * 0.5 * trace_quality) * lod_fac;
168     ray_time += stride;
169
170     /* Save previous values. */
171     times_and_deltas.xyzw = times_and_deltas.yxwz;
172
173 #ifdef GROUPED_FETCHES
174     stride *= 4.0;
175     vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter);
176
177     vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time));
178
179     vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy;
180     vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww;
181
182     vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod);
183
184     vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw;
185     vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz);
186
187     vec4 deltas = depth_samples - ray_z;
188     /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */
189     bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0));
190     hit = any(test);
191
192     if (hit) {
193       vec2 m = vec2(1.0, 0.0); /* Mask */
194
195       vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx;
196       ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx :
197                                         ret_times_and_deltas;
198       ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx :
199                                         ret_times_and_deltas;
200       times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy +
201                                         times_and_deltas.yyww * m.yxyx :
202                                     ret_times_and_deltas;
203
204       depth_sample = depth_samples.w;
205       depth_sample = (test.z) ? depth_samples.z : depth_sample;
206       depth_sample = (test.y) ? depth_samples.y : depth_sample;
207       depth_sample = (test.x) ? depth_samples.x : depth_sample;
208     }
209     else {
210       curr_time = times.w;
211       curr_delta = deltas.w;
212     }
213 #else
214     float jit_stride = mix(2.0, stride, ray_jitter);
215
216     curr_time = min(ray_time + jit_stride, max_trace_time);
217     vec4 ss_ray = ss_start + ss_step * curr_time;
218
219     depth_sample = sample_depth(ss_ray.xy, index, lod);
220
221     float prev_w = ss_start.w + ss_step.w * prev_time;
222     curr_delta = depth_sample - ss_ray.z;
223     hit = (curr_delta <= 0.0) && (prev_w <= depth_sample);
224 #endif
225   }
226
227   if (discard_backface) {
228     /* Discard backface hits */
229     hit = hit && (prev_delta > 0.0);
230   }
231
232   /* Reject hit if background. */
233   hit = hit && (depth_sample != 1.0);
234
235   curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time;
236   ray_time = (hit) ? curr_time : ray_time;
237
238   /* Clip to frustum. */
239   ray_time = max(0.001, min(ray_time, max_time - 1.5));
240
241   vec4 ss_ray = ss_start + ss_step * ray_time;
242
243   /* Tag Z if ray failed. */
244   ss_ray.z *= (hit) ? 1.0 : -1.0;
245   return ss_ray.xyz;
246 }
247
248 float screen_border_mask(vec2 hit_co)
249 {
250   const float margin = 0.003;
251   float atten = ssrBorderFac + margin; /* Screen percentage */
252   hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co));
253
254   float screenfade = hit_co.x * hit_co.y;
255
256   return screenfade;
257 }