Prechádzať zdrojové kódy

Renderer: Optimize and correct volumetric shader

Panagiotis Christopoulos Charitos 9 rokov pred
rodič
commit
66486287d3

+ 1 - 1
bled/Main.cpp

@@ -34,7 +34,7 @@ Error MyApp::init()
 	MainRenderer& renderer = app->getMainRenderer();
 	ResourceManager& resources = app->getResourceManager();
 
-	renderer.getOffscreenRenderer().getVolumetric().setFog(
+	renderer.getOffscreenRenderer().getVolumetric().setFogParticleColor(
 		Vec3(1.0, 0.9, 0.9), 0.7);
 	if(getenv("PROFILE"))
 	{

+ 1 - 1
samples/simple_scene/Main.cpp

@@ -33,7 +33,7 @@ Error MyApp::init(int argc, char** argv)
 	getInput().moveCursor(Vec2(0.0));
 
 	// Some renderer stuff
-	getMainRenderer().getOffscreenRenderer().getVolumetric().setFog(Vec3(1.0, 0.9, 0.9), 0.7);
+	getMainRenderer().getOffscreenRenderer().getVolumetric().setFogParticleColor(Vec3(1.0, 0.9, 0.9) * 0.0001);
 
 	return ErrorCode::NONE;
 }

+ 1 - 1
sandbox/Main.cpp

@@ -44,7 +44,7 @@ Error MyApp::init(int argc, char* argv[])
 	MainRenderer& renderer = getMainRenderer();
 	ResourceManager& resources = getResourceManager();
 
-	renderer.getOffscreenRenderer().getVolumetric().setFog(Vec3(1.0, 0.9, 0.9), 0.7);
+	renderer.getOffscreenRenderer().getVolumetric().setFogParticleColor(Vec3(1.0, 0.9, 0.9) * 0.009);
 
 	if(getenv("PROFILE"))
 	{

+ 70 - 82
shaders/Volumetric.frag.glsl

@@ -21,150 +21,138 @@ layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2DArray u_noiseTex;
 layout(std140, ANKI_UBO_BINDING(0, 3)) uniform ubo0_
 {
 	vec4 u_linearizeNoiseTexOffsetLayer;
-	vec4 u_fogColorFogFactor;
+	vec4 u_fogParticleColorPad1;
 };
 
 #define u_linearize u_linearizeNoiseTexOffsetLayer.xy
 #define u_noiseYOffset u_linearizeNoiseTexOffsetLayer.z
 #define u_noiseLayer u_linearizeNoiseTexOffsetLayer.w
+#define u_fogParticleColor u_fogParticleColorPad1.rgb
 
 layout(location = 0) out vec4 out_color;
 
 #define ENABLE_SHADOWS 1
 const uint MAX_SAMPLES_PER_CLUSTER = 4u;
+const float DIST_BETWEEN_SAMPLES = 0.25;
 
 // Return the diffuse color without taking into account the diffuse term of the particles.
-vec3 computeLightColor(vec3 fragPos[MAX_SAMPLES_PER_CLUSTER], uint iterCount, uint clusterIdx)
+vec3 computeLightColor(vec3 fragPos, uint plightCount, uint plightIdx, uint slightCount, uint slightIdx)
 {
 	vec3 outColor = vec3(0.0);
 
-	uint idxOffset = u_clusters[clusterIdx];
-
-	// Skip decals
-	uint count = u_lightIndices[idxOffset];
-	idxOffset += count + 1;
-
 	// Point lights
-	count = u_lightIndices[idxOffset++];
-	while(count-- != 0)
+	while(plightCount-- != 0)
 	{
-		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
-
-		for(uint i = 0; i < iterCount; ++i)
-		{
-			vec3 frag2Light = light.posRadius.xyz - fragPos[i];
-			float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
+		PointLight light = u_pointLights[u_lightIndices[plightIdx++]];
+		vec3 frag2Light = light.posRadius.xyz - fragPos;
+		float factor = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-			float shadow = 1.0;
 #if ENABLE_SHADOWS
-			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-			if(light.diffuseColorShadowmapId.w >= 0.0)
-			{
-				shadow = computeShadowFactorOmni(frag2Light,
-					shadowmapLayerIdx,
-					-1.0 / light.posRadius.w,
-					u_lightingUniforms.invViewRotation,
-					u_omniMapArr);
-			}
+		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+		if(light.diffuseColorShadowmapId.w >= 0.0)
+		{
+			factor *= computeShadowFactorOmni(frag2Light,
+				shadowmapLayerIdx,
+				-1.0 / light.posRadius.w,
+				u_lightingUniforms.invViewRotation,
+				u_omniMapArr);
+		}
 #endif
 
-			outColor += light.diffuseColorShadowmapId.rgb * (att * shadow);
-		}
+		outColor += light.diffuseColorShadowmapId.rgb * factor;
 	}
 
 	// Spot lights
-	count = u_lightIndices[idxOffset++];
-	while(count-- != 0)
+	while(slightCount-- != 0)
 	{
-		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
-
-		for(uint i = 0; i < iterCount; ++i)
-		{
-			vec3 frag2Light = light.posRadius.xyz - fragPos[i];
-			float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
+		SpotLight light = u_spotLights[u_lightIndices[slightIdx++]];
+		vec3 frag2Light = light.posRadius.xyz - fragPos;
+		float factor = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-			vec3 l = normalize(frag2Light);
+		vec3 l = normalize(frag2Light);
 
-			float spot = computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
+		factor *= computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
 
-			float shadow = 1.0;
 #if ENABLE_SHADOWS
-			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-			if(shadowmapLayerIdx >= 0.0)
-			{
-				shadow =
-					computeShadowFactorSpot(light.texProjectionMat, fragPos[i], shadowmapLayerIdx, 1, u_spotMapArr);
-			}
+		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+		if(shadowmapLayerIdx >= 0.0)
+		{
+			factor *= computeShadowFactorSpot(light.texProjectionMat, fragPos, shadowmapLayerIdx, 1, u_spotMapArr);
+		}
 #endif
 
-			outColor += light.diffuseColorShadowmapId.rgb * (att * spot * shadow);
-		}
+		outColor += light.diffuseColorShadowmapId.rgb * factor;
 	}
 
 	return outColor;
 }
 
-vec3 fog(in float depth)
-{
-	float linearDepth = linearizeDepthOptimal(depth, u_linearize.x, u_linearize.y);
-	float t = linearDepth * u_fogColorFogFactor.w;
-	return u_fogColorFogFactor.rgb * t;
-}
-
 void main()
 {
 	float depth = textureLod(u_msDepthRt, in_uv, 0.0).r;
 	float farZ = u_lightingUniforms.projectionParams.z / (u_lightingUniforms.projectionParams.w + depth);
 
-	// Compute the max cluster
-	uint maxK = computeClusterKSafe(u_lightingUniforms.nearFarClustererMagicPad1.x,
-		u_lightingUniforms.nearFarClustererMagicPad1.y,
-		u_lightingUniforms.nearFarClustererMagicPad1.z,
-		farZ);
-	++maxK;
-
 	vec2 ndc = in_uv * 2.0 - 1.0;
 
-	uint i = uint(in_uv.x * CLUSTER_COUNT.x);
-	uint j = uint(in_uv.y * CLUSTER_COUNT.y);
+	uint i = uint(in_uv.x * float(CLUSTER_COUNT.x));
+	uint j = uint(in_uv.y * float(CLUSTER_COUNT.y));
+	uint ij = j * CLUSTER_COUNT.x + i;
 
-	const float DIST = 1.0 / float(MAX_SAMPLES_PER_CLUSTER);
 	vec3 noiseTexUv = vec3(vec2(FB_SIZE) / vec2(NOISE_MAP_SIZE) * in_uv + vec2(0.0, u_noiseYOffset), u_noiseLayer);
-	float randFactor = texture(u_noiseTex, noiseTexUv).r;
-	float start = DIST * randFactor;
-	float factors[MAX_SAMPLES_PER_CLUSTER] = float[](start, DIST + start, 2.0 * DIST + start, 3.0 * DIST + start);
+	float randFactor = clamp(texture(u_noiseTex, noiseTexUv).r, EPSILON, 1.0 - EPSILON);
 
 	float kNear = -u_lightingUniforms.nearFarClustererMagicPad1.x;
 	vec3 newCol = vec3(0.0);
-	uint count = 0;
-	for(uint k = 0u; k < maxK; ++k)
+	for(uint k = 0u; k < CLUSTER_COUNT.z; ++k)
 	{
 		float kFar = computeClusterFar(
 			k, u_lightingUniforms.nearFarClustererMagicPad1.x, u_lightingUniforms.nearFarClustererMagicPad1.z);
 
-		vec3 fragPos[MAX_SAMPLES_PER_CLUSTER];
+		//
+		// Compute sample count
+		//
+		float diff = kNear - kFar;
+		float samplesf = clamp(diff / DIST_BETWEEN_SAMPLES, 1.0, float(MAX_SAMPLES_PER_CLUSTER));
+		float dist = 1.0 / samplesf;
+		float start = dist * randFactor;
 
-		uint n;
-		for(n = 0u; n < MAX_SAMPLES_PER_CLUSTER; ++n)
-		{
-			float zMedian = mix(kNear, kFar, factors[n]);
+		//
+		// Find index ranges
+		//
+		uint clusterIdx = k * (CLUSTER_COUNT.x * CLUSTER_COUNT.y) + ij;
+		uint idxOffset = u_clusters[clusterIdx];
 
-			fragPos[n].z = zMedian;
-			fragPos[n].xy = ndc * u_lightingUniforms.projectionParams.xy * fragPos[n].z;
+		// Skip decals
+		uint count = u_lightIndices[idxOffset];
+		idxOffset += count + 1;
+
+		uint plightCount = u_lightIndices[idxOffset++];
+		uint plightIdx = idxOffset;
+		idxOffset += plightCount;
+
+		uint slightCount = u_lightIndices[idxOffset++];
+		uint slightIdx = idxOffset;
+
+		for(float factor = start; factor < 1.0; factor += dist)
+		{
+			float zMedian = mix(kNear, kFar, factor);
 
 			if(zMedian < farZ)
 			{
+				k = CLUSTER_COUNT.z; // Break the outer loop
 				break;
 			}
-		}
 
-		uint clusterIdx = k * (CLUSTER_COUNT.x * CLUSTER_COUNT.y) + j * CLUSTER_COUNT.x + i;
-		newCol += computeLightColor(fragPos, n, clusterIdx);
-		count += n;
+			vec3 fragPos;
+			fragPos.z = zMedian;
+			fragPos.xy = ndc * u_lightingUniforms.projectionParams.xy * fragPos.z;
+
+			newCol += computeLightColor(fragPos, plightCount, plightIdx, slightCount, slightIdx);
+		}
 
 		kNear = kFar;
 	}
 
-	newCol = newCol * fog(depth) / max(1.0, float(count));
-	out_color = vec4(newCol, 1.0 / 3.0);
+	newCol *= u_fogParticleColor;
+	out_color = vec4(newCol, 1.0 / 2.0);
 }

+ 1 - 1
src/anki/renderer/Volumetric.cpp

@@ -117,7 +117,7 @@ void Volumetric::run(RenderingContext& ctx)
 	uniforms[0].z() = m_r->getFrameCount() * texelOffset;
 	uniforms[0].w() = m_r->getFrameCount() & (m_noiseTex->getLayerCount() - 1);
 
-	uniforms[1] = Vec4(m_fogColor, m_fogFactor);
+	uniforms[1] = Vec4(m_fogParticleColor, 0.0);
 
 	bindStorage(cmdb, 0, 0, ctx.m_is.m_clustersToken);
 	bindStorage(cmdb, 0, 1, ctx.m_is.m_lightIndicesToken);

+ 4 - 5
src/anki/renderer/Volumetric.h

@@ -17,10 +17,9 @@ namespace anki
 class Volumetric : public RenderingPass
 {
 public:
-	void setFog(const Vec3& color, F32 factor)
+	void setFogParticleColor(const Vec3& color)
 	{
-		m_fogColor = color;
-		m_fogFactor = factor;
+		m_fogParticleColor = color;
 	}
 
 anki_internal:
@@ -44,8 +43,8 @@ private:
 	ShaderProgramPtr m_prog;
 	FramebufferPtr m_fb;
 
-	Vec3 m_fogColor = Vec3(1.0);
-	F32 m_fogFactor = 1.0;
+	Vec3 m_fogParticleColor = Vec3(1.0);
+	Mat3x4 m_prevCameraRot = Mat3x4::getIdentity();
 
 	TextureResourcePtr m_noiseTex;