Implement SSAO in deferred renderer
This commit is contained in:
parent
077a95e78b
commit
c8c5e874da
3 changed files with 354 additions and 134 deletions
|
|
@ -6,7 +6,7 @@ file(GLOB_RECURSE PSEMEK_GFX_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "sou
|
|||
|
||||
add_library(psemek-gfx ${PSEMEK_GFX_HEADERS} ${PSEMEK_GFX_SOURCES})
|
||||
target_include_directories(psemek-gfx PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(psemek-gfx PUBLIC psemek-util psemek-geom psemek-cg OpenGL::GL)
|
||||
target_link_libraries(psemek-gfx PUBLIC psemek-util psemek-geom psemek-cg psemek-random OpenGL::GL)
|
||||
|
||||
psemek_add_resources(psemek-gfx
|
||||
resources/font_9x12.pbm psemek/gfx/resource/font_9x12
|
||||
|
|
|
|||
|
|
@ -108,6 +108,14 @@ namespace psemek::gfx
|
|||
};
|
||||
|
||||
std::optional<bloom_data> bloom;
|
||||
|
||||
struct ssao_data
|
||||
{
|
||||
float radius;
|
||||
std::size_t downsample = 2;
|
||||
};
|
||||
|
||||
std::optional<ssao_data> ssao;
|
||||
};
|
||||
|
||||
void render(std::vector<object> const & objects, render_target const & target, options const & opts);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
#include <psemek/gfx/effect/blur.hpp>
|
||||
#include <psemek/gfx/effect/overlay.hpp>
|
||||
|
||||
#include <psemek/random/generator.hpp>
|
||||
#include <psemek/random/uniform_hemiball.hpp>
|
||||
#include <psemek/random/uniform_sphere.hpp>
|
||||
|
||||
#include <psemek/geom/homogeneous.hpp>
|
||||
#include <psemek/geom/gram_schmidt.hpp>
|
||||
#include <psemek/geom/translation.hpp>
|
||||
|
|
@ -15,6 +19,8 @@
|
|||
|
||||
#include <psemek/cg/convex_hull_2d/graham.hpp>
|
||||
|
||||
#include <psemek/util/to_string.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace psemek::gfx
|
||||
|
|
@ -181,66 +187,66 @@ void main()
|
|||
}
|
||||
)";
|
||||
|
||||
static char const shadow_builder_vs[] =
|
||||
R"(
|
||||
uniform mat4 u_light_transform;
|
||||
uniform mat4x3 u_pre_transform;
|
||||
uniform mat4x3 u_post_transform;
|
||||
static char const shadow_builder_vs[] =
|
||||
R"(
|
||||
uniform mat4 u_light_transform;
|
||||
uniform mat4x3 u_pre_transform;
|
||||
uniform mat4x3 u_post_transform;
|
||||
|
||||
layout (location = 0) in vec4 in_position;
|
||||
layout (location = 0) in vec4 in_position;
|
||||
|
||||
layout (location = 4) in mat3x4 in_instance_transform;
|
||||
layout (location = 4) in mat3x4 in_instance_transform;
|
||||
|
||||
void main()
|
||||
void main()
|
||||
{
|
||||
vec4 pos = in_position;
|
||||
|
||||
if ((u_flag_mask & O_PRE_TRANSFORM) != 0u)
|
||||
{
|
||||
vec4 pos = in_position;
|
||||
|
||||
if ((u_flag_mask & O_PRE_TRANSFORM) != 0u)
|
||||
{
|
||||
pos = vec4(u_pre_transform * pos, 1.0);
|
||||
}
|
||||
|
||||
if ((u_flag_mask & O_INSTANCED) != 0u)
|
||||
{
|
||||
pos = vec4(transpose(in_instance_transform) * pos, 1.0);
|
||||
}
|
||||
|
||||
if ((u_flag_mask & O_POST_TRANSFORM) != 0u)
|
||||
{
|
||||
pos = vec4(u_post_transform * pos, 1.0);
|
||||
}
|
||||
|
||||
gl_Position = u_light_transform * pos;
|
||||
pos = vec4(u_pre_transform * pos, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
static char const shadow_builder_gs[] =
|
||||
R"(#version 330
|
||||
|
||||
uniform mat4 u_layer_transform[6];
|
||||
|
||||
layout (triangles) in;
|
||||
layout (triangle_strip, max_vertices = 18) out;
|
||||
|
||||
void main()
|
||||
if ((u_flag_mask & O_INSTANCED) != 0u)
|
||||
{
|
||||
for (int face = 0; face < 6; ++face)
|
||||
{
|
||||
gl_Layer = face;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
gl_Position = u_layer_transform[face] * gl_in[i].gl_Position;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
pos = vec4(transpose(in_instance_transform) * pos, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
static char const shadow_builder_fs[] =
|
||||
R"(#version 330
|
||||
void main(){}
|
||||
)";
|
||||
if ((u_flag_mask & O_POST_TRANSFORM) != 0u)
|
||||
{
|
||||
pos = vec4(u_post_transform * pos, 1.0);
|
||||
}
|
||||
|
||||
gl_Position = u_light_transform * pos;
|
||||
}
|
||||
)";
|
||||
|
||||
static char const shadow_builder_gs[] =
|
||||
R"(#version 330
|
||||
|
||||
uniform mat4 u_layer_transform[6];
|
||||
|
||||
layout (triangles) in;
|
||||
layout (triangle_strip, max_vertices = 18) out;
|
||||
|
||||
void main()
|
||||
{
|
||||
for (int face = 0; face < 6; ++face)
|
||||
{
|
||||
gl_Layer = face;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
gl_Position = u_layer_transform[face] * gl_in[i].gl_Position;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
static char const shadow_builder_fs[] =
|
||||
R"(#version 330
|
||||
void main(){}
|
||||
)";
|
||||
|
||||
static char const fullscreen_vs[] =
|
||||
R"(#version 330
|
||||
|
|
@ -337,6 +343,8 @@ vec3 unpack_normal(uint v)
|
|||
R"(
|
||||
|
||||
uniform vec3 u_ambient;
|
||||
uniform sampler2D u_ssao_texture;
|
||||
uniform int u_use_ssao;
|
||||
|
||||
uniform float u_max_intensity;
|
||||
|
||||
|
|
@ -348,6 +356,8 @@ void main()
|
|||
|
||||
if (albedo.a < 0.5)
|
||||
color = albedo.rgb;
|
||||
else if (u_use_ssao == 1)
|
||||
color = albedo.rgb * u_ambient * texture(u_ssao_texture, texcoord).r;
|
||||
else
|
||||
color = albedo.rgb * u_ambient;
|
||||
|
||||
|
|
@ -582,6 +592,58 @@ void main()
|
|||
|
||||
out_color = vec4(albedo.rgb / u_max_intensity, albedo.a);
|
||||
}
|
||||
)";
|
||||
|
||||
static char const ssao_pass_fs[] =
|
||||
R"(
|
||||
|
||||
uniform sampler2D u_ssao_rotation;
|
||||
uniform vec2 u_ssao_rotation_step;
|
||||
|
||||
uniform float u_ssao_radius;
|
||||
|
||||
uniform vec3 u_ssao_kernel[16];
|
||||
|
||||
uniform mat4 u_view;
|
||||
uniform mat4 u_transform;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 albedo = texture(u_g1, texcoord);
|
||||
if (albedo.a < 0.5)
|
||||
{
|
||||
out_color = vec4(1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 position = texture(u_g0, texcoord).xyz;
|
||||
vec3 normal = unpack_normal(texture(u_g2, texcoord).r);
|
||||
|
||||
vec3 tangent = texture(u_ssao_rotation, texcoord * u_ssao_rotation_step).xyz;
|
||||
tangent = normalize(tangent - normal * dot(normal, tangent));
|
||||
vec3 bitangent = cross(normal, tangent);
|
||||
|
||||
mat3 tbn = mat3(tangent, bitangent, normal);
|
||||
|
||||
float occlusion = 0.0;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
vec3 sample = position + (tbn * u_ssao_kernel[i]) * u_ssao_radius;
|
||||
|
||||
vec4 clip = u_transform * vec4(sample, 1.0);
|
||||
clip.xy /= clip.w;
|
||||
clip.xy = clip.xy * 0.5 + vec2(0.5);
|
||||
|
||||
vec3 pos = texture(u_g0, clip.xy).xyz;
|
||||
|
||||
float w = length(pos - position) / u_ssao_radius;
|
||||
|
||||
if (w <= 1.0 && dot(pos - position, normal) >= 0.f && (u_view * vec4(pos, 1.0)).z > (u_view * vec4(sample, 1.0)).z)
|
||||
occlusion += 1.0 / 16.0;
|
||||
}
|
||||
|
||||
out_color = vec4(1.0 - occlusion);
|
||||
}
|
||||
)";
|
||||
|
||||
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)
|
||||
|
|
@ -645,6 +707,7 @@ void main()
|
|||
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};
|
||||
gfx::program bloom_pass_program{std::string(g_buffer_pass_common) + transparent_pass_vs, std::string(g_buffer_pass_common) + transparent_pass_fs};
|
||||
gfx::program ssao_pass_program{fullscreen_vs, std::string(light_common) + ssao_pass_fs};
|
||||
|
||||
// G-buffer attachments:
|
||||
// 0 - position (rbg)
|
||||
|
|
@ -680,6 +743,20 @@ void main()
|
|||
gfx::framebuffer bloom_framebuffer[3];
|
||||
gfx::texture_2d bloom_texture[3];
|
||||
|
||||
gfx::texture_2d ssao_rotation_texture;
|
||||
|
||||
std::optional<geom::vector<std::size_t, 2>> ssao_size;
|
||||
std::optional<std::size_t> ssao_downsample;
|
||||
|
||||
// 0: original, unblurred ssao
|
||||
// 1: horizontally blurred ssao
|
||||
// 2: fully blurred ssao
|
||||
gfx::framebuffer ssao_framebuffer[3];
|
||||
gfx::texture_2d ssao_texture[3];
|
||||
|
||||
hblur ssao_hblur{2, 2.f};
|
||||
vblur ssao_vblur{2, 2.f};
|
||||
|
||||
gfx::mesh screen_mesh;
|
||||
};
|
||||
|
||||
|
|
@ -701,6 +778,7 @@ void main()
|
|||
impl().ambient_pass_program["u_g1"] = 1;
|
||||
impl().ambient_pass_program["u_g2"] = 2;
|
||||
impl().ambient_pass_program["u_g3"] = 3;
|
||||
impl().ambient_pass_program["u_ssao_texture"] = 4;
|
||||
|
||||
impl().directional_light_pass_program.bind();
|
||||
impl().directional_light_pass_program["u_g0"] = 0;
|
||||
|
|
@ -735,12 +813,57 @@ void main()
|
|||
impl().point_shadow_framebuffer.depth(impl().point_shadow_texture);
|
||||
impl().point_shadow_framebuffer.assert_complete();
|
||||
|
||||
impl().bloom_texture[0].linear_filter();
|
||||
impl().bloom_texture[1].linear_filter();
|
||||
impl().bloom_texture[2].linear_filter();
|
||||
impl().bloom_texture[0].clamp();
|
||||
impl().bloom_texture[1].clamp();
|
||||
impl().bloom_texture[2].clamp();
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
impl().bloom_texture[i].linear_filter();
|
||||
impl().bloom_texture[i].clamp();
|
||||
}
|
||||
|
||||
{
|
||||
// params are random
|
||||
random::generator rng{0xaa8e8eabull, 0x44a700e7ull};
|
||||
|
||||
{
|
||||
random::uniform_hemiball_vector_distribution<float, 3> d{geom::vector{0.f, 0.f, 1.f}};
|
||||
std::vector<geom::vector<float, 3>> ssao_kernel(16);
|
||||
for (auto & v : ssao_kernel)
|
||||
v = d(rng);
|
||||
|
||||
impl().ssao_pass_program.bind();
|
||||
for (std::size_t i = 0; i < ssao_kernel.size(); ++i)
|
||||
{
|
||||
impl().ssao_pass_program[util::to_string("u_ssao_kernel[", i, "]").data()] = ssao_kernel[i];
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
random::uniform_sphere_vector_distribution<float, 2> d;
|
||||
|
||||
basic_pixmap<geom::vector<float, 2>> pm({8, 8});
|
||||
for (auto & v : pm)
|
||||
v = d(rng);
|
||||
|
||||
impl().ssao_rotation_texture.load(pm);
|
||||
impl().ssao_rotation_texture.nearest_filter();
|
||||
impl().ssao_rotation_texture.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
impl().ssao_texture[i].linear_filter();
|
||||
impl().ssao_texture[i].clamp();
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_SWIZZLE_G, gl::RED);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_SWIZZLE_B, gl::RED);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_SWIZZLE_A, gl::RED);
|
||||
}
|
||||
|
||||
impl().ssao_pass_program.bind();
|
||||
impl().ssao_pass_program["u_g0"] = 0;
|
||||
impl().ssao_pass_program["u_g1"] = 1;
|
||||
impl().ssao_pass_program["u_g2"] = 2;
|
||||
impl().ssao_pass_program["u_g3"] = 3;
|
||||
impl().ssao_pass_program["u_ssao_rotation"] = 4;
|
||||
|
||||
impl().screen_mesh.setup<geom::point<float, 2>>();
|
||||
}
|
||||
|
|
@ -873,6 +996,20 @@ void main()
|
|||
impl().bloom_downsample = opts.bloom->downsample;
|
||||
}
|
||||
|
||||
bool const ssao_size_changed = opts.ssao && (!impl().ssao_size || *impl().ssao_size != buffer_size || !impl().ssao_downsample || *impl().ssao_downsample != opts.ssao->downsample);
|
||||
if (ssao_size_changed)
|
||||
{
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
impl().ssao_texture[i].load<std::uint8_t>(buffer_size / opts.ssao->downsample);
|
||||
impl().ssao_framebuffer[i].color(impl().ssao_texture[i]);
|
||||
impl().ssao_framebuffer[i].assert_complete();
|
||||
}
|
||||
|
||||
impl().ssao_size = buffer_size;
|
||||
impl().ssao_downsample = opts.ssao->downsample;
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::size_t, float>> hblur_params;
|
||||
std::optional<std::pair<std::size_t, float>> vblur_params;
|
||||
|
||||
|
|
@ -1014,104 +1151,111 @@ void main()
|
|||
|
||||
// Render bloom
|
||||
|
||||
impl().bloom_framebuffer[0].bind();
|
||||
|
||||
gl::ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
gl::DepthFunc(gl::LEQUAL);
|
||||
|
||||
gl::Disable(gl::BLEND);
|
||||
|
||||
impl().bloom_pass_program.bind();
|
||||
impl().bloom_pass_program["u_camera_transform"] = camera_transform;
|
||||
impl().bloom_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
|
||||
for (auto const & p : objects_by_mask)
|
||||
if (opts.bloom)
|
||||
{
|
||||
std::uint32_t mask = p.first;
|
||||
impl().bloom_framebuffer[0].bind();
|
||||
|
||||
if (!(mask & O_BLOOMING))
|
||||
continue;
|
||||
gl::ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
if (p.second.empty()) continue;
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
gl::DepthFunc(gl::LEQUAL);
|
||||
|
||||
impl().bloom_pass_program["u_flag_mask"] = mask;
|
||||
gl::Disable(gl::BLEND);
|
||||
|
||||
for (std::size_t i : p.second)
|
||||
impl().bloom_pass_program.bind();
|
||||
impl().bloom_pass_program["u_camera_transform"] = camera_transform;
|
||||
impl().bloom_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
|
||||
for (auto const & p : objects_by_mask)
|
||||
{
|
||||
auto const & o = objects[i];
|
||||
std::uint32_t mask = p.first;
|
||||
|
||||
if (mask & O_UNIFORM_COLOR)
|
||||
impl().bloom_pass_program["u_color"] = *o.mat.color;
|
||||
if (!(mask & O_BLOOMING))
|
||||
continue;
|
||||
|
||||
if (mask & O_TEXTURE_COLOR)
|
||||
if (p.second.empty()) continue;
|
||||
|
||||
impl().bloom_pass_program["u_flag_mask"] = mask;
|
||||
|
||||
for (std::size_t i : p.second)
|
||||
{
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
o.mat.texture->bind();
|
||||
auto const & o = objects[i];
|
||||
|
||||
if (mask & O_UNIFORM_COLOR)
|
||||
impl().bloom_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().bloom_pass_program["u_pre_transform"] = *o.pre_transform;
|
||||
|
||||
if (mask & O_POST_TRANSFORM)
|
||||
impl().bloom_pass_program["u_post_transform"] = *o.post_transform;
|
||||
|
||||
impl().bloom_pass_program["u_material"] = geom::vector<float, 3>{o.mat.diffuse, o.mat.specular.intensity, o.mat.specular.shininess};
|
||||
|
||||
o.mesh->draw();
|
||||
}
|
||||
|
||||
if (mask & O_PRE_TRANSFORM)
|
||||
impl().bloom_pass_program["u_pre_transform"] = *o.pre_transform;
|
||||
|
||||
if (mask & O_POST_TRANSFORM)
|
||||
impl().bloom_pass_program["u_post_transform"] = *o.post_transform;
|
||||
|
||||
impl().bloom_pass_program["u_material"] = geom::vector<float, 3>{o.mat.diffuse, o.mat.specular.intensity, o.mat.specular.shininess};
|
||||
|
||||
o.mesh->draw();
|
||||
}
|
||||
}
|
||||
|
||||
// Render unlit transparent objects to bloom
|
||||
|
||||
impl().transparent_pass_program.bind();
|
||||
impl().transparent_pass_program["u_camera_transform"] = camera_transform;
|
||||
impl().transparent_pass_program["u_max_intensity"] = 1.f;
|
||||
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ZERO, gl::ONE);
|
||||
|
||||
for (auto const & p : objects_by_mask)
|
||||
if (opts.bloom)
|
||||
{
|
||||
std::uint32_t mask = p.first;
|
||||
impl().transparent_pass_program.bind();
|
||||
impl().transparent_pass_program["u_camera_transform"] = camera_transform;
|
||||
impl().transparent_pass_program["u_max_intensity"] = 1.f;
|
||||
|
||||
if (!(mask & O_TRANSPARENT))
|
||||
continue;
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ZERO, gl::ONE);
|
||||
|
||||
if (p.second.empty()) continue;
|
||||
|
||||
impl().transparent_pass_program["u_flag_mask"] = mask;
|
||||
|
||||
for (std::size_t i : p.second)
|
||||
for (auto const & p : objects_by_mask)
|
||||
{
|
||||
auto const & o = objects[i];
|
||||
std::uint32_t mask = p.first;
|
||||
|
||||
if (mask & O_UNIFORM_COLOR)
|
||||
impl().transparent_pass_program["u_color"] = *o.mat.color;
|
||||
if (!(mask & O_TRANSPARENT))
|
||||
continue;
|
||||
|
||||
if (mask & O_TEXTURE_COLOR)
|
||||
if (p.second.empty()) continue;
|
||||
|
||||
impl().transparent_pass_program["u_flag_mask"] = mask;
|
||||
|
||||
for (std::size_t i : p.second)
|
||||
{
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
o.mat.texture->bind();
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
gl::Disable(gl::BLEND);
|
||||
gl::DepthMask(gl::TRUE);
|
||||
gl::Disable(gl::BLEND);
|
||||
}
|
||||
|
||||
// Apply horizontal blur to bloom
|
||||
|
||||
if (opts.bloom)
|
||||
{
|
||||
render_target target;
|
||||
target.framebuffer = &impl().bloom_framebuffer[1];
|
||||
|
|
@ -1127,6 +1271,7 @@ void main()
|
|||
|
||||
// Apply vertical blur to bloom
|
||||
|
||||
if (opts.bloom)
|
||||
{
|
||||
render_target target;
|
||||
target.framebuffer = &impl().bloom_framebuffer[2];
|
||||
|
|
@ -1140,12 +1285,7 @@ void main()
|
|||
impl().vblur_container.at(*vblur_params).invoke(impl().bloom_texture[1], target);
|
||||
}
|
||||
|
||||
// Setup destination framebuffer
|
||||
|
||||
target.bind();
|
||||
|
||||
gl::Disable(gl::DEPTH_TEST);
|
||||
gl::Disable(gl::BLEND);
|
||||
// Bind g-buffer textures
|
||||
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
impl().g_buffer_texture[0].bind();
|
||||
|
|
@ -1156,6 +1296,68 @@ void main()
|
|||
gl::ActiveTexture(gl::TEXTURE3);
|
||||
impl().g_buffer_texture[3].bind();
|
||||
|
||||
gl::Disable(gl::DEPTH_TEST);
|
||||
gl::Disable(gl::BLEND);
|
||||
|
||||
// Generate SSAO
|
||||
|
||||
if (opts.ssao)
|
||||
{
|
||||
impl().ssao_framebuffer[0].bind();
|
||||
gl::Viewport(0, 0, impl().ssao_texture[0].width(), impl().ssao_texture[0].height());
|
||||
gl::ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
impl().ssao_pass_program.bind();
|
||||
gl::ActiveTexture(gl::TEXTURE4);
|
||||
impl().ssao_rotation_texture.bind();
|
||||
impl().ssao_pass_program["u_ssao_rotation_step"] = geom::cast<float>(impl().ssao_texture[0].size()) / (1.f * impl().ssao_rotation_texture.width());
|
||||
impl().ssao_pass_program["u_ssao_radius"] = opts.ssao->radius;
|
||||
impl().ssao_pass_program["u_transform"] = camera_transform;
|
||||
impl().ssao_pass_program["u_view"] = opts.camera->view();
|
||||
|
||||
gl::DrawArrays(gl::TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
// Blur ssao horizontally
|
||||
|
||||
if (opts.ssao)
|
||||
{
|
||||
render_target target;
|
||||
target.framebuffer = &impl().ssao_framebuffer[1];
|
||||
target.draw_buffer = gl::COLOR_ATTACHMENT0;
|
||||
target.viewport = {{{0, impl().ssao_texture[1].width()}, {0, impl().ssao_texture[1].height()}}};
|
||||
|
||||
target.bind();
|
||||
gl::ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
impl().ssao_hblur.invoke(impl().ssao_texture[0], target);
|
||||
}
|
||||
|
||||
// Blur ssao vertically
|
||||
|
||||
if (opts.ssao)
|
||||
{
|
||||
render_target target;
|
||||
target.framebuffer = &impl().ssao_framebuffer[2];
|
||||
target.draw_buffer = gl::COLOR_ATTACHMENT0;
|
||||
target.viewport = {{{0, impl().ssao_texture[2].width()}, {0, impl().ssao_texture[2].height()}}};
|
||||
|
||||
target.bind();
|
||||
gl::ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||
|
||||
impl().ssao_vblur.invoke(impl().ssao_texture[1], target);
|
||||
}
|
||||
|
||||
// Setup destination framebuffer
|
||||
|
||||
gl::ActiveTexture(gl::TEXTURE0);
|
||||
impl().g_buffer_texture[0].bind();
|
||||
|
||||
target.bind();
|
||||
|
||||
impl().screen_mesh.bind();
|
||||
|
||||
// Draw unlit & ambient layers
|
||||
|
|
@ -1163,6 +1365,16 @@ void main()
|
|||
impl().ambient_pass_program.bind();
|
||||
impl().ambient_pass_program["u_ambient"] = opts.ambient;
|
||||
impl().ambient_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
if (opts.ssao)
|
||||
{
|
||||
gl::ActiveTexture(gl::TEXTURE4);
|
||||
impl().ssao_texture[2].bind();
|
||||
impl().ambient_pass_program["u_use_ssao"] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
impl().ambient_pass_program["u_use_ssao"] = 0;
|
||||
}
|
||||
gl::DrawArrays(gl::TRIANGLES, 0, 6);
|
||||
|
||||
// Directional lights
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue