Deferred renderer: implement unlit transparent objects

This commit is contained in:
Nikita Lisitsa 2020-12-09 19:32:57 +03:00
parent 167f979285
commit e799771a40

View file

@ -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<float, 4, 4> const & camera_transform, geom::box<float, 3> const & b, geom::point<float, 2> * 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<geom::vector<std::size_t, 2>> 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<float, 4, 4>::identity();
// impl().cubemap_shadow_builder_program["u_layer_transform[0]"] = geom::matrix<float, 4, 4>::identity();
// impl().cubemap_shadow_builder_program["u_layer_transform[1]"] = geom::matrix<float, 4, 4>::identity();
// impl().cubemap_shadow_builder_program["u_layer_transform[2]"] = geom::matrix<float, 4, 4>::identity();
// impl().cubemap_shadow_builder_program["u_layer_transform[3]"] = geom::matrix<float, 4, 4>::identity();
// impl().cubemap_shadow_builder_program["u_layer_transform[4]"] = geom::matrix<float, 4, 4>::identity();
// impl().cubemap_shadow_builder_program["u_layer_transform[5]"] = geom::matrix<float, 4, 4>::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;