Kaynağa Gözat

Add another method to compute the reflection vector based on roughness

Panagiotis Christopoulos Charitos 1 yıl önce
ebeveyn
işleme
f6744889bb
1 değiştirilmiş dosya ile 62 ekleme ve 0 silme
  1. 62 0
      AnKi/Shaders/LightFunctions.hlsl

+ 62 - 0
AnKi/Shaders/LightFunctions.hlsl

@@ -618,6 +618,41 @@ Vec3 sampleGgxVndf(Vec3 v, F32 alphaX, F32 alphaY, F32 u1, F32 u2)
 	return nE;
 }
 
+// Same thing as sampleGgxVndf but it works in world space and not in TBN
+// https://auzaiffe.wordpress.com/2024/04/15/vndf-importance-sampling-an-isotropic-distribution/
+// viewDir is camPos-worldPos
+Vec3 sampleVndfIsotropic(Vec2 randFactors, Vec3 viewDir, F32 alpha, Vec3 normal)
+{
+	// decompose the floattor in parallel and perpendicular components
+	const Vec3 viewDirZ = -normal * dot(viewDir, normal);
+	const Vec3 viewDirXY = viewDir + viewDirZ;
+
+	// warp to the hemisphere configuration
+	const Vec3 wiStd = -normalize(alpha * viewDirXY + viewDirZ);
+
+	// sample a spherical cap in (-wiStd.z, 1]
+	const F32 wiStdZ = dot(wiStd, normal);
+	const F32 z = 1.0 - randFactors.y * (1.0 + wiStdZ);
+	const F32 sinTheta = sqrt(saturate(1.0 - z * z));
+	const F32 phi = 2.0 * kPi * randFactors.x - kPi;
+	const F32 x = sinTheta * cos(phi);
+	const F32 y = sinTheta * sin(phi);
+	const Vec3 cStd = Vec3(x, y, z);
+
+	// reflect sample to align with normal
+	const Vec3 up = Vec3(0, 0, 1.000001); // Used for the singularity
+	const Vec3 wr = normal + up;
+	const Vec3 c = dot(wr, cStd) * wr / wr.z - cStd;
+
+	// compute halfway direction as standard normal
+	const Vec3 wmStd = c + wiStd;
+	const Vec3 wmStdZ = normal * dot(normal, wmStd);
+	const Vec3 wmStdXY = wmStdZ - wmStd;
+
+	// return final normal
+	return normalize(alpha * wmStdXY + wmStdZ);
+}
+
 /// Calculate the reflection vector based on roughness. Sometimes the refl vector is bellow the normal so this func will try again with a new one.
 /// viewDir is camPos-worldPos
 Vec3 sampleReflectionVector(Vec3 viewDir, Vec3 normal, F32 roughness, Vec2 randFactors, U32 tryCount)
@@ -653,6 +688,33 @@ Vec3 sampleReflectionVector(Vec3 viewDir, Vec3 normal, F32 roughness, Vec2 randF
 	return r;
 }
 
+// Another version of sampleReflectionVector. Possibly faster
+Vec3 sampleReflectionVector2(Vec3 viewDir, Vec3 normal, F32 roughness, Vec2 randFactors, U32 tryCount)
+{
+	const F32 alpha = roughness * roughness;
+
+	Vec3 reflDir = normal;
+	do
+	{
+		reflDir = sampleVndfIsotropic(randFactors, viewDir, alpha, normal);
+		reflDir = reflect(-viewDir, reflDir);
+
+		if(dot(reflDir, normal) > cos(kPi / 2.0 * 0.9))
+		{
+			// Angle between the refl vec and the normal is less than 90 degr. We are good to go
+			break;
+		}
+		else
+		{
+			// Try again
+			randFactors.x = frac(randFactors.x + 0.7324);
+			randFactors.y = frac(randFactors.y + 0.6523);
+		}
+	} while(--tryCount);
+
+	return reflDir;
+}
+
 /// Get the index of the cascade given the distance from zero.
 U32 computeShadowCascadeIndex(F32 distance, Vec4 cascadeDistances, U32 shadowCascadeCount)
 {