浏览代码

Add reprojection of light accumulation

Panagiotis Christopoulos Charitos 7 年之前
父节点
当前提交
4f5da4f132

+ 4 - 2
CMakeLists.txt

@@ -67,6 +67,8 @@ endif()
 # Configuration                                                                #
 ################################################################################
 
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
 option(ANKI_EXTRA_CHECKS "Debugging checks (assertions)" OFF)
 option(ANKI_LTO "LTO compilation" OFF)
 
@@ -264,7 +266,7 @@ add_subdirectory(thirdparty/freetype)
 message("++ End configuring freetype")
 
 # glslang
-message("++ Configuring glslang")	
+message("++ Configuring glslang")
 add_subdirectory(thirdparty/glslang)
 message("++ End configuring glslang")
 
@@ -420,7 +422,7 @@ if(SDL)
 	set(THIRD_PARTY_LIBS ${THIRD_PARTY_LIBS} SDL2-static)
 endif()
 
-set(THIRD_PARTY_LIBS ${THIRD_PARTY_LIBS} BulletSoftBody BulletDynamics BulletCollision LinearMath 
+set(THIRD_PARTY_LIBS ${THIRD_PARTY_LIBS} BulletSoftBody BulletDynamics BulletCollision LinearMath
 	ankispirvcross ankitinyxml2 ankilua ankiz glslang SPIRV OGLCompiler OSDependent ankitinyexpr)
 
 # Add anki sub libraries

二进制
engine_data/BlueNoise_Rgb8_64x64x64_3D.ankitex


二进制
engine_data/blue_noise_rgb8_16x16x16_3d.ankitex


+ 2 - 1
shaders/ClusteredShadingCommon.glsl

@@ -26,10 +26,11 @@ layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING), std140, row_major) unifor
 #	define u_clusterCountX UNIFORM(u_lightingUniforms.m_clusterCount.x)
 #	define u_clusterCountY UNIFORM(u_lightingUniforms.m_clusterCount.y)
 #	define u_clustererMagic u_lightingUniforms.m_clustererMagicValues
+#	define u_prevClustererMagic u_lightingUniforms.m_prevClustererMagicValues
 #	define u_time UNIFORM(u_lightingUniforms.m_rendererSizeTimeNear.z)
 #	define u_unprojectionParams UNIFORM(u_lightingUniforms.m_unprojectionParams)
 #	define u_rendererSize u_lightingUniforms.m_rendererSizeTimeNear.xy
-#	define m_lightVolumeLastCluster UNIFORM(u_lightingUniforms.m_lightVolumeLastClusterPad3.x)
+#	define u_lightVolumeLastCluster UNIFORM(u_lightingUniforms.m_lightVolumeLastClusterPad3.x)
 
 #	define u_viewMat u_lightingUniforms.m_viewMat
 #	define u_invViewMat u_lightingUniforms.m_invViewMat

+ 1 - 1
shaders/ForwardShadingCommonFrag.glsl

@@ -117,7 +117,7 @@ Vec3 computeLightColorHigh(Vec3 diffCol, Vec3 worldPos)
 Vec3 computeLightColorLow(Vec3 diffCol, Vec3 worldPos)
 {
 	Vec2 uv = gl_FragCoord.xy / RENDERER_SIZE;
-	Vec3 uv3d = computeClustererVolumeTextureUvs(u_clustererMagic, uv, worldPos, m_lightVolumeLastCluster);
+	Vec3 uv3d = computeClustererVolumeTextureUvs(u_clustererMagic, uv, worldPos, u_lightVolumeLastCluster + 1u);
 
 	Vec3 light = textureLod(u_lightVol, uv3d, 0.0).rgb;
 	return diffuseLambert(diffCol) * light;

+ 1 - 1
shaders/ForwardShadingParticles.glslp

@@ -54,7 +54,7 @@ void main()
 #endif
 
 #if LIGHT
-	texCol.rgb = computeLightColorHigh(texCol.rgb, in_worldPos);
+	texCol.rgb = computeLightColorLow(texCol.rgb, in_worldPos);
 #endif
 
 	Vec4 colScale = colorScale;

+ 2 - 0
shaders/LightFunctions.glsl

@@ -12,7 +12,9 @@
 
 const F32 LIGHT_FRUSTUM_NEAR_PLANE = 0.1 / 4.0;
 const U32 SHADOW_SAMPLE_COUNT = 16;
+#if !defined(ESM_CONSTANT)
 const F32 ESM_CONSTANT = 40.0;
+#endif
 
 // Fresnel term unreal
 Vec3 F_Unreal(Vec3 specular, F32 VoH)

+ 29 - 12
shaders/VolumetricLightingAccumulation.glslp

@@ -16,10 +16,14 @@
 
 #pragma anki start comp
 
+// Lower the ESM constant to smooth the shadows
+#define ESM_CONSTANT 20.0
+
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = WORKGROUP_SIZE.z) in;
 
-layout(ANKI_IMAGE_BINDING(0, 0), r11f_g11f_b10f) uniform image3D out_volume;
+layout(ANKI_IMAGE_BINDING(0, 0)) writeonly uniform image3D u_volume;
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler3D u_noiseTex;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler3D u_prevVolume;
 
 struct PushConsts
 {
@@ -29,7 +33,7 @@ ANKI_PUSH_CONSTANTS(PushConsts, u_regs);
 
 #define u_noiseOffset u_regs.m_noiseOffsetPad3.x
 
-#define LIGHT_TEX_BINDING 1
+#define LIGHT_TEX_BINDING 2
 #define LIGHT_UBO_BINDING 0
 #define LIGHT_SS_BINDING 0
 #define LIGHT_SET 0
@@ -46,15 +50,12 @@ Vec3 readRand()
 	return textureLod(u_noiseTex, uv, 0.0).rgb;
 }
 
-Vec3 randWPos()
+Vec3 worldPosInsideCluster(Vec3 relativePos)
 {
-	// Read a rand value
-	Vec3 rand = readRand();
-
 	// Compute the cluster Z as float
 	F32 clusterKNear = g_globalInvocationID.z * (F32(FINAL_CLUSTER_Z + 1u) / F32(VOLUME_SIZE.z));
 	F32 clusterKFar = (g_globalInvocationID.z + 1.0) * (F32(FINAL_CLUSTER_Z + 1u) / F32(VOLUME_SIZE.z));
-	F32 clusterK = mix(clusterKNear, clusterKFar, rand.z);
+	F32 clusterK = mix(clusterKNear, clusterKFar, relativePos.z);
 
 	// Get a Z value
 	F32 zVSpace = -computeClusterNearf(u_clustererMagic, clusterK);
@@ -62,7 +63,7 @@ Vec3 randWPos()
 	// Get a XY value
 	Vec2 uvMin = g_globalInvocationID.xy / Vec2(VOLUME_SIZE.xy);
 	Vec2 uvMax = uvMin + 1.0 / Vec2(VOLUME_SIZE.xy);
-	Vec2 uv = mix(uvMin, uvMax, rand.xy);
+	Vec2 uv = mix(uvMin, uvMax, relativePos.xy);
 	Vec2 ndc = UV_TO_NDC(uv);
 	Vec2 xyZVspace = ndc * u_unprojectionParams.xy * zVSpace;
 
@@ -147,17 +148,33 @@ void main()
 	U32 clusterIdx = clusterXYZ.z * (CLUSTER_COUNT.x * CLUSTER_COUNT.y) + clusterXYZ.y * CLUSTER_COUNT.x + clusterXYZ.x;
 
 	// Find a random pos inside the cluster
-	Vec3 worldPos = randWPos();
+	Vec3 worldPos = worldPosInsideCluster(readRand());
 
 	// Get lighting
 	Vec3 color = accumulateLights(clusterIdx, worldPos);
 
 	// Read the prev result
-	Vec3 prev = imageLoad(out_volume, IVec3(gl_GlobalInvocationID)).rgb;
-	color = mix(prev, color, 1.0 / 16.0);
+	{
+		// Better get a new world pos in the center of the cluster. Using worldPos creates noisy results
+		Vec3 midWPos = worldPosInsideCluster(Vec3(0.5));
+
+		// Compute UV
+		Vec4 prevClipPos4 = u_prevViewProjMat * Vec4(worldPos, 1.0);
+		Vec2 prevUv = NDC_TO_UV(prevClipPos4.xy / prevClipPos4.w);
+
+		// Compute new Z tex coord
+		F32 k = computeClusterKf(u_prevClustererMagic, midWPos);
+		k /= F32(FINAL_CLUSTER_Z + 1u);
+
+		// Read prev
+		Vec3 prev = textureLod(u_prevVolume, Vec3(prevUv, k), 0.0).rgb;
+
+		// Modulate
+		color = mix(prev, color, 1.0 / 16.0);
+	}
 
 	// Write result
-	imageStore(out_volume, IVec3(gl_GlobalInvocationID), Vec4(color, 0.0));
+	imageStore(u_volume, IVec3(gl_GlobalInvocationID), Vec4(color, 0.0));
 }
 
 #pragma anki end

+ 1 - 0
shaders/glsl_cpp_common/ClusteredShading.h

@@ -67,6 +67,7 @@ struct LightingUniforms
 	Vec4 m_rendererSizeTimeNear;
 	Vec4 m_cameraPosFar;
 	ClustererMagicValues m_clustererMagicValues;
+	ClustererMagicValues m_prevClustererMagicValues;
 	UVec4 m_clusterCount;
 	UVec4 m_lightVolumeLastClusterPad3;
 	Mat4 m_viewMat;

+ 1 - 1
src/anki/core/Config.cpp

@@ -20,7 +20,7 @@ Config::Config()
 	newOption("r.clusterSizeZ", 32);
 	newOption("r.avgObjectsPerCluster", 16);
 
-	newOption("r.volumetricLightingAccumulation.clusterFractionXY", 2);
+	newOption("r.volumetricLightingAccumulation.clusterFractionXY", 4);
 	newOption("r.volumetricLightingAccumulation.clusterFractionZ", 4);
 	newOption("r.volumetricLightingAccumulation.finalClusterInZ", 26);
 

+ 5 - 0
src/anki/renderer/Renderer.cpp

@@ -316,6 +316,10 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 	cin.m_threadHive = m_threadHive;
 	m_clusterBin.bin(cin, ctx.m_clusterBinOut);
 
+	ctx.m_prevClustererMagicValues =
+		(m_frameCount > 0) ? m_prevClustererMagicValues : ctx.m_clusterBinOut.m_shaderMagicValues;
+	m_prevClustererMagicValues = ctx.m_clusterBinOut.m_shaderMagicValues;
+
 	updateLightShadingUniforms(ctx);
 	m_stats.m_lightBinTime = HighRezTimer::getCurrentTime() - m_stats.m_lightBinTime;
 
@@ -542,6 +546,7 @@ void Renderer::updateLightShadingUniforms(RenderingContext& ctx) const
 		Vec4(ctx.m_renderQueue->m_cameraTransform.getTranslationPart().xyz(), ctx.m_renderQueue->m_cameraFar);
 
 	blk->m_clustererMagicValues = ctx.m_clusterBinOut.m_shaderMagicValues;
+	blk->m_prevClustererMagicValues = ctx.m_prevClustererMagicValues;
 
 	blk->m_lightVolumeLastClusterPad3 = UVec4(m_volLighting->getFinalClusterInZ());
 

+ 2 - 0
src/anki/renderer/Renderer.h

@@ -60,6 +60,7 @@ public:
 	Vec4 m_unprojParams;
 
 	ClusterBinOut m_clusterBinOut;
+	ClustererMagicValues m_prevClustererMagicValues;
 
 	StagingGpuMemoryToken m_lightShadingUniformsToken;
 
@@ -409,6 +410,7 @@ private:
 	Bool m_resourcesDirty = true;
 
 	RenderingContextMatrices m_prevMatrices;
+	ClustererMagicValues m_prevClustererMagicValues;
 
 	Array<Mat4, 16> m_jitteredMats16x;
 	Array<Mat4, 8> m_jitteredMats8x;

+ 16 - 8
src/anki/renderer/VolumetricLightingAccumulation.cpp

@@ -39,7 +39,7 @@ Error VolumetricLightingAccumulation::init(const ConfigSet& config)
 		m_volumeSize[1],
 		m_volumeSize[2]);
 
-	ANKI_CHECK(getResourceManager().loadResource("engine_data/BlueNoise_Rgb8_64x64x64_3D.ankitex", m_noiseTex));
+	ANKI_CHECK(getResourceManager().loadResource("engine_data/blue_noise_rgb8_16x16x16_3d.ankitex", m_noiseTex));
 
 	// Shaders
 	ANKI_CHECK(getResourceManager().loadResource("shaders/VolumetricLightingAccumulation.glslp", m_prog));
@@ -63,12 +63,14 @@ Error VolumetricLightingAccumulation::init(const ConfigSet& config)
 	TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(m_volumeSize[0],
 		m_volumeSize[1],
 		LIGHT_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT,
-		TextureUsageBit::IMAGE_COMPUTE_READ_WRITE | TextureUsageBit::SAMPLED_FRAGMENT,
+		TextureUsageBit::IMAGE_COMPUTE_READ_WRITE | TextureUsageBit::SAMPLED_FRAGMENT
+			| TextureUsageBit::SAMPLED_COMPUTE,
 		"VolLight");
 	texinit.m_depth = m_volumeSize[2];
 	texinit.m_type = TextureType::_3D;
 	texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
-	m_rtTex = m_r->createAndClearRenderTarget(texinit);
+	m_rtTextures[0] = m_r->createAndClearRenderTarget(texinit);
+	m_rtTextures[1] = m_r->createAndClearRenderTarget(texinit);
 
 	return Error::NONE;
 }
@@ -78,7 +80,10 @@ void VolumetricLightingAccumulation::populateRenderGraph(RenderingContext& ctx)
 	m_runCtx.m_ctx = &ctx;
 	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
 
-	m_runCtx.m_rt = rgraph.importRenderTarget(m_rtTex, TextureUsageBit::SAMPLED_FRAGMENT);
+	const U readRtIdx = m_r->getFrameCount() & 1;
+
+	m_runCtx.m_rts[0] = rgraph.importRenderTarget(m_rtTextures[readRtIdx], TextureUsageBit::SAMPLED_FRAGMENT);
+	m_runCtx.m_rts[1] = rgraph.importRenderTarget(m_rtTextures[!readRtIdx], TextureUsageBit::NONE);
 
 	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("Vol light");
 
@@ -87,7 +92,8 @@ void VolumetricLightingAccumulation::populateRenderGraph(RenderingContext& ctx)
 	};
 	pass.setWork(callback, this, 0);
 
-	pass.newDependency({m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_READ_WRITE});
+	pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_COMPUTE});
+	pass.newDependency({m_runCtx.m_rts[1], TextureUsageBit::IMAGE_COMPUTE_WRITE});
 	pass.newDependency({m_r->getShadowMapping().getShadowmapRt(), TextureUsageBit::SAMPLED_COMPUTE});
 }
 
@@ -98,12 +104,14 @@ void VolumetricLightingAccumulation::run(RenderPassWorkContext& rgraphCtx)
 
 	cmdb->bindShaderProgram(m_grProg);
 
-	rgraphCtx.bindImage(0, 0, m_runCtx.m_rt, TextureSubresourceInfo());
+	rgraphCtx.bindImage(0, 0, m_runCtx.m_rts[1], TextureSubresourceInfo());
 
 	cmdb->bindTextureAndSampler(
 		0, 0, m_noiseTex->getGrTextureView(), m_r->getTrilinearRepeatSampler(), TextureUsageBit::SAMPLED_COMPUTE);
 
-	rgraphCtx.bindColorTextureAndSampler(0, 1, m_r->getShadowMapping().getShadowmapRt(), m_r->getLinearSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 1, m_runCtx.m_rts[0], m_r->getLinearSampler());
+
+	rgraphCtx.bindColorTextureAndSampler(0, 2, m_r->getShadowMapping().getShadowmapRt(), m_r->getLinearSampler());
 
 	const ClusterBinOut& rsrc = ctx.m_clusterBinOut;
 	bindUniforms(cmdb, 0, 0, ctx.m_lightShadingUniformsToken);
@@ -131,4 +139,4 @@ void VolumetricLightingAccumulation::run(RenderPassWorkContext& rgraphCtx)
 		m_volumeSize[2]);
 }
 
-} // end namespace anki
+} // end namespace anki

+ 8 - 7
src/anki/renderer/VolumetricLightingAccumulation.h

@@ -27,7 +27,7 @@ anki_internal:
 
 	RenderTargetHandle getRt() const
 	{
-		return m_runCtx.m_rt;
+		return m_runCtx.m_rts[1];
 	}
 
 	/// Get the last cluster split in Z axis that will be affected by lighting.
@@ -37,21 +37,22 @@ anki_internal:
 	}
 
 private:
-	U32 m_finalClusterZ = 0;
-
-	Array<U32, 3> m_workgroupSize = {{8, 8, 8}};
-	Array<U32, 3> m_volumeSize;
 	ShaderProgramResourcePtr m_prog;
 	ShaderProgramPtr m_grProg;
 
-	TexturePtr m_rtTex;
+	Array<TexturePtr, 2> m_rtTextures;
 	TextureResourcePtr m_noiseTex;
 
+	U32 m_finalClusterZ = 0;
+
+	Array<U32, 3> m_workgroupSize = {{8, 8, 8}};
+	Array<U32, 3> m_volumeSize;
+
 	class
 	{
 	public:
 		RenderingContext* m_ctx = nullptr;
-		RenderTargetHandle m_rt;
+		Array<RenderTargetHandle, 2> m_rts;
 	} m_runCtx; ///< Runtime context.
 
 	void run(RenderPassWorkContext& rgraphCtx);