Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl234
1 files changed, 234 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
new file mode 100644
index 00000000000..cb75731b7da
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -0,0 +1,234 @@
+#define MAX_STEP 256
+
+float sample_depth(vec2 uv, int index, float lod)
+{
+#ifdef PLANAR_PROBE_RAYTRACE
+ if (index > -1) {
+ return textureLod(planarDepth, vec3(uv, index), 0.0).r;
+ }
+ else {
+#endif
+ /* Correct UVs for mipmaping mis-alignment */
+ uv *= mipRatio[int(lod + 1.0)];
+ return textureLod(maxzBuffer, uv, lod).r;
+#ifdef PLANAR_PROBE_RAYTRACE
+ }
+#endif
+}
+
+vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod)
+{
+ vec4 depths;
+#ifdef PLANAR_PROBE_RAYTRACE
+ if (index > -1) {
+ depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r;
+ depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r;
+ depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r;
+ depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r;
+ }
+ else {
+#endif
+ depths.x = textureLod(maxzBuffer, uv1.xy, lod).r;
+ depths.y = textureLod(maxzBuffer, uv1.zw, lod).r;
+ depths.z = textureLod(maxzBuffer, uv2.xy, lod).r;
+ depths.w = textureLod(maxzBuffer, uv2.zw, lod).r;
+#ifdef PLANAR_PROBE_RAYTRACE
+ }
+#endif
+ return depths;
+}
+
+float refine_isect(float prev_delta, float curr_delta)
+{
+ /**
+ * Simplification of 2D intersection :
+ * r0 = (0.0, prev_ss_ray.z);
+ * r1 = (1.0, curr_ss_ray.z);
+ * d0 = (0.0, prev_hit_depth_sample);
+ * d1 = (1.0, curr_hit_depth_sample);
+ * vec2 r = r1 - r0;
+ * vec2 d = d1 - d0;
+ * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d);
+ *
+ * We only want isect.x to know how much stride we need. So it simplifies :
+ *
+ * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d);
+ * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d);
+ */
+ return saturate(prev_delta / (prev_delta - curr_delta));
+}
+
+void prepare_raycast(vec3 ray_origin, vec3 ray_end, float thickness, out vec4 ss_step, out vec4 ss_ray, out float max_time)
+{
+ /* Negate the ray direction if it goes towards the camera.
+ * This way we don't need to care if the projected point
+ * is behind the near plane. */
+ float z_sign = -sign(ray_end.z);
+ ray_end = z_sign * ray_end + ray_origin;
+
+ /* Project into screen space. */
+ vec4 ss_start, ss_end;
+ ss_start.xyz = project_point(ProjectionMatrix, ray_origin);
+ ss_end.xyz = project_point(ProjectionMatrix, ray_end);
+
+ /* We interpolate the ray Z + thickness values to check if depth is within threshold. */
+ ray_origin.z -= thickness;
+ ray_end.z -= thickness;
+ ss_start.w = project_point(ProjectionMatrix, ray_origin).z;
+ ss_end.w = project_point(ProjectionMatrix, ray_end).z;
+
+ /* XXX This is a hack a better method is welcome ! */
+ /* We take the delta between the offseted depth and the depth and substract it from the ray depth.
+ * This will change the world space thickness appearance a bit but we can have negative
+ * values without worries. We cannot do this in viewspace because of the perspective division. */
+ ss_start.w = 2.0 * ss_start.z - ss_start.w;
+ ss_end.w = 2.0 * ss_end.z - ss_end.w;
+
+ ss_step = ss_end - ss_start;
+ max_time = length(ss_step.xyz);
+ ss_step = z_sign * ss_step / length(ss_step.xyz);
+
+ /* If the line is degenerate, make it cover at least one pixel
+ * to not have to handle zero-pixel extent as a special case later */
+ ss_step.xy += vec2((dot(ss_step.xy, ss_step.xy) < 0.000001) ? 0.001 : 0.0);
+
+ /* Make ss_step cover one pixel. */
+ ss_step /= max(abs(ss_step.x), abs(ss_step.y));
+ ss_step *= ((abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y);
+
+ /* Clip to segment's end. */
+ max_time /= length(ss_step.xyz);
+
+ /* Clipping to frustum sides. */
+ max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz));
+
+ /* Convert to texture coords. Z component included
+ * since this is how it's stored in the depth buffer.
+ * 4th component how far we are on the ray */
+ ss_ray = ss_start * 0.5 + 0.5;
+ ss_step *= 0.5;
+}
+
+/* See times_and_deltas. */
+#define curr_time times_and_deltas.x
+#define prev_time times_and_deltas.y
+#define curr_delta times_and_deltas.z
+#define prev_delta times_and_deltas.w
+
+// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */
+/* Return the hit position, and negate the z component (making it positive) if not hit occured. */
+/* __ray_end__ is the ray direction premultiplied by it's maximum length */
+vec3 raycast(
+ int index, vec3 ray_origin, vec3 ray_end, float thickness, float ray_jitter,
+ float trace_quality, float roughness, const bool discard_backface)
+{
+ vec4 ss_step, ss_start;
+ float max_time;
+ prepare_raycast(ray_origin, ray_end, thickness, ss_step, ss_start, max_time);
+
+ float max_trace_time = max(0.001, max_time - 0.01);
+
+#ifdef GROUPED_FETCHES
+ ray_jitter *= 0.25;
+#endif
+
+ /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */
+ vec4 times_and_deltas = vec4(0.0);
+
+ float ray_time = 0.0;
+ float depth_sample = sample_depth(ss_start.xy, index, 0.0);
+ curr_delta = depth_sample - ss_start.z;
+
+ float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4);
+ bool hit = false;
+ float iter;
+ for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) {
+ /* Minimum stride of 2 because we are using half res minmax zbuffer. */
+ float stride = max(1.0, iter * trace_quality) * 2.0;
+ float lod = log2(stride * 0.5 * trace_quality) * lod_fac;
+ ray_time += stride;
+
+ /* Save previous values. */
+ times_and_deltas.xyzw = times_and_deltas.yxwz;
+
+#ifdef GROUPED_FETCHES
+ stride *= 4.0;
+ vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter);
+
+ vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time));
+
+ vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy;
+ vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww;
+
+ vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod);
+
+ vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw;
+ vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz);
+
+ vec4 deltas = depth_samples - ray_z;
+ /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */
+ bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0));
+ hit = any(test);
+
+ if (hit) {
+ vec2 m = vec2(1.0, 0.0); /* Mask */
+
+ vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx;
+ ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx : ret_times_and_deltas;
+ ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx : ret_times_and_deltas;
+ times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy + times_and_deltas.yyww * m.yxyx : ret_times_and_deltas;
+
+ depth_sample = depth_samples.w;
+ depth_sample = (test.z) ? depth_samples.z : depth_sample;
+ depth_sample = (test.y) ? depth_samples.y : depth_sample;
+ depth_sample = (test.x) ? depth_samples.x : depth_sample;
+ }
+ else {
+ curr_time = times.w;
+ curr_delta = deltas.w;
+ }
+#else
+ float jit_stride = mix(2.0, stride, ray_jitter);
+
+ curr_time = min(ray_time + jit_stride, max_trace_time);
+ vec4 ss_ray = ss_start + ss_step * curr_time;
+
+ depth_sample = sample_depth(ss_ray.xy, index, lod);
+
+ float prev_w = ss_start.w + ss_step.w * prev_time;
+ curr_delta = depth_sample - ss_ray.z;
+ hit = (curr_delta <= 0.0) && (prev_w <= depth_sample);
+#endif
+ }
+
+ if (discard_backface) {
+ /* Discard backface hits */
+ hit = hit && (prev_delta > 0.0);
+ }
+
+ /* Reject hit if background. */
+ hit = hit && (depth_sample != 1.0);
+
+ curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time;
+ ray_time = (hit) ? curr_time : ray_time;
+
+ /* Clip to frustum. */
+ ray_time = max(0.001, min(ray_time, max_time - 1.5));
+
+ vec4 ss_ray = ss_start + ss_step * ray_time;
+
+ /* Tag Z if ray failed. */
+ ss_ray.z *= (hit) ? 1.0 : -1.0;
+ return ss_ray.xyz;
+}
+
+float screen_border_mask(vec2 hit_co)
+{
+ const float margin = 0.003;
+ float atten = ssrBorderFac + margin; /* Screen percentage */
+ hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co));
+
+ float screenfade = hit_co.x * hit_co.y;
+
+ return screenfade;
+}