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:
authorClément Foucault <foucault.clem@gmail.com>2017-07-18 17:48:24 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-07-24 16:28:27 +0300
commit3be8ab881ed4a085778593ccae59a6f0e1b4bffa (patch)
tree50d7ee3cf173e280746fb2faca49c477b426e357 /source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
parent19323a0ff550deea2c6ec8c945059c8927a8cedb (diff)
Eevee: SSR: Add simple raytracing.
Still imprecise.
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl162
1 files changed, 162 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..6f6ced3c668
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -0,0 +1,162 @@
+/* Based on work from Morgan McGuire and Michael Mara at Williams College 2014
+ * Released as open source under the BSD 2-Clause License
+ * http://opensource.org/licenses/BSD-2-Clause
+ * http://casual-effects.blogspot.fr/2014/08/screen-space-ray-tracing.html */
+
+#define MAX_STEP 256
+
+uniform mat4 PixelProjMatrix; /* View > NDC > Texel : maps view coords to texel coord */
+
+void swapIfBigger(inout float a, inout float b)
+{
+ if (a > b) {
+ float temp = a;
+ a = b;
+ b = temp;
+ }
+}
+
+/* Return the length of the ray if there is a hit, and -1.0 if not hit occured */
+float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir)
+{
+ float near = get_view_z_from_depth(0.0); /* TODO optimize */
+
+ /* Clip ray to a near plane in 3D */
+ float ray_length = 1e16;
+ if ((ray_origin.z + ray_dir.z * ray_length) > near)
+ ray_length = (near - ray_origin.z) / ray_dir.z;
+
+ vec3 ray_end = ray_dir * ray_length + ray_origin;
+
+ /* Project into screen space */
+ vec4 H0 = PixelProjMatrix * vec4(ray_origin, 1.0);
+ vec4 H1 = PixelProjMatrix * vec4(ray_end, 1.0);
+
+ /* There are a lot of divisions by w that can be turned into multiplications
+ * at some minor precision loss...and we need to interpolate these 1/w values
+ * anyway. */
+ float k0 = 1.0 / H0.w;
+ float k1 = 1.0 / H1.w;
+
+ /* Switch the original points to values that interpolate linearly in 2D */
+ vec3 Q0 = ray_origin * k0;
+ vec3 Q1 = ray_end * k1;
+
+ /* Screen-space endpoints */
+ vec2 P0 = H0.xy * k0;
+ vec2 P1 = H1.xy * k1;
+
+ /* [Optional clipping to frustum sides here] */
+
+ /* Initialize to off screen */
+ vec2 hitpixel = vec2(-1.0, -1.0);
+
+ /* 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 */
+ P1 += vec2((distance_squared(P0, P1) < 0.0001) ? 0.01 : 0.0);
+
+ vec2 delta = P1 - P0;
+
+ /* Permute so that the primary iteration is in x to reduce large branches later.
+ * After this, "x" is the primary iteration direction and "y" is the secondary one
+ * If it is a more-vertical line, create a permutation that swaps x and y in the output
+ * and directly swizzle the inputs. */
+ bool permute = false;
+ if (abs(delta.x) < abs(delta.y)) {
+ permute = true;
+ delta = delta.yx;
+ P1 = P1.yx;
+ P0 = P0.yx;
+ }
+
+ /* Track the derivatives */
+ float step_sign = sign(delta.x);
+ float invdx = step_sign / delta.x;
+ vec2 dP = vec2(step_sign, invdx * delta.y);
+ vec3 dQ = (Q1 - Q0) * invdx;
+ float dk = (k1 - k0) * invdx;
+
+ /* Slide each value from the start of the ray to the end */
+ vec4 pqk = vec4(P0, Q0.z, k0);
+
+ /* Scale derivatives by the desired pixel stride */
+ vec4 dPQK = vec4(dP, dQ.z, dk) * 4.0;
+
+ /* We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid
+ * voxels. Because the depth at -1/2 for a given pixel will be the same as at
+ * +1/2 for the previous iteration, we actually only have to compute one value
+ * per iteration. */
+ float prev_zmax = ray_origin.z;
+ float zmax, zmin;
+
+ /* P1.x is never modified after this point, so pre-scale it by
+ * the step direction for a signed comparison */
+ float end = P1.x * step_sign;
+
+ bool hit = false;
+ float hitstep, refinestep, raw_depth, view_depth;
+ for (hitstep = 0.0; hitstep < MAX_STEP && !hit; hitstep++) {
+ /* Ray finished & no hit*/
+ if ((pqk.x * step_sign) > end) break;
+
+ /* step through current cell */
+ pqk += dPQK;
+
+ hitpixel = permute ? pqk.yx : pqk.xy;
+ zmin = prev_zmax;
+ zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
+ prev_zmax = zmax;
+ swapIfBigger(zmin, zmax);
+
+ raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r;
+ view_depth = get_view_z_from_depth(raw_depth);
+
+ if (zmax < view_depth) {
+ /* Below surface, cannot trace further */
+ hit = true;
+ }
+ }
+
+ if (hit) {
+ /* Rewind back a step */
+ pqk -= dPQK;
+
+ /* And do a finer trace over this segment */
+ dPQK /= 4.0;
+
+ for (refinestep = 0.0; refinestep < 4.0; refinestep++) {
+ /* step through current cell */
+ pqk += dPQK;
+
+ hitpixel = permute ? pqk.yx : pqk.xy;
+ zmin = prev_zmax;
+ zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
+ prev_zmax = zmax;
+ swapIfBigger(zmin, zmax);
+
+ raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r;
+ view_depth = get_view_z_from_depth(raw_depth);
+
+ if (zmax < view_depth) {
+ /* Below surface, cannot trace further */
+ break;
+ }
+ }
+ }
+
+ /* Check if we are somewhere near the surface. */
+ /* TODO user threshold */
+ float threshold = 0.05 / pqk.w; /* In view space */
+ if (zmax < (view_depth - threshold)) {
+ hit = false;
+ }
+
+ /* Check failure cases (out of screen, hit background) */
+ if (hit && (raw_depth != 1.0) && (raw_depth != 0.0)) {
+ /* Return length */
+ return (zmax - ray_origin.z) / ray_dir.z;
+ }
+
+ /* Failure, return no hit */
+ return -1.0;
+}