Panagiotis Christopoulos Charitos 5 years ago
parent
commit
2da42f3804

+ 1 - 1
shaders/Functions.glsl

@@ -531,7 +531,7 @@ Mat3 rotationFromDirection(Vec3 zAxis)
 #else
 	// http://jcgt.org/published/0006/01/01/
 	const Vec3 z = zAxis;
-	const F32 sign = (z.z >= 0) ? 1.0 : -1.0;
+	const F32 sign = (z.z >= 0.0) ? 1.0 : -1.0;
 	const F32 a = -1.0 / (sign + z.z);
 	const F32 b = z.x * z.y * a;
 

+ 15 - 3
shaders/ImportanceSampling.glsl

@@ -3,6 +3,8 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+// NOTE: To visualize some of these functions go to https://www.shadertoy.com/view/wsBBzV
+
 #pragma once
 
 #include <shaders/Common.glsl>
@@ -38,7 +40,7 @@ UVec3 rand3DPCG16(UVec3 v)
 }
 
 // Stolen from Unreal
-// It will return a uniform 2D point inside a circle. For random use rand3DPCG16()
+// It will return a uniform 2D point inside [0.0, 1.0]. For random use rand3DPCG16()
 Vec2 hammersleyRandom16(U32 sampleIdx, U32 sampleCount, UVec2 random)
 {
 	const F32 e1 = fract(F32(sampleIdx) / sampleCount + F32(random.x) * (1.0 / 65536.0));
@@ -47,11 +49,21 @@ Vec2 hammersleyRandom16(U32 sampleIdx, U32 sampleCount, UVec2 random)
 }
 
 // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
-// From a uniform 2D point inside a circle get a 3D point in a hemisphere. It's oriented in the z axis
+// From a uniform 2D point inside a circle get a 3D point in the surface of a hemisphere. It's oriented in the z axis
 Vec3 hemisphereSampleUniform(Vec2 uv)
 {
 	const F32 phi = uv.y * 2.0 * PI;
 	const F32 cosTheta = 1.0 - uv.x;
 	const F32 sinTheta = sqrt(1.0 - cosTheta * cosTheta);
-	return Vec3(cos(phi) * sinTheta, cosTheta, sin(phi) * sinTheta);
+	return Vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
+}
+
+// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
+// Same as hemisphereSampleUniform but it distributes points closer to the z axis
+Vec3 hemisphereSampleCos(Vec2 uv)
+{
+	const F32 phi = uv.y * 2.0 * PI;
+	const F32 cosTheta = sqrt(1.0 - uv.x);
+	const F32 sinTheta = sqrt(1.0 - cosTheta * cosTheta);
+	return Vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
 }

+ 4 - 3
shaders/Ssgi.ankiprog

@@ -54,6 +54,7 @@ void main()
 
 	// Get normal
 	const Vec3 worldNormal = readNormalFromGBuffer(u_gbufferRt2, u_trilinearClampSampler, uv);
+	const Vec3 viewNormal = u_unis.m_normalMat * worldNormal;
 
 	// Get depth
 	const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, uv, 0.0).r;
@@ -62,10 +63,10 @@ void main()
 	const Vec4 viewPos4 = u_unis.m_invProjMat * Vec4(UV_TO_NDC(uv), depth, 1.0);
 	const Vec3 viewPos = viewPos4.xyz / viewPos4.w;
 
-	// Get a random point inside the hemisphere
+	// Get a random point inside the hemisphere. Use hemisphereSampleCos to avoid perpendicular vecs to viewNormal
 	const UVec2 random = rand3DPCG16(UVec3(fixedInvocationId, u_unis.m_frameCount)).xy;
 	const Vec2 randomCircle = hammersleyRandom16(0, 0xFFFFu, random);
-	const Vec3 randomHemisphere = rotationFromDirection(worldNormal) * hemisphereSampleUniform(randomCircle);
+	const Vec3 randomHemisphere = rotationFromDirection(viewNormal) * hemisphereSampleCos(randomCircle);
 
 	// Trace
 	Vec3 hitPoint;
@@ -109,7 +110,7 @@ void main()
 		outColor = Vec4(0.0, 0.0, 0.0, 1.0);
 	}
 
-	const F32 NoL = dot(randomHemisphere, worldNormal);
+	const F32 NoL = saturate(dot(randomHemisphere, worldNormal));
 	outColor.xyz *= NoL;
 
 	imageStore(out_img, fixedInvocationId, outColor);

+ 5 - 0
shaders/glsl_cpp_common/Ssgi.h

@@ -20,6 +20,11 @@ struct SsgiUniforms
 	Mat4 m_invProjMat;
 	Mat4 m_projMat;
 	Mat4 m_prevViewProjMatMulInvViewProjMat;
+#ifdef __cplusplus
+	Mat3x4 m_normalMat;
+#else
+	Mat3 m_normalMat;
+#endif
 };
 
 ANKI_END_NAMESPACE

+ 1 - 0
src/anki/renderer/Ssgi.cpp

@@ -100,6 +100,7 @@ void Ssgi::run(RenderPassWorkContext& rgraphCtx)
 	unis->m_projMat = ctx.m_matrices.m_projectionJitter;
 	unis->m_prevViewProjMatMulInvViewProjMat =
 		ctx.m_prevMatrices.m_viewProjection * ctx.m_matrices.m_viewProjectionJitter.getInverse();
+	unis->m_normalMat = Mat3x4(ctx.m_matrices.m_view.getRotationPart());
 	unis->m_frameCount = m_r->getFrameCount() & MAX_U32;
 	unis->m_maxSteps = m_main.m_maxSteps;