From e799771a4087202fe72f2dc2c22dd4d8d47b3a38 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Wed, 9 Dec 2020 19:32:57 +0300 Subject: [PATCH] Deferred renderer: implement unlit transparent objects --- libs/gfx/source/renderer/deferred.cpp | 154 ++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 9 deletions(-) diff --git a/libs/gfx/source/renderer/deferred.cpp b/libs/gfx/source/renderer/deferred.cpp index 3bb3424d..23ed82de 100644 --- a/libs/gfx/source/renderer/deferred.cpp +++ b/libs/gfx/source/renderer/deferred.cpp @@ -497,6 +497,88 @@ void main() out_color = vec4(color, 1.0); } +)"; + + static char const transparent_pass_vs[] = +R"( + +uniform mat4 u_camera_transform; +uniform mat4x3 u_pre_transform; +uniform mat4x3 u_post_transform; + +layout (location = 0) in vec4 in_position; +layout (location = 1) in vec4 in_color; +layout (location = 2) in vec2 in_texcoord; +layout (location = 3) in vec3 in_normal; + +layout (location = 4) in mat3x4 in_instance_transform; + +out vec4 color; +out vec2 texcoord; + +void main() +{ + vec4 pos = in_position; + vec3 n = in_normal; + + if ((u_flag_mask & O_PRE_TRANSFORM) != 0u) + { + pos = vec4(u_pre_transform * pos, 1.0); + n = u_pre_transform * vec4(n, 0.0); + } + + if ((u_flag_mask & O_INSTANCED) != 0u) + { + pos = vec4(transpose(in_instance_transform) * pos, 1.0); + n = transpose(in_instance_transform) * vec4(n, 0.0); + } + + if ((u_flag_mask & O_POST_TRANSFORM) != 0u) + { + pos = vec4(u_post_transform * pos, 1.0); + n = u_post_transform * vec4(n, 0.0); + } + + gl_Position = u_camera_transform * pos; + + color = in_color; + texcoord = in_texcoord; +} +)"; + + static char const transparent_pass_fs[] = +R"( + +uniform vec4 u_color; +uniform sampler2D u_texture; +uniform float u_max_intensity; + +in vec4 color; +in vec2 texcoord; + +layout (location = 0) out vec4 out_color; + +void main() +{ + vec4 albedo; + if ((u_flag_mask & O_TEXTURE_COLOR) != 0u) + { + vec4 base_color = texture(u_texture, texcoord); + if ((u_flag_mask & O_UNIFORM_COLOR) != 0u) + albedo = u_color * base_color; + else + albedo = base_color; + } + else + { + if ((u_flag_mask & O_UNIFORM_COLOR) != 0u) + albedo = u_color; + else + albedo = color; + } + + out_color = vec4(albedo.rgb / u_max_intensity, albedo.a); +} )"; static std::size_t bbox_to_screen_fan(geom::matrix const & camera_transform, geom::box const & b, geom::point * result) @@ -558,6 +640,7 @@ void main() gfx::program point_light_pass_program{screen_vs, std::string(light_common) + point_light_pass_fs}; gfx::program shadow_builder_program{std::string(g_buffer_pass_common) + shadow_builder_vs, shadow_builder_fs}; gfx::program cubemap_shadow_builder_program{std::string(g_buffer_pass_common) + shadow_builder_vs, shadow_builder_gs, shadow_builder_fs}; + gfx::program transparent_pass_program{std::string(g_buffer_pass_common) + transparent_pass_vs, std::string(g_buffer_pass_common) + transparent_pass_fs}; // G-buffer attachments: // 0 - position (rbg) @@ -569,6 +652,9 @@ void main() gfx::texture_2d g_buffer_texture[4]; gfx::texture_2d g_buffer_depth; + // Only albedo & depth attached + gfx::framebuffer transparent_framebuffer; + std::optional> g_buffer_size; gfx::framebuffer directional_shadow_framebuffer; @@ -688,7 +774,8 @@ void main() auto const & o = objects[i]; assert(o.mesh); - if (o.mat.transparent) throw std::runtime_error("Transparency is not supported yet"); + if (o.mat.lit && o.mat.transparent) + throw std::runtime_error("Materials that are both tit & transparent are not supported"); objects_by_mask[mask(objects[i])].push_back(i); @@ -726,6 +813,10 @@ void main() impl().g_framebuffer.assert_complete(); + impl().transparent_framebuffer.color(impl().g_buffer_texture[1]); + impl().transparent_framebuffer.depth(impl().g_buffer_depth); + impl().transparent_framebuffer.assert_complete(); + impl().g_buffer_size = buffer_size; impl().position_mode_changed = false; } @@ -767,10 +858,13 @@ void main() for (auto const & p : objects_by_mask) { - if (p.second.empty()) continue; - std::uint32_t mask = p.first; + if (mask & O_TRANSPARENT) + continue; + + if (p.second.empty()) continue; + impl().g_buffer_pass_program["u_flag_mask"] = mask; for (std::size_t i : p.second) @@ -798,6 +892,54 @@ void main() } } + // Render unlit transparent objects + + impl().transparent_framebuffer.bind(); + impl().transparent_pass_program.bind(); + impl().transparent_pass_program["u_camera_transform"] = camera_transform; + impl().transparent_pass_program["u_max_intensity"] = opts.max_intensity; + + gl::Enable(gl::BLEND); + gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ZERO); + + gl::DepthMask(gl::FALSE); + + for (auto const & p : objects_by_mask) + { + std::uint32_t mask = p.first; + + if (!(mask & O_TRANSPARENT)) + continue; + + if (p.second.empty()) continue; + + impl().transparent_pass_program["u_flag_mask"] = mask; + + for (std::size_t i : p.second) + { + auto const & o = objects[i]; + + if (mask & O_UNIFORM_COLOR) + impl().transparent_pass_program["u_color"] = *o.mat.color; + + if (mask & O_TEXTURE_COLOR) + { + gl::ActiveTexture(gl::TEXTURE0); + o.mat.texture->bind(); + } + + if (mask & O_PRE_TRANSFORM) + impl().transparent_pass_program["u_pre_transform"] = *o.pre_transform; + + if (mask & O_POST_TRANSFORM) + impl().transparent_pass_program["u_post_transform"] = *o.post_transform; + + o.mesh->draw(); + } + } + + gl::DepthMask(gl::TRUE); + // Setup destination framebuffer target.bind(); @@ -1054,12 +1196,6 @@ void main() impl().cubemap_shadow_builder_program.bind(); impl().cubemap_shadow_builder_program["u_light_transform"] = geom::matrix::identity(); -// impl().cubemap_shadow_builder_program["u_layer_transform[0]"] = geom::matrix::identity(); -// impl().cubemap_shadow_builder_program["u_layer_transform[1]"] = geom::matrix::identity(); -// impl().cubemap_shadow_builder_program["u_layer_transform[2]"] = geom::matrix::identity(); -// impl().cubemap_shadow_builder_program["u_layer_transform[3]"] = geom::matrix::identity(); -// impl().cubemap_shadow_builder_program["u_layer_transform[4]"] = geom::matrix::identity(); -// impl().cubemap_shadow_builder_program["u_layer_transform[5]"] = geom::matrix::identity(); impl().cubemap_shadow_builder_program["u_layer_transform[0]"] = transform[0] * translate_by_light; impl().cubemap_shadow_builder_program["u_layer_transform[1]"] = transform[1] * translate_by_light;