Browse Source

Add indirect in the fog

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
068eae4614

+ 2 - 1
sandbox/Main.cpp

@@ -45,7 +45,8 @@ Error MyApp::init(int argc, char* argv[])
 	MainRenderer& renderer = getMainRenderer();
 	ResourceManager& resources = getResourceManager();
 
-	renderer.getOffscreenRenderer().getVolumetricFog().setFogParticleColor(Vec3(1.0, 0.9, 0.9) * 0.009);
+	renderer.getOffscreenRenderer().getVolumetricFog().setFogParticleColor(Vec3(1.0, 0.9, 0.9));
+	renderer.getOffscreenRenderer().getVolumetricFog().setParticleDensity(0.25f);
 
 	if(getenv("PROFILE"))
 	{

+ 0 - 192
shaders/VolumetricFog.glslp

@@ -1,192 +0,0 @@
-// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki mutator ENABLE_SHADOWS 0 1
-
-#pragma anki input const UVec2 FB_SIZE
-#pragma anki input const UVec3 CLUSTER_COUNT
-#pragma anki input const U32 NOISE_MAP_SIZE
-
-#pragma anki start vert
-#include <shaders/QuadVert.glsl>
-#pragma anki end
-
-#pragma anki start frag
-#include <shaders/Common.glsl>
-#include <shaders/Functions.glsl>
-
-#define LIGHT_TEX_BINDING 3
-#define LIGHT_UBO_BINDING 0
-#define LIGHT_SS_BINDING 0
-#define LIGHT_SET 0
-#define LIGHT_LIGHTS
-#define LIGHT_COMMON_UNIS
-#include <shaders/ClusteredShadingCommon.glsl>
-
-layout(location = 0) in Vec2 in_uv;
-
-layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_msDepthRt;
-layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2DArray u_noiseTex;
-layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_historyRt;
-
-layout(std140, ANKI_UBO_BINDING(0, 3), row_major) uniform ubo0_
-{
-	Vec4 u_linearizeNoiseTexOffsetLayer;
-	Vec4 u_fogParticleColorPad1;
-};
-
-#define u_linearize UNIFORM(u_linearizeNoiseTexOffsetLayer.xy)
-#define u_noiseYOffset UNIFORM(u_linearizeNoiseTexOffsetLayer.z)
-#define u_noiseLayer UNIFORM(u_linearizeNoiseTexOffsetLayer.w)
-#define u_fogParticleColor UNIFORM(u_fogParticleColorPad1.rgb)
-
-layout(location = 0) out Vec3 out_color;
-
-const U32 MAX_ITERATIONS = 256u;
-const F32 JITTER_DISTANCE = 10.0; // In meters
-const F32 HISTORY_FEEDBACK = 1.0 / 16.0;
-
-// Return the diffuse color without taking into account the diffuse term of the particles.
-Vec3 computeLightColor(Vec3 fragPos, U32 idxOffset)
-{
-	Vec3 color = Vec3(0.0);
-
-	// Skip decals
-	U32 count = u_lightIndices[idxOffset];
-	idxOffset += count + 1u;
-
-	// Point lights
-	count = u_lightIndices[idxOffset++];
-	U32 idxOffsetEnd = idxOffset + count;
-	ANKI_LOOP while(idxOffset < idxOffsetEnd)
-	{
-		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
-
-		Vec3 frag2Light = light.m_posRadius.xyz - fragPos;
-		F32 factor = computeAttenuationFactor(light.m_posRadius.w, frag2Light);
-
-#if ENABLE_SHADOWS
-		if(light.m_diffuseColorTileSize.w >= 0.0)
-		{
-			factor *= computeShadowFactorOmni(
-				frag2Light, light.m_radiusPad1.x, light.m_atlasTiles, light.m_diffuseColorTileSize.w, u_shadowTex);
-		}
-#endif
-
-		color += light.m_diffuseColorTileSize.rgb * factor;
-	}
-
-	// Spot lights
-	count = u_lightIndices[idxOffset++];
-	idxOffsetEnd = idxOffset + count;
-	ANKI_LOOP while(idxOffset < idxOffsetEnd)
-	{
-		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
-
-		Vec3 frag2Light = light.m_posRadius.xyz - fragPos;
-		F32 factor = computeAttenuationFactor(light.m_posRadius.w, frag2Light);
-
-		Vec3 l = normalize(frag2Light);
-
-		factor *=
-			computeSpotFactor(l, light.m_outerCosInnerCos.x, light.m_outerCosInnerCos.y, light.m_lightDirRadius.xyz);
-
-#if ENABLE_SHADOWS
-		F32 shadowmapLayerIdx = light.m_diffuseColorShadowmapId.w;
-		if(shadowmapLayerIdx >= 0.0)
-		{
-			factor *= computeShadowFactorSpot(light.m_texProjectionMat, fragPos, light.m_lightDirRadius.w, u_shadowTex);
-		}
-#endif
-
-		color += light.m_diffuseColorShadowmapId.rgb * factor;
-	}
-
-	return color;
-}
-
-Vec3 readHistory(Vec3 worldPos, out F32 historyFeedback)
-{
-	Vec4 v4 = u_prevViewProjMat * Vec4(worldPos, 1.0);
-	Vec2 ndc = v4.xy / v4.w;
-
-	Vec2 oldUv = NDC_TO_UV(ndc);
-	Vec3 history = textureLod(u_historyRt, oldUv, 0.0).rgb;
-
-	// Compute the history blend. If clip falls outside NDC then it's 1.0 (use only current fog term) and if it's
-	// inside NDC then use the HISTORY_FEEDBACK value
-	Vec2 posNdc = abs(ndc);
-	historyFeedback = max(posNdc.x, posNdc.y);
-	historyFeedback = min(floor(historyFeedback), 1.0 - HISTORY_FEEDBACK);
-	historyFeedback += HISTORY_FEEDBACK;
-
-	return history;
-}
-
-void main()
-{
-	F32 depth = textureLod(u_msDepthRt, in_uv, 0.0).r;
-	Vec2 ndc = UV_TO_NDC(in_uv);
-
-	// Compute some cluster stuff
-	U32 i = U32(in_uv.x * F32(CLUSTER_COUNT.x));
-	U32 j = U32(in_uv.y * F32(CLUSTER_COUNT.y));
-	U32 ij = j * CLUSTER_COUNT.x + i;
-
-	// Get a rand jitter distance
-	Vec3 noiseTexUv = Vec3(Vec2(FB_SIZE) / Vec2(NOISE_MAP_SIZE) * in_uv + Vec2(0.0, u_noiseYOffset), u_noiseLayer);
-	F32 randFactor = texture(u_noiseTex, noiseTexUv).r;
-	F32 randDistance = JITTER_DISTANCE * randFactor;
-
-	// Get world position
-	Vec4 worldPos4 = u_invViewProjMat * Vec4(ndc, depth, 1.0);
-	Vec3 worldPos = worldPos4.xyz / worldPos4.w;
-
-	// Compute the distances from the camera
-	F32 maxDistFromTheCamera = length(worldPos - u_cameraPos);
-
-	worldPos4 = u_invViewProjMat * Vec4(ndc, EPSILON, 1.0);
-	Vec3 nearWorldPos = worldPos4.xyz / worldPos4.w;
-	F32 minDistFromTheCamera = length(nearWorldPos - u_cameraPos);
-
-	// Ray march
-	Vec3 crntColor = Vec3(0.0);
-	const F32 FRACTION = 1.0 / F32(MAX_ITERATIONS - 1u);
-	ANKI_LOOP for(F32 f = FRACTION; f < 1.0; f += FRACTION)
-	{
-		// Compute new world pos
-		F32 f2 = f * f; // Higher detail closer to the camera
-		F32 distFromTheCamera = (u_far - minDistFromTheCamera - JITTER_DISTANCE) * f;
-		distFromTheCamera += minDistFromTheCamera + randDistance;
-
-		if(distFromTheCamera >= maxDistFromTheCamera)
-		{
-			break;
-		}
-
-		Vec3 newWorldPos = u_cameraPos + normalize(worldPos - u_cameraPos) * distFromTheCamera;
-
-		// Compute cluster idx
-		U32 k = computeClusterK(u_clustererMagic, newWorldPos);
-		U32 clusterIdx = k * (CLUSTER_COUNT.x * CLUSTER_COUNT.y) + ij;
-		U32 lightIdxOffset = u_clusters[clusterIdx];
-
-		// Do lighting
-		crntColor += computeLightColor(newWorldPos, lightIdxOffset);
-	}
-
-	crntColor *= diffuseLambert(u_fogParticleColor);
-
-	// Read history
-	F32 historyFeedback;
-	Vec3 history = readHistory(worldPos, historyFeedback);
-
-	// Fix ghosting
-	history = max(history, crntColor);
-
-	// Blend
-	out_color = mix(history, crntColor, historyFeedback);
-}
-#pragma anki end

+ 1 - 1
shaders/VolumetricFogAccumulation.glslp

@@ -61,7 +61,7 @@ void main()
 
 		// Read the light value
 		Vec3 light = textureLod(u_lightVolume, Vec3(uv, clusterKFar / F32(FINAL_CLUSTER_Z + 1u)), 0.0).rgb;
-		light *= u_fogDiffuse;
+		light *= u_fogDiffuse / PI;
 
 		// Integrate
 		Vec4 colorAndDensityBack = Vec4(light * scattering, scattering + absorption);

+ 40 - 1
shaders/VolumetricLightingAccumulation.glslp

@@ -17,7 +17,7 @@
 #pragma anki start comp
 
 // Lower the ESM constant to smooth the shadows
-#define ESM_CONSTANT 20.0
+#define ESM_CONSTANT 30.0
 
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = WORKGROUP_SIZE.z) in;
 
@@ -39,6 +39,7 @@ ANKI_PUSH_CONSTANTS(PushConsts, u_regs);
 #define LIGHT_SET 0
 #define LIGHT_LIGHTS
 #define LIGHT_COMMON_UNIS
+#define LIGHT_INDIRECT
 #include <shaders/ClusteredShadingCommon.glsl>
 
 Vec3 g_globalInvocationID = Vec3(gl_GlobalInvocationID);
@@ -74,9 +75,23 @@ Vec3 worldPosInsideCluster(Vec3 relativePos)
 	return worldPos;
 }
 
+F32 phaseFunction(Vec3 viewDir, Vec3 lightDir, F32 g)
+{
+	F32 g2 = g * g;
+
+	F32 a = (3.0 * (1.0 - g2)) / (2.0 * (2.0 + g2));
+
+	F32 cosTheta = dot(viewDir, lightDir);
+	F32 cosTheta2 = cosTheta * cosTheta;
+	F32 b = (1.0 + cosTheta2) / pow(1.0 + g2 - 2.0 * g * cosTheta, 3.0 / 2.0);
+
+	return a / b;
+}
+
 Vec3 accumulateLights(U32 clusterIdx, Vec3 worldPos)
 {
 	Vec3 color = Vec3(0.0);
+	Vec3 viewDir = normalize(u_cameraPos - worldPos);
 
 	// Get ID offset
 	U32 idxOffset = u_clusters[clusterIdx];
@@ -133,6 +148,30 @@ Vec3 accumulateLights(U32 clusterIdx, Vec3 worldPos)
 		color += light.m_diffuseColorShadowmapId.rgb * factor;
 	}
 
+	// Probes
+	F32 totalBlendWeight = EPSILON;
+	Vec3 diffIndirect = Vec3(0.0);
+	count = u_lightIndices[idxOffset++];
+	idxOffsetEnd = idxOffset + count;
+	ANKI_LOOP while(idxOffset < idxOffsetEnd)
+	{
+		ReflectionProbe probe = u_reflectionProbes[u_lightIndices[idxOffset++]];
+		Vec3 aabbMin = probe.m_aabbMinPad1.xyz;
+		Vec3 aabbMax = probe.m_aabbMaxPad1.xyz;
+		Vec3 probeOrigin = probe.m_positionCubemapIndex.xyz;
+		F32 cubemapIndex = probe.m_positionCubemapIndex.w;
+
+		F32 blendWeight = computeProbeBlendWeight(worldPos, aabbMin, aabbMax, 0.2);
+		totalBlendWeight += blendWeight;
+
+		Vec3 c = textureLod(u_irradianceTex, Vec4(viewDir, cubemapIndex), 0.0).rgb;
+		c *= PI; // Irradiance is pre-divided with PI so fix it
+		diffIndirect += c * blendWeight;
+	}
+
+	diffIndirect /= totalBlendWeight;
+	color += diffIndirect;
+
 	return color;
 }
 

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

@@ -99,7 +99,7 @@ Error Renderer::initInternal(const ConfigSet& config)
 	{
 		TextureInitInfo texinit;
 		texinit.m_width = texinit.m_height = 4;
-		texinit.m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
+		texinit.m_usage = TextureUsageBit::SAMPLED_ALL;
 		texinit.m_format = Format::R8G8B8A8_UNORM;
 		texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
 		TexturePtr tex = getGrManager().newTexture(texinit);

+ 7 - 0
src/anki/renderer/VolumetricLightingAccumulation.cpp

@@ -5,6 +5,7 @@
 
 #include <anki/renderer/VolumetricLightingAccumulation.h>
 #include <anki/renderer/ShadowMapping.h>
+#include <anki/renderer/Indirect.h>
 #include <anki/renderer/Renderer.h>
 #include <anki/resource/TextureResource.h>
 #include <anki/misc/ConfigSet.h>
@@ -112,11 +113,17 @@ void VolumetricLightingAccumulation::run(RenderPassWorkContext& rgraphCtx)
 	rgraphCtx.bindColorTextureAndSampler(0, 1, m_runCtx.m_rts[0], m_r->getLinearSampler());
 
 	rgraphCtx.bindColorTextureAndSampler(0, 2, m_r->getShadowMapping().getShadowmapRt(), m_r->getLinearSampler());
+	cmdb->bindTextureAndSampler(
+		0, 3, m_r->getDummyTextureView(), m_r->getNearestSampler(), TextureUsageBit::SAMPLED_COMPUTE);
+	rgraphCtx.bindColorTextureAndSampler(0, 4, m_r->getIndirect().getIrradianceRt(), m_r->getTrilinearRepeatSampler());
+	cmdb->bindTextureAndSampler(
+		0, 5, m_r->getDummyTextureView(), m_r->getNearestSampler(), TextureUsageBit::SAMPLED_COMPUTE);
 
 	const ClusterBinOut& rsrc = ctx.m_clusterBinOut;
 	bindUniforms(cmdb, 0, 0, ctx.m_lightShadingUniformsToken);
 	bindUniforms(cmdb, 0, 1, rsrc.m_pointLightsToken);
 	bindUniforms(cmdb, 0, 2, rsrc.m_spotLightsToken);
+	bindUniforms(cmdb, 0, 3, rsrc.m_probesToken);
 	bindStorage(cmdb, 0, 0, rsrc.m_clustersToken);
 	bindStorage(cmdb, 0, 1, rsrc.m_indicesToken);