Compress normals to 32-bit integers in deferred renderer

This commit is contained in:
Nikita Lisitsa 2020-10-25 21:29:53 +03:00
parent e7427e1d58
commit 1b8ef017ad

View file

@ -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<std::size_t>(target.viewport.dimensions());
if (!impl().g_buffer_size || *impl().g_buffer_size != buffer_size)
{
// TODO: compact normals storage
impl().g_buffer_texture[0].load<geom::vector<gfx::float16, 3>>(buffer_size);
impl().g_buffer_texture[1].load<geom::vector<std::uint16_t, 4>>(buffer_size);
impl().g_buffer_texture[2].load<geom::vector<gfx::float16, 3>>(buffer_size);
impl().g_buffer_texture[2].load<gfx::integer<std::uint32_t>>(buffer_size);
impl().g_buffer_texture[3].load<geom::vector<gfx::float16, 3>>(buffer_size);
impl().g_buffer_depth.load<gfx::depth24_pixel>(buffer_size);