From 1b8ef017add989b7df9dd6ed8ca60c993cf492ed Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 25 Oct 2020 21:29:53 +0300 Subject: [PATCH] Compress normals to 32-bit integers in deferred renderer --- libs/gfx/source/renderer/deferred.cpp | 145 +++++++++++++++++++------- 1 file changed, 109 insertions(+), 36 deletions(-) diff --git a/libs/gfx/source/renderer/deferred.cpp b/libs/gfx/source/renderer/deferred.cpp index 68bd618f..ad133102 100644 --- a/libs/gfx/source/renderer/deferred.cpp +++ b/libs/gfx/source/renderer/deferred.cpp @@ -95,9 +95,58 @@ in vec3 normal; layout (location = 0) out vec3 out0; layout (location = 1) out vec4 out1; -layout (location = 2) out vec3 out2; +layout (location = 2) out uint out2; layout (location = 3) out vec3 out3; +uint pack_normal(vec3 n) +{ + uint face = 0u; + + float a0, a1; + + vec3 an = abs(n); + + if (an.x > an.y) + { + if (an.x > an.z) + { + bool p = (n.x > 0.0); + face = p ? 1u : 6u; + a0 = (p ? n.y : n.z) / an.x; + a1 = (p ? n.z : n.y) / an.x; + } + else + { + bool p = (n.z > 0.0); + face = p ? 4u : 3u; + a0 = (p ? n.x : n.y) / an.z; + a1 = (p ? n.y : n.x) / an.z; + } + } + else + { + if (an.y > an.z) + { + bool p = (n.y > 0.0); + face = p ? 2u : 5u; + a0 = (p ? n.z : n.x) / an.y; + a1 = (p ? n.x : n.z) / an.y; + } + else + { + bool p = (n.z > 0.0); + face = p ? 4u : 3u; + a0 = (p ? n.x : n.y) / an.z; + a1 = (p ? n.y : n.x) / an.z; + } + } + + uint v0 = uint((a0 * 0.5 + 0.5) * float(1 << 15)); + uint v1 = uint((a1 * 0.5 + 0.5) * float(1 << 14)); + + return (face << 29u) | (v1 << 15u) | v0; +} + void main() { vec4 albedo; @@ -119,7 +168,7 @@ void main() out0 = position; out1 = vec4(albedo.rgb / u_max_intensity, (u_flag_mask & O_LIT) != 0u ? 1.f : 0.f); - out2 = normalize(normal) * 0.5 + vec3(0.5); + out2 = pack_normal(normalize(normal)); out3 = u_material; } )"; @@ -162,22 +211,66 @@ void main() } )"; - static char const ambient_pass_fs[] = + + static char const light_common[] = R"(#version 330 uniform sampler2D u_g0; uniform sampler2D u_g1; -uniform sampler2D u_g2; +uniform usampler2D u_g2; uniform sampler2D u_g3; -uniform vec3 u_ambient; - -uniform float u_max_intensity; in vec2 texcoord; out vec4 out_color; +vec3 unpack_normal(uint v) +{ + uint v0 = v & ((1u << 15) - 1u); + uint v1 = (v >> 15) & ((1u << 14) - 1u); + uint face = (v >> 29) & 7u; + + float a0 = 2.0 * float(v0) / float(1 << 15) - 1.0; + float a1 = 2.0 * float(v1) / float(1 << 14) - 1.0; + + if (face == 1u) + { + return normalize(vec3(1.0, a0, a1)); + } + else if (face == 2u) + { + return normalize(vec3(a1, 1.0, a0)); + } + else if (face == 3u) + { + return normalize(vec3(a1, a0, -1.0)); + } + else if (face == 4u) + { + return normalize(vec3(a0, a1, 1.0)); + } + else if (face == 5u) + { + return normalize(vec3(a0, -1.0, a1)); + } + else if (face == 6u) + { + return normalize(vec3(-1.0, a1, a0)); + } + + return vec3(0.0, 0.0, 0.0); +} + +)"; + + static char const ambient_pass_fs[] = +R"( + +uniform vec3 u_ambient; + +uniform float u_max_intensity; + void main() { vec4 albedo = texture(u_g1, texcoord); @@ -194,12 +287,7 @@ void main() )"; static char const directional_light_pass_fs[] = -R"(#version 330 - -uniform sampler2D u_g0; -uniform sampler2D u_g1; -uniform sampler2D u_g2; -uniform sampler2D u_g3; +R"( uniform vec3 u_light_direction; uniform vec3 u_light_color; @@ -208,15 +296,11 @@ uniform vec3 u_camera_position; uniform float u_max_intensity; -in vec2 texcoord; - -out vec4 out_color; - void main() { vec3 position = texture(u_g0, texcoord).xyz; vec4 albedo = texture(u_g1, texcoord); - vec3 normal = texture(u_g2, texcoord).xyz * 2.0 - vec3(1.0); + vec3 normal = unpack_normal(texture(u_g2, texcoord).r); vec3 material = texture(u_g3, texcoord).xyz; vec3 view = normalize(u_camera_position - position); @@ -234,12 +318,7 @@ void main() )"; static char const point_light_pass_fs[] = -R"(#version 330 - -uniform sampler2D u_g0; -uniform sampler2D u_g1; -uniform sampler2D u_g2; -uniform sampler2D u_g3; +R"( uniform vec3 u_light_position; uniform vec3 u_light_color; @@ -249,15 +328,11 @@ uniform vec3 u_camera_position; uniform float u_max_intensity; -in vec2 texcoord; - -out vec4 out_color; - void main() { vec3 position = texture(u_g0, texcoord).xyz; vec4 albedo = texture(u_g1, texcoord); - vec3 normal = texture(u_g2, texcoord).xyz * 2.0 - vec3(1.0); + vec3 normal = unpack_normal(texture(u_g2, texcoord).r); vec3 material = texture(u_g3, texcoord).xyz; vec3 view = normalize(u_camera_position - position); @@ -331,14 +406,14 @@ void main() struct deferred_renderer::impl { gfx::program g_buffer_pass_program{std::string(g_buffer_pass_common) + g_buffer_pass_vs, std::string(g_buffer_pass_common) + g_buffer_pass_fs}; - gfx::program ambient_pass_program{fullscreen_vs, ambient_pass_fs}; - gfx::program directional_light_pass_program{screen_vs, directional_light_pass_fs}; - gfx::program point_light_pass_program{screen_vs, point_light_pass_fs}; + gfx::program ambient_pass_program{fullscreen_vs, std::string(light_common) + ambient_pass_fs}; + gfx::program directional_light_pass_program{screen_vs, std::string(light_common) + directional_light_pass_fs}; + gfx::program point_light_pass_program{screen_vs, std::string(light_common) + point_light_pass_fs}; // G-buffer attachments: // 0 - position (rbg) // 1 - albedo (rgb), lit (a) - // 2 - normal (rgb) + // 2 - normal (packed) // 3 - material.diffuse (r), material.specular (g), material.shininess (b) gfx::framebuffer g_framebuffer; @@ -440,11 +515,9 @@ void main() auto buffer_size = geom::cast(target.viewport.dimensions()); if (!impl().g_buffer_size || *impl().g_buffer_size != buffer_size) { - // TODO: compact normals storage - impl().g_buffer_texture[0].load>(buffer_size); impl().g_buffer_texture[1].load>(buffer_size); - impl().g_buffer_texture[2].load>(buffer_size); + impl().g_buffer_texture[2].load>(buffer_size); impl().g_buffer_texture[3].load>(buffer_size); impl().g_buffer_depth.load(buffer_size);