Kaynağa Gözat

[FEATURE] Some work on SSLR

Panagiotis Christopoulos Charitos 8 yıl önce
ebeveyn
işleme
127d6415f3
1 değiştirilmiş dosya ile 115 ekleme ve 88 silme
  1. 115 88
      programs/Reflections.ankiprog

+ 115 - 88
programs/Reflections.ankiprog

@@ -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>