Răsfoiți Sursa

[FEATURE] Improve quality of gbuffer's normal map

Panagiotis Christopoulos Charitos 8 ani în urmă
părinte
comite
16eb91ffdc

+ 1 - 0
shaders/Common.glsl

@@ -36,6 +36,7 @@ const uint UBO_MAX_SIZE = 16384u;
 
 #define UV_TO_NDC(x_) ((x_)*2.0 - 1.0)
 #define NDC_TO_UV(x_) ((x_)*0.5 + 0.5)
+#define saturate(x_) clamp((x_), 0.0, 1.0)
 
 // Common locations
 #define POSITION_LOCATION 0

+ 1 - 1
shaders/Functions.glsl

@@ -249,7 +249,7 @@ vec3 grayScale(vec3 col)
 	return vec3(grey);
 }
 
-vec3 saturate(vec3 col, float factor)
+vec3 saturateColor(vec3 col, float factor)
 {
 	const vec3 LUM_COEFF = vec3(0.2125, 0.7154, 0.0721);
 	vec3 intensity = vec3(dot(col, LUM_COEFF));

+ 38 - 5
shaders/Pack.glsl

@@ -29,6 +29,37 @@ vec3 unpackNormal(in vec2 enc)
 	return normalize(normal);
 }
 
+// See http://johnwhite3d.blogspot.no/2017/10/signed-octahedron-normal-encoding.html
+// Result in [0.0, 1.0]
+vec3 signedOctEncode(vec3 n)
+{
+	vec3 outn;
+
+	vec3 nabs = abs(n);
+	n /= nabs.x + nabs.y + nabs.z;
+
+	outn.y = n.y * 0.5 + 0.5;
+	outn.x = n.x * 0.5 + outn.y;
+	outn.y = n.x * -0.5 + outn.y;
+
+	outn.z = saturate(n.z * FLT_MAX);
+	return outn;
+}
+
+// See http://johnwhite3d.blogspot.no/2017/10/signed-octahedron-normal-encoding.html
+vec3 signedOctDecode(vec3 n)
+{
+	vec3 outn;
+
+	outn.x = n.x - n.y;
+	outn.y = n.x + n.y - 1.0;
+	outn.z = n.z * 2.0 - 1.0;
+	outn.z = outn.z * (1.0 - abs(outn.x) - abs(outn.y));
+
+	outn = normalize(outn);
+	return outn;
+}
+
 #if GL_ES || __VERSION__ < 400
 
 // Vectorized version. See clean one at <= r1048
@@ -97,7 +128,7 @@ vec2 unpackUnorm1ToUnorm2(in float c)
 }
 
 // Max emission. Keep as low as possible
-const float MAX_EMISSION = 10.0;
+const float MAX_EMISSION = 20.0;
 
 // G-Buffer structure
 struct GbufferInfo
@@ -117,13 +148,15 @@ void writeGBuffer(in GbufferInfo g, out vec4 rt0, out vec4 rt1, out vec4 rt2)
 	float comp = packUnorm2ToUnorm1(vec2(g.subsurface, g.metallic));
 	rt0 = vec4(g.diffuse, comp);
 	rt1 = vec4(g.specular, g.roughness);
-	rt2 = vec4(g.normal * 0.5 + 0.5, g.emission / MAX_EMISSION);
+
+	vec3 encNorm = signedOctEncode(g.normal);
+	rt2 = vec4(encNorm.xy, g.emission / MAX_EMISSION, encNorm.z);
 }
 
 // Read from G-buffer
 void readNormalFromGBuffer(in sampler2D rt2, in vec2 uv, out vec3 normal)
 {
-	normal = texture(rt2, uv).rgb * 2.0 - 1.0;
+	normal = signedOctDecode(texture(rt2, uv).rga);
 }
 
 // Read from the G buffer
@@ -140,8 +173,8 @@ void readGBuffer(in sampler2D rt0, in sampler2D rt1, in sampler2D rt2, in vec2 u
 	g.roughness = comp.w;
 
 	comp = textureLod(rt2, uv, lod);
-	g.normal = comp.xyz * 2.0 - 1.0;
-	g.emission = comp.w * MAX_EMISSION;
+	g.normal = signedOctDecode(comp.xyw);
+	g.emission = comp.z * MAX_EMISSION;
 
 	// Fix values
 	g.specular = mix(g.specular, g.diffuse, g.metallic);

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

@@ -11,6 +11,6 @@ namespace anki
 const Array<PixelFormat, GBUFFER_COLOR_ATTACHMENT_COUNT> MS_COLOR_ATTACHMENT_PIXEL_FORMATS = {
 	{PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM),
 		PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM),
-		PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM)}};
+		PixelFormat(ComponentFormat::R10G10B10A2, TransformFormat::UNORM)}};
 
 } // end namespace anki

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

@@ -48,7 +48,7 @@ Error GBuffer::initInternal(const ConfigSet& initializer)
 	{
 		m_colorRtDescrs[i] = m_r->create2DRenderTargetDescription(m_r->getWidth(),
 			m_r->getHeight(),
-			MS_COLOR_ATTACHMENT_PIXEL_FORMATS[0],
+			MS_COLOR_ATTACHMENT_PIXEL_FORMATS[i],
 			TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 			SamplingFilter::NEAREST,
 			rtNames[i]);