|
|
@@ -8,8 +8,10 @@ http://www.anki3d.org/LICENSE
|
|
|
<shaders>
|
|
|
<shader type="comp">
|
|
|
<inputs>
|
|
|
- <input name="INPUT_TEX_SIZE" type="uvec2" const="1"/>
|
|
|
+ <input name="FB_SIZE" type="uvec2" const="1"/>
|
|
|
<input name="WORKGROUP_SIZE" type="uvec2" const="1"/>
|
|
|
+ <input name="MAX_STEPS" type="uint" const="1"/>
|
|
|
+ <input name="LIGHT_BUFFER_MIP_COUNT" type="uint" const="1"/>
|
|
|
</inputs>
|
|
|
|
|
|
<source><![CDATA[
|
|
|
@@ -30,117 +32,142 @@ layout(ANKI_UBO_BINDING(0, 0), std140, row_major) uniform u0_
|
|
|
mat4 u_prevViewProjMatMulInvViewProjMat;
|
|
|
};
|
|
|
|
|
|
-const float ONE = 0.9;
|
|
|
-
|
|
|
-// Returns the Z of the position in view space
|
|
|
-float readZ(in vec2 uv)
|
|
|
+// http://paulbourke.net/geometry/pointlineplane/
|
|
|
+// Line segment A is p1, p2. Line segment B is p3, p4
|
|
|
+vec3 lineSegmentsIntersection(vec3 p1, vec3 p2, vec3 p3, vec3 p4)
|
|
|
{
|
|
|
- float depth = textureLod(u_depthRt, uv, 1.0).r;
|
|
|
- float z = u_projectionParams.z / (u_projectionParams.w + depth);
|
|
|
- return z;
|
|
|
-}
|
|
|
+ vec3 p13 = p1 - p3;
|
|
|
+ vec3 p43 = p4 - p3;
|
|
|
|
|
|
-vec2 projectXy(in vec3 p)
|
|
|
-{
|
|
|
- vec4 a = u_projectionMat * vec4(p, 1.0);
|
|
|
- return a.xy / a.w;
|
|
|
+ float d1343 = dot(p13, p43);
|
|
|
+ float d4321 = dot(p43, p21);
|
|
|
+ float d1321 = dot(p13, p21);
|
|
|
+ float d4343 = dot(p43, p43);
|
|
|
+ float d2121 = dot(p21, p21);
|
|
|
+
|
|
|
+ float denom = d2121 * d4343 - d4321 * d4321;
|
|
|
+ if(denom == 0.0)
|
|
|
+ {
|
|
|
+ denom = EPSILON;
|
|
|
+ }
|
|
|
+
|
|
|
+ float numer = d1343 * d4321 - d1321 * d4343;
|
|
|
+
|
|
|
+ float mua = numer / denom;
|
|
|
+
|
|
|
+ vec3 result = p1 + mua * p21;
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
-vec3 doSslr(vec3 r, vec3 posVSpace, vec2 uv, out float contribution)
|
|
|
+vec3 doSslr(vec3 r, vec3 worldPos, vec2 uv, out float contribution)
|
|
|
{
|
|
|
- vec3 color = vec3(0.0);
|
|
|
- vec3 p0 = posVSpace;
|
|
|
- contribution = 1.0;
|
|
|
-
|
|
|
- // Let p1 be the intersection of p0+r to the near plane, then
|
|
|
- // p1 = p0 + t*r or
|
|
|
- // p1.x = p0.x + t*r.x (1)
|
|
|
- // p1.y = p0.y + t*r.y (2) and
|
|
|
- // p1.z = p0.z + t*r.z (3)
|
|
|
- // p1.z is known to be something ~0.0 so if we solve (3) t becomes:
|
|
|
- float t = -p0.z / (r.z + 0.0000001);
|
|
|
- vec3 p1 = p0 + r * t;
|
|
|
-
|
|
|
- vec2 pp0 = uv * 2.0 - 1.0;
|
|
|
- vec2 pp1 = projectXy(p1);
|
|
|
-
|
|
|
- // Calculate the ray from p0 to p1 in 2D space and get the number of steps
|
|
|
- vec2 dir = pp1 - pp0;
|
|
|
- vec2 path = dir * 0.5; // (pp1/2+1/2)-(pp0.xy/2+1/2)
|
|
|
- path *= vec2(float(WIDTH), float(HEIGHT));
|
|
|
- path = abs(path);
|
|
|
- float steps = max(path.x, path.y);
|
|
|
-
|
|
|
- // Calculate the step increase
|
|
|
- float len = length(dir);
|
|
|
- float stepInc = len / steps;
|
|
|
- dir /= len; // Normalize dir at last
|
|
|
-
|
|
|
- steps = min(steps, 300.0);
|
|
|
-
|
|
|
- for(float i = 0.0; i < steps; i += 1.0)
|
|
|
+ vec3 p0 = worldPos;
|
|
|
+ contribution = 0.0;
|
|
|
+
|
|
|
+ // Compute an end point p1 that is p1 = p0 + t*r. p1 will lie in the near plane.
|
|
|
+ // The code is the same used to compute the intersection of a ray to a plane.
|
|
|
+ // NOTE: The nearPlane is a bit in front of the real near plane. We do that to be able to project p1 without
|
|
|
+ // problems
|
|
|
+ vec3 p1;
|
|
|
{
|
|
|
- vec2 ndc = pp0 + dir * (i * stepInc);
|
|
|
+ float d = dot(nearPlane.xyz, p0) - nearPlane.w;
|
|
|
+ float a = dot(nearPlane.xyz, r);
|
|
|
+
|
|
|
+ float s;
|
|
|
+ if(d > 0.0 && a < 0.0)
|
|
|
+ {
|
|
|
+ // We have intersection, compute the intersection point
|
|
|
+ s = -d / a;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // No intersection, create a correct point
|
|
|
+ s = 1000.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ p1 = p0 + s * r;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Project the starting and end points
|
|
|
+ vec2 start = uv;
|
|
|
+ vec4 end4 = u_viewProjMat * vec4(p1, 1.0);
|
|
|
+ vec2 end = NDC_TO_UV(end4.xy / end4.w);
|
|
|
+
|
|
|
+ // Compute the step size
|
|
|
+ vec2 dir = end - start;
|
|
|
+ float stepSize = max(dir.x, dir.y);
|
|
|
+ dir = normalize(dir);
|
|
|
+
|
|
|
+ // Iterate
|
|
|
+ for(float i = 1.0; i < float(MAX_STEPS); i += 1.0)
|
|
|
+ {
|
|
|
+ vec2 newUv = start + dir * (i * stepSize);
|
|
|
|
|
|
// Check if it's out of the view
|
|
|
- vec2 comp = abs(ndc);
|
|
|
- if(comp.x > ONE || comp.y > ONE)
|
|
|
+ if(newUv.x < 0.0 || newUv.y < 0.0 || newUv.x > 1.0 || newUv.y > 1.0)
|
|
|
{
|
|
|
- //color = vec3(1, 0.0, 1);
|
|
|
- return color;
|
|
|
+ return vec3(0.0);
|
|
|
}
|
|
|
|
|
|
+ vec2 ndc = UV_TO_NDC(newUv);
|
|
|
+
|
|
|
// 'a' is ray that passes through the eye and into ndc
|
|
|
- vec3 a;
|
|
|
- a.z = -1.0;
|
|
|
- a.xy = ndc * u_projectionParams.xy * a.z; // Unproject
|
|
|
- a = normalize(a);
|
|
|
-
|
|
|
- // Compute the intersection between 'a' (before normalization) and r
|
|
|
- // 'k' is the value to multiply to 'a' to get the intersection
|
|
|
- // c0 = cross(a, r);
|
|
|
- // c1 = cross(p0, r);
|
|
|
- // k = c1.x / c0.x; and the optimized:
|
|
|
- vec2 tmpv2 = a.yz * r.zy;
|
|
|
- float c0x = tmpv2.x - tmpv2.y;
|
|
|
- tmpv2 = p0.yz * r.zy;
|
|
|
- float c1x = tmpv2.x - tmpv2.y;
|
|
|
- float k = c1x / c0x;
|
|
|
-
|
|
|
- float intersectionZ = a.z * k; // intersectionXYZ = a * k;
|
|
|
-
|
|
|
- vec2 texCoord = ndc * 0.5 + 0.5;
|
|
|
- float depth = readZ(u_depthRt, texCoord);
|
|
|
-
|
|
|
- float diffDepth = depth - intersectionZ;
|
|
|
-
|
|
|
- if(diffDepth > 0.0)
|
|
|
- {
|
|
|
- if(diffDepth > 0.7)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ vec4 a4 = u_invViewProjMat * vec4(ndc, 1.0, 1.0);
|
|
|
+ vec3 a = a4.xyz / a4.w;
|
|
|
+
|
|
|
+ // Compute the intersection between line segment (camera_pos, a) and line segment (p0, p1)
|
|
|
+ vec3 intersection = lineSegmentsIntersection(u_camPos, a, p0, p1);
|
|
|
+
|
|
|
+ // Project the intersection
|
|
|
+ vec4 intersection4 = u_viewProjMat * vec4(intersection, 1.0);
|
|
|
+ float intersectionDepth = intersection4.z / intersection4.w;
|
|
|
|
|
|
- float factor = sin(length(ndc) * PI);
|
|
|
- factor *= 1.0 - length(pp0);
|
|
|
- //factor *= specColor;
|
|
|
+ // Read depth
|
|
|
+ float depth = textureLod(u_depthRt, newUv, 0.0).r;
|
|
|
|
|
|
- color = textureLod(u_isRt, texCoord, 0.0).rgb * factor;
|
|
|
+ // Compare depths
|
|
|
+ float diffDepth = depth - intersectionDepth;
|
|
|
|
|
|
- //color = vec3(1.0, 0.0, 1.0);
|
|
|
- //color = vec3(1.0 - abs(pp0.xy), 0.0);
|
|
|
+ if(diffDepth > EPSILON)
|
|
|
+ {
|
|
|
+ contribution = sin(length(ndc) * PI);
|
|
|
+
|
|
|
+ float roughness;
|
|
|
+ vec3 specular;
|
|
|
+ readRoughnessSpecularFromGBuffer(u_gbufferRt1, newUv, roughness, specular);
|
|
|
+
|
|
|
+ float lod = float(LIGHT_BUFFER_MIP_COUNT - 1u) * roughness;
|
|
|
+ vec3 color = textureLod(u_lightBufferRt, newUv, lod).rgb;
|
|
|
return color;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return color;
|
|
|
+ return vec3(0.0);
|
|
|
}
|
|
|
|
|
|
void main()
|
|
|
{
|
|
|
- vec2 uv = vec2(gl_GlobalInvocationID.xy) / vec2(INPUT_TEX_SIZE);
|
|
|
+ vec2 uv = vec2(gl_GlobalInvocationID.xy) / vec2(FB_SIZE);
|
|
|
+
|
|
|
+ // Get normal
|
|
|
+ vec3 normal;
|
|
|
+ readNormalFromGBuffer(u_gbufferRt2, uv, normal);
|
|
|
+
|
|
|
+ // Get world pos
|
|
|
+ float depth = textureLod(u_depthRt, uv, 0.0).r;
|
|
|
+ vec4 worldPos4 = u_invViewProjMat * vec4(UV_TO_NDC(uv), depth, 1.0);
|
|
|
+ vec3 worldPos = worldPos4.xyz / worldPos4.w;
|
|
|
+
|
|
|
+ // Compute reflection vec
|
|
|
+ vec4 viewDir = normalize(worldPos - u_camPos);
|
|
|
+ vec3 refl = reflect(viewDir, normal);
|
|
|
+
|
|
|
+ // Do SSLR
|
|
|
+ float sslrFactor;
|
|
|
+ vec3 sslrCol = doSslr(r, worldPos, uv, sslrFactor);
|
|
|
|
|
|
- doSslr();
|
|
|
+ // Write it
|
|
|
+ imageStore(u_out, gl_GlobalInvocationID.xy, vec4(sslrCol, 0.0));
|
|
|
}
|
|
|
]]></source>
|
|
|
</shader>
|