Przeglądaj źródła

Merge pull request #28 from godlikepanos/separate_decals_pass

Separate decals pass + enable SSR
Panagiotis Christopoulos Charitos 7 lat temu
rodzic
commit
d7908bead8

+ 141 - 0
programs/GBufferPost.ankiprog

@@ -0,0 +1,141 @@
+<!-- 
+Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+All rights reserved.
+Code licensed under the BSD License.
+http://www.anki3d.org/LICENSE
+-->
+<shaderProgram>
+	<inputs>
+		<input name="CLUSTER_COUNT_X" type="uint" const="1"/>
+		<input name="CLUSTER_COUNT_Y" type="uint" const="1"/>
+		<input name="CLUSTER_COUNT_Z" type="uint" const="1"/>
+	</inputs>
+
+	<shaders>
+		<shader type="vert">
+			<source><![CDATA[
+#include "shaders/Common.glsl"
+
+layout(location = 0) out vec2 out_uv;
+layout(location = 1) out vec2 out_clusterIJ;
+
+out gl_PerVertex
+{
+	vec4 gl_Position;
+};
+
+void main()
+{
+	out_uv = vec2(gl_VertexID & 1, gl_VertexID >> 1) * 2.0;
+	vec2 pos = out_uv * 2.0 - 1.0;
+	gl_Position = vec4(pos, 0.0, 1.0);
+
+	out_clusterIJ = vec2(CLUSTER_COUNT_X, CLUSTER_COUNT_Y) * out_uv;
+}
+			]]></source>
+		</shader>
+
+		<shader type="frag">
+			<source><![CDATA[
+#include "shaders/Pack.glsl"
+#include "shaders/Clusterer.glsl"
+#include "shaders/Functions.glsl"
+
+#define LIGHT_SET 0
+#define LIGHT_SS_BINDING 0
+#define LIGHT_UBO_BINDING 0
+#define LIGHT_TEX_BINDING 2
+#define LIGHT_DECALS
+#define LIGHT_COMMON_UNIS
+#include "shaders/ClusterLightCommon.glsl"
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_msDepthRt;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_ssaoTex;
+
+layout(location = 0) in vec2 in_uv;
+layout(location = 1) in vec2 in_clusterIJ;
+
+layout(location = 0) out vec4 out_color0;
+layout(location = 1) out vec4 out_color1;
+
+void main()
+{
+	// This code blends the diffuse and the specular+rougness of the decals with GBuffer render targets.
+	// Normaly the blending is being done ('D' is the decal diffuse and 'f' is decal blend factor):
+	// d=gbuffer.diff
+	// 1st decal: d'=d*(1-f)+D*f
+	// 2nd decal: d''=d'*(1-f')+D'*f' <=> d''=d*(1-f)*(1-f')+D*f*(1-f')+D'*f'
+	// By looking at the trend we will have to multiply the gbuffer.diff with: (1-f)*(1-f') ... (1-f'''')
+
+	vec4 outDiffuse = vec4(0.0, 0.0, 0.0, 1.0);
+	vec4 outSpecular = vec4(0.0, 0.0, 0.0, 1.0);
+
+	// Sample SSAO
+	float ssao = textureLod(u_ssaoTex, in_uv, 0.0).r;
+	outDiffuse.a *= ssao;
+
+	// Get worldPos
+	float depth = textureLod(u_msDepthRt, in_uv, 0.0).r;
+	vec2 ndc = UV_TO_NDC(in_uv);
+	vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
+	vec3 worldPos = worldPos4.xyz / worldPos4.w;
+
+	// Get first light index
+	uint idxOffset;
+	{
+		uint k = computeClusterK(u_clustererMagic, worldPos);
+		uint clusterIdx = 
+			k * (CLUSTER_COUNT_X * CLUSTER_COUNT_Y) + uint(in_clusterIJ.y) * CLUSTER_COUNT_X + uint(in_clusterIJ.x);
+
+		idxOffset = u_clusters[clusterIdx];
+	}
+
+	// Process decals
+	uint count = u_lightIndices[idxOffset++];
+	while(count-- != 0)
+	{
+		Decal decal = u_decals[u_lightIndices[idxOffset++]];
+
+		// Project pos to decal space
+		vec4 texCoords4 = decal.texProjectionMat * vec4(worldPos, 1.0);
+		if(texCoords4.w <= 0.7)
+		{
+			// Behind the decal, skip
+			continue;
+		}
+
+		vec2 texCoords2 = texCoords4.xy / texCoords4.w;
+
+		// Clamp the tex coords. Expect a border in the texture atlas
+		texCoords2 = saturate(texCoords2);
+	
+		// Read diffuse
+		vec2 diffUv = mad(texCoords2, decal.diffUv.zw, decal.diffUv.xy);
+		vec4 decalDiff = texture(u_diffDecalTex, diffUv);
+
+		// Read roughness
+		vec2 specUv = mad(texCoords2, decal.normRoughnessUv.zw, decal.normRoughnessUv.xy);
+		vec3 spec = texture(u_specularRoughnessDecalTex, specUv).rgb;
+
+		// Update diffuse
+		float f = decalDiff.a * decal.blendFactors[0];
+		outDiffuse.rgb = outDiffuse.rgb * (1.0 - f) + decalDiff.rgb * f;
+		outDiffuse.a *= (1.0 - f);
+
+		// Update specular
+		f = decalDiff.a * decal.blendFactors[1];
+		outSpecular.rgb = outSpecular.rgb * (1.0 - f) + spec.rgb * f;
+		outSpecular.a *= (1.0 - f);
+	}
+
+	out_color0 = outDiffuse;
+	out_color1 = outSpecular;
+}
+			]]></source>
+		</shader>
+	</shaders>
+
+</shaderProgram>
+
+
+

+ 9 - 92
programs/LightShading.ankiprog

@@ -46,19 +46,16 @@ void main()
 #define LIGHT_SET 0
 #define LIGHT_SS_BINDING 0
 #define LIGHT_UBO_BINDING 0
-#define LIGHT_TEX_BINDING 0
+#define LIGHT_TEX_BINDING 5
 #define LIGHT_LIGHTS
-#define LIGHT_INDIRECT
-#define LIGHT_DECALS
 #define LIGHT_COMMON_UNIS
 #include "shaders/ClusterLightCommon.glsl"
 
-layout(ANKI_TEX_BINDING(1, 0)) uniform sampler2D u_msRt0;
-layout(ANKI_TEX_BINDING(1, 1)) uniform sampler2D u_msRt1;
-layout(ANKI_TEX_BINDING(1, 2)) uniform sampler2D u_msRt2;
-layout(ANKI_TEX_BINDING(1, 3)) uniform sampler2D u_msDepthRt;
-
-layout(ANKI_TEX_BINDING(1, 4)) uniform sampler2D u_ssaoTex;
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_msRt0;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_msRt1;
+layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_msRt2;
+layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_msDepthRt;
+layout(ANKI_TEX_BINDING(0, 4)) uniform sampler2D u_indirectRt;
 
 layout(location = 0) in vec2 in_uv;
 layout(location = 1) in vec2 in_clusterIJ;
@@ -77,63 +74,6 @@ const float SUBSURFACE_MIN = 0.05;
 	float att = computeAttenuationFactor(light.posRadius.w, frag2Light); \
 	float lambert = nol;
 
-// Compute the colors of a decal.
-void appendDecalColors(in Decal decal, in vec3 worldPos, inout vec3 diffuseColor, inout float roughness)
-{
-	vec4 texCoords4 = decal.texProjectionMat * vec4(worldPos, 1.0);
-	vec2 texCoords2 = texCoords4.xy / texCoords4.w;
-
-	// Clamp the tex coords. Expect a border in the texture atlas
-	texCoords2 = saturate(texCoords2);
-
-	vec2 diffUv = mad(texCoords2, decal.diffUv.zw, decal.diffUv.xy);
-	vec4 dcol = texture(u_diffDecalTex, diffUv);
-	diffuseColor = mix(diffuseColor, dcol.rgb, dcol.a * decal.blendFactors[0]);
-
-	// Roughness
-	vec2 roughnessUv = mad(texCoords2, decal.normRoughnessUv.zw, decal.normRoughnessUv.xy);
-	float r = texture(u_normalRoughnessDecalTex, roughnessUv).w;
-	roughness = mix(roughness, r, dcol.a * decal.blendFactors[1]);
-}
-
-void readIndirect(uint idxOffset, vec3 pos, vec3 r, vec3 n, float lod, out vec3 specIndirect, out vec3 diffIndirect)
-{
-	specIndirect = vec3(0.0);
-	diffIndirect = vec3(0.0);
-
-	// Check proxy
-	uint count = u_lightIndices[idxOffset++];
-	while(count-- != 0)
-	{
-		ReflectionProbe probe = u_reflectionProbes[u_lightIndices[idxOffset++]];
-
-		float R2 = probe.positionRadiusSq.w;
-		vec3 center = probe.positionRadiusSq.xyz;
-
-		// Get distance from the center of the probe
-		vec3 f = pos - center;
-
-		// Cubemap UV in view space
-		vec3 uv = computeCubemapVecAccurate(r, R2, f);
-
-		// Read!
-		float cubemapIndex = probe.cubemapIndexPad3.x;
-		vec3 c = textureLod(u_reflectionsTex, vec4(uv, cubemapIndex), lod).rgb;
-
-		// Combine (lerp) with previous color
-		float d = dot(f, f);
-		float factor = d / R2;
-		factor = min(factor, 1.0);
-		specIndirect = mix(c, specIndirect, factor);
-		// Same as: specIndirect = c * (1.0 - factor) + specIndirect * factor
-
-		// Do the same for diffuse
-		uv = computeCubemapVecAccurate(n, R2, f);
-		vec3 id = textureLod(u_irradianceTex, vec4(uv, cubemapIndex), 0.0).rgb;
-		diffIndirect = mix(id, diffIndirect, factor);
-	}
-}
-
 void main()
 {
 	float depth = textureLod(u_msDepthRt, in_uv, 0.0).r;
@@ -172,18 +112,9 @@ void main()
 		idxOffset = u_clusters[clusterIdx];
 	}
 
-	// Decals
+	// Skip decals
 	uint count = u_lightIndices[idxOffset++];
-	while(count-- != 0)
-	{
-		Decal decal = u_decals[u_lightIndices[idxOffset++]];
-
-		appendDecalColors(decal, worldPos, diffCol, roughness);
-	}
-
-	// Apply SSAO
-	float ssao = textureLod(u_ssaoTex, in_uv, 0.0).r;
-	diffCol *= ssao;
+	idxOffset += count;
 
 	// Ambient and emissive color
 	vec3 outC = diffCol * emission;
@@ -235,21 +166,7 @@ void main()
 	}
 
 	// Indirect
-	{
-		vec3 eye = -viewDir;
-		vec3 reflVec = reflect(eye, normal);
-
-		float reflLod = float(IR_MIPMAP_COUNT - 1u) * a2;
-
-		vec3 specIndirect, diffIndirect;
-		readIndirect(idxOffset, worldPos, reflVec, normal, reflLod, specIndirect, diffIndirect);
-
-		float ndotv = dot(normal, viewDir);
-		vec2 envBRDF = texture(u_integrationLut, vec2(a2, ndotv)).xy;
-		vec3 specIndirectTerm = specCol * envBRDF.x + envBRDF.y;
-
-		outC += specIndirect * specIndirectTerm + diffIndirect * diffCol;
-	}
+	outC += textureLod(u_indirectRt, in_uv, 0.0).rgb;
 
 	out_color = outC;
 #if 0

+ 57 - 33
programs/Reflections.ankiprog

@@ -31,7 +31,7 @@ http://www.anki3d.org/LICENSE
 #define LIGHT_SET 0
 #define LIGHT_SS_BINDING 0
 #define LIGHT_UBO_BINDING 0
-#define LIGHT_TEX_BINDING 5
+#define LIGHT_TEX_BINDING 6
 #define LIGHT_INDIRECT
 #define LIGHT_COMMON_UNIS
 #include "shaders/ClusterLightCommon.glsl"
@@ -40,14 +40,14 @@ const ivec2 HIZ_SIZE = ivec2(FB_SIZE) >> 1;
 
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
 
-layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_gbufferRt1;
-layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_gbufferRt2;
-layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_hizRt;
-layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_lightBufferRt;
-layout(ANKI_TEX_BINDING(0, 4)) uniform sampler2D u_depthRt;
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_gbufferRt0;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_gbufferRt1;
+layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_gbufferRt2;
+layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_depthRt;
+layout(ANKI_TEX_BINDING(0, 4)) uniform sampler2D u_hizRt;
+layout(ANKI_TEX_BINDING(0, 5)) uniform sampler2D u_lightBufferRt;
 
-layout(ANKI_IMAGE_BINDING(0, 0)) writeonly uniform image2D out_refl;
-layout(ANKI_IMAGE_BINDING(0, 1)) writeonly uniform image2D out_indirect;
+layout(ANKI_IMAGE_BINDING(0, 0)) writeonly uniform image2D out_reflAndIndirect;
 
 #define u_normalMat mat3(u_viewMat)
 
@@ -154,7 +154,7 @@ vec4 doSslr(vec3 r, vec3 n, vec3 viewPos, vec2 uv, float depth, float roughness)
 }
 
 // Note: All calculations in world space
-void doProbeReflections(
+void readReflectionsAndIrradianceFromProbes(
 	uint idxOffset, vec3 worldPos, vec3 normal, float roughness, out vec3 specIndirect, out vec3 diffIndirect)
 {
 	specIndirect = vec3(0.0);
@@ -197,6 +197,17 @@ void doProbeReflections(
 	}
 }
 
+vec3 computeSpecIndirectFactor(vec3 worldPos, vec3 normal, float roughness, vec3 specColor)
+{
+	vec3 viewDir = normalize(u_cameraPos - worldPos);
+	float ndotv = dot(normal, viewDir);
+
+	vec2 envBRDF = texture(u_integrationLut, vec2(roughness, ndotv)).xy;
+	vec3 specIndirectTerm = specColor * envBRDF.x + envBRDF.y;
+
+	return specIndirectTerm;
+}
+
 void main()
 {
 	uvec2 realInvocationId = gl_GlobalInvocationID.xy;
@@ -217,22 +228,29 @@ void main()
 	}
 
 	vec2 uv = (vec2(realInvocationId) + 0.5) / vec2(FB_SIZE);
+	vec2 ndc = UV_TO_NDC(uv);
 
-	// Get normal
-	vec3 worldNormal;
-	readNormalFromGBuffer(u_gbufferRt2, uv, worldNormal);
-
-	// Get roughness
-	float roughness;
-	vec3 specular;
-	readRoughnessSpecularFromGBuffer(u_gbufferRt1, uv, roughness, specular);
+	// Read gbuffer
+	GbufferInfo gbuffer;
+	readGBuffer(u_gbufferRt0, u_gbufferRt1, u_gbufferRt2, uv, 0.0, gbuffer);
 
 	// Get depth
 	float depth = textureLod(u_depthRt, uv, 0.0).r;
 
+	// Get world position
+	vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
+	vec3 worldPos = worldPos4.xyz / worldPos4.w;
+
+	// Compute how much reflections we need
+	float a2 = computeRoughnesSquared(gbuffer.roughness);
+	vec3 specIndirectTerm = computeSpecIndirectFactor(worldPos, gbuffer.normal, a2, gbuffer.specular);
+	bool runSslr = 
+		max(max(specIndirectTerm.x, specIndirectTerm.y), specIndirectTerm.z) > 0.05;
+
 	// Try SSR
 	float sslrFactor = 0.0;
 	vec3 sslrCol = vec3(0.0);
+	if(runSslr)
 	{
 		// Get view pos
 		vec4 viewPos4 = u_invProjMat * vec4(UV_TO_NDC(uv), depth, 1.0);
@@ -240,24 +258,19 @@ void main()
 
 		// Do SSLR
 		vec3 viewDir = normalize(viewPos);
-		vec3 viewNormal = u_normalMat * worldNormal;
+		vec3 viewNormal = u_normalMat * gbuffer.normal;
 		vec3 reflVec = reflect(viewDir, viewNormal);
 
-		vec4 sslr = doSslr(reflVec, viewNormal, viewPos, uv, depth, roughness);
+		vec4 sslr = doSslr(reflVec, viewNormal, viewPos, uv, depth, gbuffer.roughness);
 		sslrFactor = sslr.w;
 		sslrCol = sslr.xyz;
+		sslrCol = clamp(sslrCol, 0.0, FLT_MAX); // Fix the value just in case
 	}
 
 	// Read probes
-	vec3 probeCol;
-	vec3 indirectCol;
+	vec3 probeCol = vec3(0.0);
+	vec3 indirectCol = vec3(0.0);
 	{
-		vec2 ndc = UV_TO_NDC(uv);
-
-		// Get world position
-		vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
-		vec3 worldPos = worldPos4.xyz / worldPos4.w;
-
 		// Get first light index
 		uint clusterIdx = computeClusterIndex(u_clustererMagic, uv, worldPos, CLUSTER_COUNT_X, CLUSTER_COUNT_Y);
 		uint idxOffset = u_clusters[clusterIdx];
@@ -275,16 +288,27 @@ void main()
 		idxOffset += count;
 
 		// Do the probe read
-		doProbeReflections(idxOffset, worldPos, worldNormal, roughness, probeCol, indirectCol);
+		readReflectionsAndIrradianceFromProbes(
+			idxOffset, worldPos, gbuffer.normal, gbuffer.roughness, probeCol, indirectCol);
 	}
 
+	vec3 outColor = indirectCol * gbuffer.diffuse;
+
 	// Combine the SSR and probe reflections and write the result
-	vec3 finalRefl = mix(probeCol, sslrCol, sslrFactor);
-	finalRefl = clamp(finalRefl, 0.0, FLT_MAX); // XXX
-	imageStore(out_refl, ivec2(realInvocationId), vec4(finalRefl, 0.0));
+	{
+		vec3 finalRefl = mix(probeCol, sslrCol, sslrFactor);
+		finalRefl = specIndirectTerm * finalRefl;
+
+		outColor += finalRefl;
+	}
+	
+	// Done!
+	imageStore(out_reflAndIndirect, ivec2(realInvocationId), vec4(outColor, 0.0));
 
-	// Write indirect diffuse
-	imageStore(out_indirect, ivec2(realInvocationId), vec4(indirectCol, 0.0));
+	// Store the same color in the next pixel as well
+	bool xIsOdd = (realInvocationId.x & 1u) == 0u;
+	realInvocationId.x = (xIsOdd) ? (realInvocationId.x + 1u) : (realInvocationId.x - 1u);
+	imageStore(out_reflAndIndirect, ivec2(realInvocationId), vec4(outColor, 0.0));
 }
 			]]></source>
 		</shader>

+ 1 - 1
shaders/ClusterLightCommon.glsl

@@ -158,7 +158,7 @@ layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING_3)) unif
 };
 
 layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_3 + 0)) uniform sampler2D u_diffDecalTex;
-layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_3 + 1)) uniform sampler2D u_normalRoughnessDecalTex;
+layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_3 + 1)) uniform sampler2D u_specularRoughnessDecalTex;
 #endif
 
 //

+ 2 - 2
src/anki/gr/CommandBuffer.h

@@ -204,8 +204,8 @@ public:
 	void setColorChannelWriteMask(U32 attachment, ColorBit mask);
 
 	/// Set blend factors seperate.
-	/// By default the values of srcRgb, dstRgb, srcA and dstA are BlendFactor::ONE, BlendFactor::ONE,
-	/// BlendFactor::ZERO, BlendFactor::ZERO respectively.
+	/// By default the values of srcRgb, dstRgb, srcA and dstA are BlendFactor::ONE, BlendFactor::ZERO,
+	/// BlendFactor::ONE, BlendFactor::ZERO respectively.
 	void setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA);
 
 	/// Set blend factors.

+ 2 - 2
src/anki/gr/Common.h

@@ -43,8 +43,8 @@ const U MAX_MIPMAPS = 16;
 const U MAX_TEXTURE_LAYERS = 32;
 const U MAX_SPECIALIZED_CONSTS = 64;
 
-const U MAX_TEXTURE_BINDINGS = 8;
-const U MAX_UNIFORM_BUFFER_BINDINGS = 5;
+const U MAX_TEXTURE_BINDINGS = 16;
+const U MAX_UNIFORM_BUFFER_BINDINGS = 4;
 const U MAX_STORAGE_BUFFER_BINDINGS = 4;
 const U MAX_IMAGE_BINDINGS = 4;
 const U MAX_TEXTURE_BUFFER_BINDINGS = 4;

+ 2 - 2
src/anki/gr/RenderGraph.cpp

@@ -1218,7 +1218,7 @@ Error RenderGraph::dumpDependencyDotFile(
 			StringAuto barrierLabel(ctx.m_alloc);
 			if(barrier.m_isTexture)
 			{
-				barrierLabel.sprintf("<b>%s</b> (mip,dp,f,l)=(%u,%u,%u,%u)<br/>%s <b>-&gt;</b> %s",
+				barrierLabel.sprintf("<b>%s</b> (mip,dp,f,l)=(%u,%u,%u,%u)<br/>%s <b>to</b> %s",
 					&descr.m_renderTargets[barrier.m_texture.m_idx].m_name[0],
 					barrier.m_texture.m_surface.m_level,
 					barrier.m_texture.m_surface.m_depth,
@@ -1231,7 +1231,7 @@ Error RenderGraph::dumpDependencyDotFile(
 			}
 			else
 			{
-				barrierLabel.sprintf("<b>%s</b><br/>%s <b>-&gt;</b> %s",
+				barrierLabel.sprintf("<b>%s</b><br/>%s <b>to</b> %s",
 					&descr.m_buffers[barrier.m_buffer.m_idx].m_name[0],
 					bufferUsageToStr(alloc, barrier.m_buffer.m_usageBefore).cstr(),
 					bufferUsageToStr(alloc, barrier.m_buffer.m_usageAfter).cstr());

+ 1 - 0
src/anki/renderer/Common.h

@@ -20,6 +20,7 @@ namespace anki
 // Forward
 class Renderer;
 class GBuffer;
+class GBufferPost;
 class ShadowMapping;
 class LightShading;
 class ForwardShading;

+ 122 - 0
src/anki/renderer/GBufferPost.cpp

@@ -0,0 +1,122 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/renderer/GBufferPost.h>
+#include <anki/renderer/Renderer.h>
+#include <anki/renderer/GBuffer.h>
+#include <anki/renderer/Ssao.h>
+#include <anki/renderer/LightShading.h>
+#include <anki/misc/ConfigSet.h>
+
+namespace anki
+{
+
+GBufferPost::~GBufferPost()
+{
+}
+
+Error GBufferPost::init(const ConfigSet& cfg)
+{
+	Error err = initInternal(cfg);
+	if(err)
+	{
+		ANKI_R_LOGE("Failed to initialize GBufferPost pass");
+	}
+	return err;
+}
+
+Error GBufferPost::initInternal(const ConfigSet& cfg)
+{
+	ANKI_R_LOGI("Initializing GBufferPost pass");
+
+	// Load shaders
+	ANKI_CHECK(getResourceManager().loadResource("programs/GBufferPost.ankiprog", m_prog));
+
+	ShaderProgramResourceConstantValueInitList<3> consts(m_prog);
+	consts.add("CLUSTER_COUNT_X", U32(cfg.getNumber("r.clusterSizeX")));
+	consts.add("CLUSTER_COUNT_Y", U32(cfg.getNumber("r.clusterSizeY")));
+	consts.add("CLUSTER_COUNT_Z", U32(cfg.getNumber("r.clusterSizeZ")));
+
+	const ShaderProgramResourceVariant* variant;
+	m_prog->getOrCreateVariant(consts.get(), variant);
+	m_grProg = variant->getProgram();
+
+	// Create FB descr
+	m_fbDescr.m_colorAttachmentCount = 2;
+	m_fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::LOAD;
+	m_fbDescr.m_colorAttachments[1].m_loadOperation = AttachmentLoadOperation::LOAD;
+	m_fbDescr.bake();
+
+	return Error::NONE;
+}
+
+void GBufferPost::populateRenderGraph(RenderingContext& ctx)
+{
+	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
+	m_runCtx.m_ctx = &ctx;
+
+	// Create pass
+	GraphicsRenderPassDescription& rpass = rgraph.newGraphicsRenderPass("GBuffPost");
+
+	rpass.setWork(runCallback, this, 0);
+	rpass.setFramebufferInfo(m_fbDescr, {{m_r->getGBuffer().getColorRt(0), m_r->getGBuffer().getColorRt(1)}}, {});
+
+	rpass.newConsumer({m_r->getGBuffer().getColorRt(0), TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE});
+	rpass.newConsumer({m_r->getGBuffer().getColorRt(1), TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE});
+	rpass.newConsumer({m_r->getGBuffer().getDepthRt(),
+		TextureUsageBit::SAMPLED_FRAGMENT,
+		TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
+
+	rpass.newConsumer({m_r->getSsao().getRt(), TextureUsageBit::SAMPLED_FRAGMENT});
+
+	rpass.newProducer({m_r->getGBuffer().getColorRt(0), TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE});
+	rpass.newProducer({m_r->getGBuffer().getColorRt(1), TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE});
+}
+
+void GBufferPost::run(RenderPassWorkContext& rgraphCtx)
+{
+	const LightShadingResources& rsrc = m_r->getLightShading().getResources();
+	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+
+	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
+	cmdb->bindShaderProgram(m_grProg);
+
+	cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::SRC_ALPHA, BlendFactor::ZERO, BlendFactor::ONE);
+	cmdb->setBlendFactors(1, BlendFactor::ONE, BlendFactor::SRC_ALPHA, BlendFactor::ZERO, BlendFactor::ONE);
+
+	// Bind textures
+	rgraphCtx.bindTextureAndSampler(0,
+		0,
+		m_r->getGBuffer().getDepthRt(),
+		TextureSubresourceInfo(DepthStencilAspectBit::DEPTH),
+		m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 1, m_r->getSsao().getRt(), m_r->getLinearSampler());
+	cmdb->bindTextureAndSampler(0,
+		2,
+		(rsrc.m_diffDecalTexView) ? rsrc.m_diffDecalTexView : m_r->getDummyTextureView(),
+		m_r->getTrilinearRepeatSampler(),
+		TextureUsageBit::SAMPLED_FRAGMENT);
+	cmdb->bindTextureAndSampler(0,
+		3,
+		(rsrc.m_specularRoughnessDecalTexView) ? rsrc.m_specularRoughnessDecalTexView : m_r->getDummyTextureView(),
+		m_r->getTrilinearRepeatSampler(),
+		TextureUsageBit::SAMPLED_FRAGMENT);
+
+	// Uniforms
+	bindUniforms(cmdb, 0, 0, rsrc.m_commonUniformsToken);
+	bindUniforms(cmdb, 0, 1, rsrc.m_decalsToken);
+
+	// Storage
+	bindStorage(cmdb, 0, 0, rsrc.m_clustersToken);
+	bindStorage(cmdb, 0, 1, rsrc.m_lightIndicesToken);
+
+	cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
+
+	// Restore state
+	cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ZERO);
+	cmdb->setBlendFactors(1, BlendFactor::ONE, BlendFactor::ZERO);
+}
+
+} // end namespace anki

+ 55 - 0
src/anki/renderer/GBufferPost.h

@@ -0,0 +1,55 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/renderer/RendererObject.h>
+
+namespace anki
+{
+
+/// @addtogroup renderer
+/// @{
+
+/// Applies SSAO and decals to the GBuffer. It's a seperate pass because it requres the depth buffer.
+class GBufferPost : public RendererObject
+{
+anki_internal:
+	GBufferPost(Renderer* r)
+		: RendererObject(r)
+	{
+	}
+
+	~GBufferPost();
+
+	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
+
+	/// Populate the rendergraph.
+	void populateRenderGraph(RenderingContext& ctx);
+
+private:
+	ShaderProgramResourcePtr m_prog;
+	ShaderProgramPtr m_grProg;
+
+	FramebufferDescription m_fbDescr;
+
+	class
+	{
+	public:
+		RenderingContext* m_ctx ANKI_DBG_NULLIFY;
+	} m_runCtx;
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
+
+	static void runCallback(RenderPassWorkContext& rgraphCtx)
+	{
+		static_cast<GBufferPost*>(rgraphCtx.m_userData)->run(rgraphCtx);
+	}
+
+	void run(RenderPassWorkContext& rgraphCtx);
+};
+/// @}
+
+} // end namespace anki

+ 9 - 9
src/anki/renderer/LightBin.cpp

@@ -320,8 +320,8 @@ public:
 
 	TextureViewPtr m_diffDecalTexAtlas;
 	SpinLock m_diffDecalTexAtlasMtx;
-	TextureViewPtr m_normalRoughnessDecalTexAtlas;
-	SpinLock m_normalRoughnessDecalTexAtlasMtx;
+	TextureViewPtr m_specularRoughnessDecalTexAtlas;
+	SpinLock m_specularRoughnessDecalTexAtlasMtx;
 
 	LightBin* m_bin = nullptr;
 };
@@ -494,7 +494,7 @@ Error LightBin::bin(const Mat4& viewMat,
 	ANKI_CHECK(m_threadPool->waitForAllThreadsToFinish());
 
 	out.m_diffDecalTexView = ctx.m_diffDecalTexAtlas;
-	out.m_normRoughnessDecalTexView = ctx.m_normalRoughnessDecalTexAtlas;
+	out.m_specularRoughnessDecalTexView = ctx.m_specularRoughnessDecalTexAtlas;
 
 	return Error::NONE;
 }
@@ -807,20 +807,20 @@ void LightBin::writeAndBinDecal(const DecalQueueElement& decalEl, LightBinContex
 		ctx.m_diffDecalTexAtlas = atlas;
 	}
 
-	atlas.reset(const_cast<TextureView*>(decalEl.m_normalRoughnessAtlas));
-	uv = decalEl.m_normalRoughnessAtlasUv;
+	atlas.reset(const_cast<TextureView*>(decalEl.m_specularRoughnessAtlas));
+	uv = decalEl.m_specularRoughnessAtlasUv;
 	decal.m_normRoughnessUv = Vec4(uv.x(), uv.y(), uv.z() - uv.x(), uv.w() - uv.y());
-	decal.m_blendFactors[1] = decalEl.m_normalRoughnessAtlasBlendFactor;
+	decal.m_blendFactors[1] = decalEl.m_specularRoughnessAtlasBlendFactor;
 
 	if(atlas)
 	{
-		LockGuard<SpinLock> lock(ctx.m_normalRoughnessDecalTexAtlasMtx);
-		if(ctx.m_normalRoughnessDecalTexAtlas && ctx.m_normalRoughnessDecalTexAtlas != atlas)
+		LockGuard<SpinLock> lock(ctx.m_specularRoughnessDecalTexAtlasMtx);
+		if(ctx.m_specularRoughnessDecalTexAtlas && ctx.m_specularRoughnessDecalTexAtlas != atlas)
 		{
 			ANKI_R_LOGF("All decals should have the same tex atlas");
 		}
 
-		ctx.m_normalRoughnessDecalTexAtlas = atlas;
+		ctx.m_specularRoughnessDecalTexAtlas = atlas;
 	}
 
 	// bias * proj_l * view_

+ 1 - 1
src/anki/renderer/LightBin.h

@@ -28,7 +28,7 @@ public:
 	StagingGpuMemoryToken m_lightIndicesToken;
 
 	TextureViewPtr m_diffDecalTexView;
-	TextureViewPtr m_normRoughnessDecalTexView;
+	TextureViewPtr m_specularRoughnessDecalTexView;
 };
 
 /// Bins lights and probes to clusters.

+ 12 - 29
src/anki/renderer/LightShading.cpp

@@ -6,7 +6,6 @@
 #include <anki/renderer/LightShading.h>
 #include <anki/renderer/Renderer.h>
 #include <anki/renderer/ShadowMapping.h>
-#include <anki/renderer/Ssao.h>
 #include <anki/renderer/Indirect.h>
 #include <anki/renderer/GBuffer.h>
 #include <anki/renderer/LightBin.h>
@@ -139,41 +138,26 @@ void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgrap
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
 	cmdb->bindShaderProgram(m_progVariant->getProgram());
 
-	rgraphCtx.bindColorTextureAndSampler(1, 0, m_r->getGBuffer().getColorRt(0), m_r->getNearestSampler());
-	rgraphCtx.bindColorTextureAndSampler(1, 1, m_r->getGBuffer().getColorRt(1), m_r->getNearestSampler());
-	rgraphCtx.bindColorTextureAndSampler(1, 2, m_r->getGBuffer().getColorRt(2), m_r->getNearestSampler());
-	rgraphCtx.bindTextureAndSampler(1,
+	// Bind textures
+	rgraphCtx.bindColorTextureAndSampler(0, 0, m_r->getGBuffer().getColorRt(0), m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 1, m_r->getGBuffer().getColorRt(1), m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 2, m_r->getGBuffer().getColorRt(2), m_r->getNearestSampler());
+	rgraphCtx.bindTextureAndSampler(0,
 		3,
 		m_r->getGBuffer().getDepthRt(),
 		TextureSubresourceInfo(DepthStencilAspectBit::DEPTH),
 		m_r->getNearestSampler());
-	rgraphCtx.bindColorTextureAndSampler(1, 4, m_r->getSsao().getRt(), m_r->getLinearSampler());
 
-	rgraphCtx.bindColorTextureAndSampler(0, 0, m_r->getShadowMapping().getShadowmapRt(), m_r->getLinearSampler());
-	rgraphCtx.bindColorTextureAndSampler(0, 1, m_r->getIndirect().getReflectionRt(), m_r->getTrilinearRepeatSampler());
-	rgraphCtx.bindColorTextureAndSampler(0, 2, m_r->getIndirect().getIrradianceRt(), m_r->getLinearSampler());
-	cmdb->bindTextureAndSampler(0,
-		3,
-		m_r->getIndirect().getIntegrationLut(),
-		m_r->getIndirect().getIntegrationLutSampler(),
-		TextureUsageBit::SAMPLED_FRAGMENT);
-	cmdb->bindTextureAndSampler(0,
-		4,
-		(rsrc.m_diffDecalTexView) ? rsrc.m_diffDecalTexView : m_r->getDummyTextureView(),
-		m_r->getTrilinearRepeatSampler(),
-		TextureUsageBit::SAMPLED_FRAGMENT);
-	cmdb->bindTextureAndSampler(0,
-		5,
-		(rsrc.m_normRoughnessDecalTexView) ? rsrc.m_normRoughnessDecalTexView : m_r->getDummyTextureView(),
-		m_r->getTrilinearRepeatSampler(),
-		TextureUsageBit::SAMPLED_FRAGMENT);
+	rgraphCtx.bindColorTextureAndSampler(0, 4, m_r->getReflections().getRt(), m_r->getNearestSampler());
+
+	rgraphCtx.bindColorTextureAndSampler(0, 5, m_r->getShadowMapping().getShadowmapRt(), m_r->getLinearSampler());
 
+	// Bind uniforms
 	bindUniforms(cmdb, 0, 0, rsrc.m_commonUniformsToken);
 	bindUniforms(cmdb, 0, 1, rsrc.m_pointLightsToken);
 	bindUniforms(cmdb, 0, 2, rsrc.m_spotLightsToken);
-	bindUniforms(cmdb, 0, 3, rsrc.m_probesToken);
-	bindUniforms(cmdb, 0, 4, rsrc.m_decalsToken);
 
+	// Bind storage
 	bindStorage(cmdb, 0, 0, rsrc.m_clustersToken);
 	bindStorage(cmdb, 0, 1, rsrc.m_lightIndicesToken);
 
@@ -237,11 +221,10 @@ void LightShading::populateRenderGraph(RenderingContext& ctx)
 	pass.newConsumer({m_r->getGBuffer().getDepthRt(),
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
-	pass.newConsumer({m_r->getSsao().getRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 	pass.newConsumer({m_r->getShadowMapping().getShadowmapRt(), TextureUsageBit::SAMPLED_FRAGMENT});
-	pass.newConsumer({m_r->getIndirect().getReflectionRt(), TextureUsageBit::SAMPLED_FRAGMENT});
-	pass.newConsumer({m_r->getIndirect().getIrradianceRt(), TextureUsageBit::SAMPLED_FRAGMENT});
+	pass.newConsumer({m_r->getReflections().getRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 
+	// For forward shading
 	pass.newConsumer({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_FRAGMENT, HIZ_HALF_DEPTH});
 	pass.newConsumer({m_r->getForwardShading().getRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 

+ 27 - 29
src/anki/renderer/Reflections.cpp

@@ -37,16 +37,12 @@ Error Reflections::initInternal(const ConfigSet& cfg)
 	ANKI_R_LOGI("Initializing reflection pass (%ux%u)", width, height);
 
 	// Create RTs
-	TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(width,
+	m_rtDescr = m_r->create2DRenderTargetDescription(width,
 		height,
 		LIGHT_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT,
-		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::IMAGE_COMPUTE_WRITE
-			| TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
-		"Refl_");
-	texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
-
-	m_reflTex = m_r->createAndClearRenderTarget(texinit);
-	m_irradianceTex = m_r->createAndClearRenderTarget(texinit);
+		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::IMAGE_COMPUTE_WRITE,
+		"IndirectRes");
+	m_rtDescr.bake();
 
 	// Create shader
 	ANKI_CHECK(getResourceManager().loadResource("programs/Reflections.ankiprog", m_prog));
@@ -78,31 +74,28 @@ Error Reflections::initInternal(const ConfigSet& cfg)
 
 void Reflections::populateRenderGraph(RenderingContext& ctx)
 {
-	return; // TODO
-
 	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
 	m_runCtx.m_ctx = &ctx;
 
 	// Create RTs
-	m_runCtx.m_reflRt = rgraph.importRenderTarget("Refl", m_reflTex, TextureUsageBit::SAMPLED_FRAGMENT);
-	m_runCtx.m_irradianceRt = rgraph.importRenderTarget("ReflIrr", m_irradianceTex, TextureUsageBit::SAMPLED_FRAGMENT);
+	m_runCtx.m_indirectRt = rgraph.newRenderTarget(m_rtDescr);
 
 	// Create pass
-	ComputeRenderPassDescription& rpass = ctx.m_renderGraphDescr.newComputeRenderPass("Refl");
+	ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("IndirectRes");
 	rpass.setWork(runCallback, this, 0);
 
-	rpass.newConsumer({m_runCtx.m_reflRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
-	rpass.newConsumer({m_runCtx.m_irradianceRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
+	rpass.newConsumer({m_runCtx.m_indirectRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
+	rpass.newConsumer({m_r->getGBuffer().getColorRt(0), TextureUsageBit::SAMPLED_COMPUTE});
 	rpass.newConsumer({m_r->getGBuffer().getColorRt(1), TextureUsageBit::SAMPLED_COMPUTE});
 	rpass.newConsumer({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
 	rpass.newConsumer({m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_COMPUTE});
 	rpass.newConsumer({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_COMPUTE});
 	rpass.newConsumer({m_r->getDownscaleBlur().getRt(), TextureUsageBit::SAMPLED_COMPUTE});
+
 	rpass.newConsumer({m_r->getIndirect().getReflectionRt(), TextureUsageBit::SAMPLED_COMPUTE});
 	rpass.newConsumer({m_r->getIndirect().getIrradianceRt(), TextureUsageBit::SAMPLED_COMPUTE});
 
-	rpass.newProducer({m_runCtx.m_reflRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
-	rpass.newProducer({m_runCtx.m_irradianceRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
+	rpass.newProducer({m_runCtx.m_indirectRt, TextureUsageBit::IMAGE_COMPUTE_WRITE});
 }
 
 void Reflections::run(RenderPassWorkContext& rgraphCtx)
@@ -110,25 +103,30 @@ void Reflections::run(RenderPassWorkContext& rgraphCtx)
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	cmdb->bindShaderProgram(m_grProg[m_r->getFrameCount() & 1]);
 
-	rgraphCtx.bindColorTextureAndSampler(0, 0, m_r->getGBuffer().getColorRt(1), m_r->getNearestSampler());
-	rgraphCtx.bindColorTextureAndSampler(0, 1, m_r->getGBuffer().getColorRt(2), m_r->getNearestSampler());
-	rgraphCtx.bindColorTextureAndSampler(0, 2, m_r->getDepthDownscale().getHiZRt(), m_r->getNearestNearestSampler());
-	rgraphCtx.bindColorTextureAndSampler(0, 3, m_r->getDownscaleBlur().getRt(), m_r->getTrilinearRepeatSampler());
+	// Bind textures
+	rgraphCtx.bindColorTextureAndSampler(0, 0, m_r->getGBuffer().getColorRt(0), m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 1, m_r->getGBuffer().getColorRt(1), m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 2, m_r->getGBuffer().getColorRt(2), m_r->getNearestSampler());
 	rgraphCtx.bindTextureAndSampler(0,
-		4,
+		3,
 		m_r->getGBuffer().getDepthRt(),
 		TextureSubresourceInfo(DepthStencilAspectBit::DEPTH),
 		m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 4, m_r->getDepthDownscale().getHiZRt(), m_r->getNearestNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 5, m_r->getDownscaleBlur().getRt(), m_r->getTrilinearRepeatSampler());
 
-	rgraphCtx.bindImage(0, 0, m_runCtx.m_reflRt, TextureSubresourceInfo());
-	rgraphCtx.bindImage(0, 1, m_runCtx.m_irradianceRt, TextureSubresourceInfo());
+	rgraphCtx.bindColorTextureAndSampler(0, 6, m_r->getIndirect().getReflectionRt(), m_r->getTrilinearRepeatSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 7, m_r->getIndirect().getIrradianceRt(), m_r->getTrilinearRepeatSampler());
+	cmdb->bindTextureAndSampler(0,
+		8,
+		m_r->getIndirect().getIntegrationLut(),
+		m_r->getIndirect().getIntegrationLutSampler(),
+		TextureUsageBit::SAMPLED_COMPUTE);
 
-	// Bind light shading stuff
-	rgraphCtx.bindColorTextureAndSampler(0, 5, m_r->getIndirect().getReflectionRt(), m_r->getTrilinearRepeatSampler());
-	rgraphCtx.bindColorTextureAndSampler(0, 6, m_r->getIndirect().getIrradianceRt(), m_r->getTrilinearRepeatSampler());
-	cmdb->bindTextureAndSampler(
-		0, 7, m_r->getDummyTextureView(), m_r->getNearestSampler(), TextureUsageBit::SAMPLED_COMPUTE);
+	// Bind image
+	rgraphCtx.bindImage(0, 0, m_runCtx.m_indirectRt, TextureSubresourceInfo());
 
+	// Bind uniforms
 	const LightShadingResources& rsrc = m_r->getLightShading().getResources();
 	bindUniforms(cmdb, 0, 0, rsrc.m_commonUniformsToken);
 	bindUniforms(cmdb, 0, 1, rsrc.m_probesToken);

+ 5 - 12
src/anki/renderer/Reflections.h

@@ -13,7 +13,7 @@ namespace anki
 /// @addtogroup renderer
 /// @{
 
-/// Reflections pass.
+/// Reflections pass. It does SSR and probe reflections and it conbines them with the irradiance as well.
 class Reflections : public RendererObject
 {
 anki_internal:
@@ -29,30 +29,23 @@ anki_internal:
 	/// Populate the rendergraph.
 	void populateRenderGraph(RenderingContext& ctx);
 
-	RenderTargetHandle getReflectionRt() const
+	RenderTargetHandle getRt() const
 	{
-		return m_runCtx.m_reflRt;
-	}
-
-	RenderTargetHandle getIrradianceRt() const
-	{
-		return m_runCtx.m_irradianceRt;
+		return m_runCtx.m_indirectRt;
 	}
 
 private:
 	ShaderProgramResourcePtr m_prog;
 	Array<ShaderProgramPtr, 2> m_grProg;
 
-	TexturePtr m_reflTex;
-	TexturePtr m_irradianceTex;
+	RenderTargetDescription m_rtDescr;
 
 	Array<U8, 2> m_workgroupSize = {{16, 16}};
 
 	class
 	{
 	public:
-		RenderTargetHandle m_reflRt;
-		RenderTargetHandle m_irradianceRt;
+		RenderTargetHandle m_indirectRt;
 		RenderingContext* m_ctx ANKI_DBG_NULLIFY;
 	} m_runCtx;
 

+ 3 - 3
src/anki/renderer/RenderQueue.h

@@ -145,11 +145,11 @@ public:
 	/// Totaly unsafe but we can't have a smart ptr in here since there will be no deletion.
 	const TextureView* m_diffuseAtlas;
 	/// Totaly unsafe but we can't have a smart ptr in here since there will be no deletion.
-	const TextureView* m_normalRoughnessAtlas;
+	const TextureView* m_specularRoughnessAtlas;
 	Vec4 m_diffuseAtlasUv;
-	Vec4 m_normalRoughnessAtlasUv;
+	Vec4 m_specularRoughnessAtlasUv;
 	F32 m_diffuseAtlasBlendFactor;
-	F32 m_normalRoughnessAtlasBlendFactor;
+	F32 m_specularRoughnessAtlasBlendFactor;
 	Mat4 m_textureMatrix;
 	Vec3 m_obbCenter;
 	Vec3 m_obbExtend;

+ 6 - 2
src/anki/renderer/Renderer.cpp

@@ -11,6 +11,7 @@
 
 #include <anki/renderer/Indirect.h>
 #include <anki/renderer/GBuffer.h>
+#include <anki/renderer/GBufferPost.h>
 #include <anki/renderer/LightShading.h>
 #include <anki/renderer/ShadowMapping.h>
 #include <anki/renderer/FinalComposite.h>
@@ -112,6 +113,9 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_gbuffer.reset(m_alloc.newInstance<GBuffer>(this));
 	ANKI_CHECK(m_gbuffer->init(config));
 
+	m_gbufferPost.reset(m_alloc.newInstance<GBufferPost>(this));
+	ANKI_CHECK(m_gbufferPost->init(config));
+
 	m_shadowMapping.reset(m_alloc.newInstance<ShadowMapping>(this));
 	ANKI_CHECK(m_shadowMapping->init(config));
 
@@ -266,9 +270,10 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 	m_indirect->populateRenderGraph(ctx);
 	m_gbuffer->populateRenderGraph(ctx);
 	m_depth->populateRenderGraph(ctx);
-	m_refl->populateRenderGraph(ctx);
 	m_vol->populateRenderGraph(ctx);
 	m_ssao->populateRenderGraph(ctx);
+	m_gbufferPost->populateRenderGraph(ctx);
+	m_refl->populateRenderGraph(ctx);
 	m_lensFlare->populateRenderGraph(ctx);
 	m_forwardShading->populateRenderGraph(ctx);
 	m_lightShading->populateRenderGraph(ctx);
@@ -338,7 +343,6 @@ TextureInitInfo Renderer::create2DRenderTargetInitInfo(
 RenderTargetDescription Renderer::create2DRenderTargetDescription(
 	U32 w, U32 h, const PixelFormat& format, TextureUsageBit usage, CString name)
 {
-	ANKI_ASSERT(!!(usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
 	RenderTargetDescription init(name);
 
 	init.m_width = w;

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

@@ -353,6 +353,7 @@ private:
 	UniquePtr<Indirect> m_indirect;
 	UniquePtr<ShadowMapping> m_shadowMapping; ///< Shadow mapping.
 	UniquePtr<GBuffer> m_gbuffer; ///< Material rendering stage
+	UniquePtr<GBufferPost> m_gbufferPost;
 	UniquePtr<Reflections> m_refl;
 	UniquePtr<LightShading> m_lightShading; ///< Illumination rendering stage
 	UniquePtr<DepthDownscale> m_depth;

+ 13 - 13
src/anki/scene/components/DecalComponent.h

@@ -34,9 +34,9 @@ public:
 		return setLayer(texAtlasFname, texAtlasSubtexName, blendFactor, LayerType::DIFFUSE);
 	}
 
-	ANKI_USE_RESULT Error setNormalRoughnessDecal(CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor)
+	ANKI_USE_RESULT Error setSpecularRoughnessDecal(CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor)
 	{
-		return setLayer(texAtlasFname, texAtlasSubtexName, blendFactor, LayerType::NORMAL_ROUGHNESS);
+		return setLayer(texAtlasFname, texAtlasSubtexName, blendFactor, LayerType::SPECULAR_ROUGHNESS);
 	}
 
 	/// Update the internal structures.
@@ -99,18 +99,18 @@ public:
 		blendFactor = m_layers[LayerType::DIFFUSE].m_blendFactor;
 	}
 
-	void getNormalRoughnessAtlasInfo(Vec4& uv, TexturePtr& tex, F32& blendFactor) const
+	void getSpecularRoughnessAtlasInfo(Vec4& uv, TexturePtr& tex, F32& blendFactor) const
 	{
-		uv = m_layers[LayerType::NORMAL_ROUGHNESS].m_uv;
-		if(m_layers[LayerType::NORMAL_ROUGHNESS].m_atlas)
+		uv = m_layers[LayerType::SPECULAR_ROUGHNESS].m_uv;
+		if(m_layers[LayerType::SPECULAR_ROUGHNESS].m_atlas)
 		{
-			tex = m_layers[LayerType::NORMAL_ROUGHNESS].m_atlas->getGrTexture();
+			tex = m_layers[LayerType::SPECULAR_ROUGHNESS].m_atlas->getGrTexture();
 		}
 		else
 		{
 			tex.reset(nullptr);
 		}
-		blendFactor = m_layers[LayerType::NORMAL_ROUGHNESS].m_blendFactor;
+		blendFactor = m_layers[LayerType::SPECULAR_ROUGHNESS].m_blendFactor;
 	}
 
 	const Vec3& getVolumeSize() const
@@ -123,13 +123,13 @@ public:
 		el.m_diffuseAtlas = (m_layers[LayerType::DIFFUSE].m_atlas)
 								? m_layers[LayerType::DIFFUSE].m_atlas->getGrTextureView().get()
 								: nullptr;
-		el.m_normalRoughnessAtlas = (m_layers[LayerType::NORMAL_ROUGHNESS].m_atlas)
-										? m_layers[LayerType::NORMAL_ROUGHNESS].m_atlas->getGrTextureView().get()
-										: nullptr;
+		el.m_specularRoughnessAtlas = (m_layers[LayerType::SPECULAR_ROUGHNESS].m_atlas)
+										  ? m_layers[LayerType::SPECULAR_ROUGHNESS].m_atlas->getGrTextureView().get()
+										  : nullptr;
 		el.m_diffuseAtlasUv = m_layers[LayerType::DIFFUSE].m_uv;
-		el.m_normalRoughnessAtlasUv = m_layers[LayerType::NORMAL_ROUGHNESS].m_uv;
+		el.m_specularRoughnessAtlasUv = m_layers[LayerType::SPECULAR_ROUGHNESS].m_uv;
 		el.m_diffuseAtlasBlendFactor = m_layers[LayerType::DIFFUSE].m_blendFactor;
-		el.m_normalRoughnessAtlasBlendFactor = m_layers[LayerType::NORMAL_ROUGHNESS].m_blendFactor;
+		el.m_specularRoughnessAtlasBlendFactor = m_layers[LayerType::SPECULAR_ROUGHNESS].m_blendFactor;
 		el.m_textureMatrix = m_biasProjViewMat;
 		el.m_obbCenter = m_obb.getCenter().xyz();
 		el.m_obbExtend = m_obb.getExtend().xyz();
@@ -142,7 +142,7 @@ private:
 	enum class LayerType
 	{
 		DIFFUSE,
-		NORMAL_ROUGHNESS,
+		SPECULAR_ROUGHNESS,
 		COUNT
 	};
 

+ 7 - 7
src/anki/script/Scene.cpp

@@ -1176,8 +1176,8 @@ static int wrapDecalComponentsetDiffuseDecal(lua_State* l)
 	return 0;
 }
 
-/// Pre-wrap method DecalComponent::setNormalRoughnessDecal.
-static inline int pwrapDecalComponentsetNormalRoughnessDecal(lua_State* l)
+/// Pre-wrap method DecalComponent::setSpecularRoughnessDecal.
+static inline int pwrapDecalComponentsetSpecularRoughnessDecal(lua_State* l)
 {
 	LuaUserData* ud;
 	(void)ud;
@@ -1216,7 +1216,7 @@ static inline int pwrapDecalComponentsetNormalRoughnessDecal(lua_State* l)
 	}
 
 	// Call the method
-	Error ret = self->setNormalRoughnessDecal(arg0, arg1, arg2);
+	Error ret = self->setSpecularRoughnessDecal(arg0, arg1, arg2);
 
 	// Push return value
 	if(ANKI_UNLIKELY(ret))
@@ -1230,10 +1230,10 @@ static inline int pwrapDecalComponentsetNormalRoughnessDecal(lua_State* l)
 	return 1;
 }
 
-/// Wrap method DecalComponent::setNormalRoughnessDecal.
-static int wrapDecalComponentsetNormalRoughnessDecal(lua_State* l)
+/// Wrap method DecalComponent::setSpecularRoughnessDecal.
+static int wrapDecalComponentsetSpecularRoughnessDecal(lua_State* l)
 {
-	int res = pwrapDecalComponentsetNormalRoughnessDecal(l);
+	int res = pwrapDecalComponentsetSpecularRoughnessDecal(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1306,7 +1306,7 @@ static inline void wrapDecalComponent(lua_State* l)
 {
 	LuaBinder::createClass(l, classnameDecalComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "setDiffuseDecal", wrapDecalComponentsetDiffuseDecal);
-	LuaBinder::pushLuaCFuncMethod(l, "setNormalRoughnessDecal", wrapDecalComponentsetNormalRoughnessDecal);
+	LuaBinder::pushLuaCFuncMethod(l, "setSpecularRoughnessDecal", wrapDecalComponentsetSpecularRoughnessDecal);
 	LuaBinder::pushLuaCFuncMethod(l, "updateShape", wrapDecalComponentupdateShape);
 	lua_settop(l, 0);
 }

+ 1 - 1
src/anki/script/Scene.xml

@@ -147,7 +147,7 @@ static SceneGraph* getSceneGraph(lua_State* l)
 					</args>
 					<return>Error</return>
 				</method>
-				<method name="setNormalRoughnessDecal">
+				<method name="setSpecularRoughnessDecal">
 					<args>
 						<arg>CString</arg>
 						<arg>CString</arg>

+ 5 - 5
tools/scene/Exporter.cpp

@@ -895,11 +895,11 @@ void Exporter::visitNode(const aiNode* ainode)
 					}
 					else if(pr.first == "decal_normal_roughness_atlas")
 					{
-						decal.m_normalRoughnessAtlasFilename = pr.second;
+						decal.m_specularRoughnessAtlasFilename = pr.second;
 					}
 					else if(pr.first == "decal_normal_roughness_sub_texture")
 					{
-						decal.m_normalRoughnessSubTextureName = pr.second;
+						decal.m_specularRoughnessSubTextureName = pr.second;
 					}
 					else if(pr.first == "decal_normal_roughness_factor")
 					{
@@ -1116,10 +1116,10 @@ void Exporter::exportAll()
 			 << decal.m_diffuseSubTextureName << "\", " << decal.m_factors[0] << ")\n";
 		file << "decalc:updateShape(" << decal.m_size.x << ", " << decal.m_size.y << ", " << decal.m_size.z << ")\n";
 
-		if(!decal.m_normalRoughnessAtlasFilename.empty())
+		if(!decal.m_specularRoughnessAtlasFilename.empty())
 		{
-			file << "decalc:setNormalRoughnessDecal(\"" << decal.m_normalRoughnessAtlasFilename << "\", \""
-				 << decal.m_normalRoughnessSubTextureName << "\", " << decal.m_factors[1] << ")\n";
+			file << "decalc:setSpecularRoughnessDecal(\"" << decal.m_specularRoughnessAtlasFilename << "\", \""
+				 << decal.m_specularRoughnessSubTextureName << "\", " << decal.m_factors[1] << ")\n";
 		}
 
 		++i;

+ 2 - 2
tools/scene/Exporter.h

@@ -97,8 +97,8 @@ public:
 	aiMatrix4x4 m_transform;
 	std::string m_diffuseTextureAtlasFilename;
 	std::string m_diffuseSubTextureName;
-	std::string m_normalRoughnessAtlasFilename;
-	std::string m_normalRoughnessSubTextureName;
+	std::string m_specularRoughnessAtlasFilename;
+	std::string m_specularRoughnessSubTextureName;
 	aiVector3D m_size;
 	std::array<float, 2> m_factors = {{1.0, 1.0}};
 };