Implement directional & point light shadows in deferred renderer
This commit is contained in:
parent
226192e264
commit
98a015fbed
3 changed files with 471 additions and 18 deletions
|
|
@ -337,6 +337,7 @@ void deferred_app::render()
|
|||
obj.mesh = &plane;
|
||||
obj.pre_transform = geom::scale<float, 3>(10.f).affine_matrix();
|
||||
obj.bbox = {{{-10.f, 10.f}, {-10.f, 10.f}, {0.f, 0.f}}};
|
||||
obj.casts_shadow = false;
|
||||
objects.push_back(obj);
|
||||
}
|
||||
|
||||
|
|
@ -387,16 +388,19 @@ void deferred_app::render()
|
|||
options.point_lights[0].color = {20.f, 0.f, 0.f};
|
||||
options.point_lights[0].position = {2.f * std::cos(time / 2.f), 2.f * std::sin(time / 2.f), 2.f};
|
||||
options.point_lights[0].attenuation = {1.f, 0.1f, 0.05f};
|
||||
options.point_lights[0].min_shadow_distance = 0.1f;
|
||||
|
||||
options.point_lights.emplace_back();
|
||||
options.point_lights[1].color = {0.f, 0.f, 20.f};
|
||||
options.point_lights[1].position = {-6.f * std::cos(time / 2.f), -6.f * std::sin(time / 2.f), 2.f};
|
||||
options.point_lights[1].position = {-6.f * std::cos(time / 1.f), -6.f * std::sin(time / 1.f), 2.f};
|
||||
options.point_lights[1].attenuation = {1.f, 0.1f, 0.05f};
|
||||
options.point_lights[1].min_shadow_distance = 0.1f;
|
||||
|
||||
options.point_lights.emplace_back();
|
||||
options.point_lights[2].color = {0.f, 20.f, 0.f};
|
||||
options.point_lights[2].position = {0.f, 0.f, 4.f};
|
||||
options.point_lights[2].attenuation = {1.f, 0.1f, 0.05f};
|
||||
options.point_lights[2].min_shadow_distance = 0.1f;
|
||||
|
||||
for (int i = 0; i < 24; ++i)
|
||||
{
|
||||
|
|
@ -406,6 +410,8 @@ void deferred_app::render()
|
|||
l.color = {15.f, 15.f, 15.f};
|
||||
l.position = {std::cos(a) * 9.f, std::sin(a) * 9.f, 0.5f};
|
||||
l.attenuation = {0.f, 0.f, 10.f};
|
||||
l.shadowed = false;
|
||||
l.min_shadow_distance = 0.1f;
|
||||
}
|
||||
|
||||
for (auto const & l : options.point_lights)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ namespace psemek::gfx
|
|||
} attenuation;
|
||||
geom::point<float, 3> position;
|
||||
bool shadowed = true;
|
||||
float min_shadow_distance;
|
||||
};
|
||||
|
||||
struct options
|
||||
|
|
|
|||
|
|
@ -7,9 +7,14 @@
|
|||
#include <psemek/gfx/error.hpp>
|
||||
|
||||
#include <psemek/geom/homogeneous.hpp>
|
||||
#include <psemek/geom/gram_schmidt.hpp>
|
||||
#include <psemek/geom/translation.hpp>
|
||||
#include <psemek/geom/mesh.hpp>
|
||||
|
||||
#include <psemek/cg/convex_hull_2d/graham.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace psemek::gfx
|
||||
{
|
||||
|
||||
|
|
@ -173,6 +178,67 @@ void main()
|
|||
}
|
||||
)";
|
||||
|
||||
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 = 4) in mat3x4 in_instance_transform;
|
||||
|
||||
void main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
)";
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -292,14 +358,24 @@ R"(
|
|||
uniform vec3 u_light_direction;
|
||||
uniform vec3 u_light_color;
|
||||
|
||||
uniform mat4 u_light_transform;
|
||||
uniform sampler2DShadow u_shadow;
|
||||
uniform int u_shadowed;
|
||||
|
||||
uniform vec3 u_camera_position;
|
||||
|
||||
uniform float u_max_intensity;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 position = texture(u_g0, texcoord).xyz;
|
||||
vec4 albedo = texture(u_g1, texcoord);
|
||||
if (albedo.a < 0.5)
|
||||
{
|
||||
out_color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 position = texture(u_g0, texcoord).xyz;
|
||||
vec3 normal = unpack_normal(texture(u_g2, texcoord).r);
|
||||
vec3 material = texture(u_g3, texcoord).xyz;
|
||||
|
||||
|
|
@ -311,7 +387,20 @@ void main()
|
|||
|
||||
float l = max(0.0, d) * material.x + pow(max(0.0, dot(view, refl)), material.z) * material.y;
|
||||
|
||||
vec3 color = l * albedo.rgb * u_light_color * albedo.a;
|
||||
vec3 color = l * albedo.rgb * u_light_color;
|
||||
|
||||
if (u_shadowed != 0)
|
||||
{
|
||||
vec4 shadow_space = u_light_transform * vec4(position, 1.0);
|
||||
|
||||
vec3 tc = shadow_space.xyz / shadow_space.w;
|
||||
tc = tc * 0.5 + vec3(0.5);
|
||||
|
||||
if (d > 0.0 && tc.x >= 0.0 && tc.x <= 1.0 && tc.y >= 0.0 && tc.y <= 1.0 && tc.z >= 0.0)
|
||||
{
|
||||
color *= texture(u_shadow, tc);
|
||||
}
|
||||
}
|
||||
|
||||
out_color = vec4(color, 1.0);
|
||||
}
|
||||
|
|
@ -324,14 +413,26 @@ uniform vec3 u_light_position;
|
|||
uniform vec3 u_light_color;
|
||||
uniform vec3 u_light_attenuation;
|
||||
|
||||
uniform samplerCubeShadow u_shadow;
|
||||
uniform int u_shadowed;
|
||||
uniform vec3 u_shadow_far_negative;
|
||||
uniform vec3 u_shadow_far_positive;
|
||||
uniform float u_shadow_near;
|
||||
|
||||
uniform vec3 u_camera_position;
|
||||
|
||||
uniform float u_max_intensity;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 position = texture(u_g0, texcoord).xyz;
|
||||
vec4 albedo = texture(u_g1, texcoord);
|
||||
if (albedo.a < 0.5)
|
||||
{
|
||||
out_color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 position = texture(u_g0, texcoord).xyz;
|
||||
vec3 normal = unpack_normal(texture(u_g2, texcoord).r);
|
||||
vec3 material = texture(u_g3, texcoord).xyz;
|
||||
|
||||
|
|
@ -340,15 +441,59 @@ void main()
|
|||
vec3 light = u_light_position - position;
|
||||
|
||||
float r = length(light);
|
||||
light /= r;
|
||||
|
||||
float d = dot(light, normal);
|
||||
vec3 light_n = light / r;
|
||||
|
||||
vec3 refl = 2.0 * normal * d - light;
|
||||
float d = dot(light_n, normal);
|
||||
|
||||
vec3 refl = 2.0 * normal * d - light_n;
|
||||
|
||||
float l = max(0.0, d) * material.x + pow(max(0.0, dot(view, refl)), material.z) * material.y;
|
||||
|
||||
vec3 color = l * albedo.rgb * u_light_color * albedo.a / (u_light_attenuation.x + r * (u_light_attenuation.y + r * u_light_attenuation.z));
|
||||
vec3 color = l * albedo.rgb * u_light_color / (u_light_attenuation.x + r * (u_light_attenuation.y + r * u_light_attenuation.z));
|
||||
|
||||
if (u_shadowed != 0 && d > 0.0)
|
||||
{
|
||||
vec3 dir = -light;
|
||||
|
||||
float far;
|
||||
float near = u_shadow_near;
|
||||
|
||||
vec3 adir = abs(dir);
|
||||
|
||||
float d = max(adir.x, max(adir.y, adir.z));
|
||||
|
||||
if (d == adir.x)
|
||||
{
|
||||
if (dir.x > 0.0)
|
||||
far = u_shadow_far_positive.x;
|
||||
else
|
||||
far = u_shadow_far_negative.x;
|
||||
}
|
||||
else if (d == adir.y)
|
||||
{
|
||||
if (dir.y > 0.0)
|
||||
far = u_shadow_far_positive.y;
|
||||
else
|
||||
far = u_shadow_far_negative.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dir.z > 0.0)
|
||||
far = u_shadow_far_positive.z;
|
||||
else
|
||||
far = u_shadow_far_negative.z;
|
||||
}
|
||||
|
||||
float A = (far + near) / (far - near);
|
||||
float B = - 2.0 * far * near / (far - near);
|
||||
|
||||
d = (A * d + B) / d;
|
||||
|
||||
float v = texture(u_shadow, vec4(dir, d * 0.5 + 0.5));
|
||||
|
||||
color *= v;
|
||||
}
|
||||
|
||||
out_color = vec4(color, 1.0);
|
||||
}
|
||||
|
|
@ -409,6 +554,8 @@ void main()
|
|||
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};
|
||||
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};
|
||||
|
||||
// G-buffer attachments:
|
||||
// 0 - position (rbg)
|
||||
|
|
@ -422,9 +569,17 @@ void main()
|
|||
|
||||
std::optional<geom::vector<std::size_t, 2>> g_buffer_size;
|
||||
|
||||
gfx::framebuffer directional_shadow_framebuffer;
|
||||
gfx::texture_2d directional_shadow_texture;
|
||||
|
||||
gfx::framebuffer point_shadow_framebuffer;
|
||||
gfx::texture_cubemap point_shadow_texture;
|
||||
|
||||
gfx::mesh screen_mesh;
|
||||
};
|
||||
|
||||
static int const shadow_map_size = 1024;
|
||||
|
||||
deferred_renderer::deferred_renderer()
|
||||
: pimpl_{std::make_unique<struct impl>()}
|
||||
{
|
||||
|
|
@ -447,12 +602,33 @@ void main()
|
|||
impl().directional_light_pass_program["u_g1"] = 1;
|
||||
impl().directional_light_pass_program["u_g2"] = 2;
|
||||
impl().directional_light_pass_program["u_g3"] = 3;
|
||||
impl().directional_light_pass_program["u_shadow"] = 4;
|
||||
|
||||
impl().point_light_pass_program.bind();
|
||||
impl().point_light_pass_program["u_g0"] = 0;
|
||||
impl().point_light_pass_program["u_g1"] = 1;
|
||||
impl().point_light_pass_program["u_g2"] = 2;
|
||||
impl().point_light_pass_program["u_g3"] = 3;
|
||||
impl().point_light_pass_program["u_shadow"] = 4;
|
||||
|
||||
impl().directional_shadow_texture.load<gfx::depth24_pixel>({shadow_map_size, shadow_map_size});
|
||||
impl().directional_shadow_texture.linear_filter();
|
||||
impl().directional_shadow_texture.clamp();
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_COMPARE_MODE, gl::COMPARE_REF_TO_TEXTURE);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_COMPARE_FUNC, gl::LEQUAL);
|
||||
impl().directional_shadow_framebuffer.depth(impl().directional_shadow_texture);
|
||||
impl().directional_shadow_framebuffer.assert_complete();
|
||||
|
||||
impl().point_shadow_texture.linear_filter();
|
||||
impl().point_shadow_texture.clamp();
|
||||
gl::TexParameteri(gl::TEXTURE_CUBE_MAP, gl::TEXTURE_COMPARE_MODE, gl::COMPARE_REF_TO_TEXTURE);
|
||||
gl::TexParameteri(gl::TEXTURE_CUBE_MAP, gl::TEXTURE_COMPARE_FUNC, gl::LEQUAL);
|
||||
for (int f = 0; f < 6; ++f)
|
||||
{
|
||||
impl().point_shadow_texture.load<gfx::depth24_pixel>(f, {shadow_map_size, shadow_map_size});
|
||||
}
|
||||
impl().point_shadow_framebuffer.depth(impl().point_shadow_texture);
|
||||
impl().point_shadow_framebuffer.assert_complete();
|
||||
|
||||
impl().screen_mesh.setup<geom::point<float, 2>>();
|
||||
}
|
||||
|
|
@ -482,6 +658,8 @@ void main()
|
|||
return m;
|
||||
}
|
||||
|
||||
static std::optional<gfx::mesh> test_mesh;
|
||||
|
||||
void deferred_renderer::render(std::vector<object> const & objects, render_target const & target, options const & opts)
|
||||
{
|
||||
// Get camera info
|
||||
|
|
@ -495,6 +673,7 @@ void main()
|
|||
std::unordered_map<std::uint32_t, std::vector<std::size_t>> objects_by_mask;
|
||||
|
||||
geom::box<float, 3> lit_bbox;
|
||||
geom::box<float, 3> casts_shadow_bbox;
|
||||
|
||||
for (std::size_t i = 0; i < objects.size(); ++i)
|
||||
{
|
||||
|
|
@ -506,6 +685,7 @@ void main()
|
|||
objects_by_mask[mask(objects[i])].push_back(i);
|
||||
|
||||
if (o.mat.lit) lit_bbox |= o.bbox;
|
||||
if (o.casts_shadow) casts_shadow_bbox |= o.bbox;
|
||||
}
|
||||
|
||||
// TODO: frustum culling
|
||||
|
|
@ -632,38 +812,304 @@ void main()
|
|||
impl().ambient_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
gl::DrawArrays(gl::TRIANGLES, 0, 6);
|
||||
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
|
||||
// Directional lights
|
||||
|
||||
geom::point<float, 2> bbox_hull_screen[8];
|
||||
auto lit_bbox_hull_size = bbox_to_screen_fan(camera_transform, lit_bbox, bbox_hull_screen);
|
||||
impl().screen_mesh.load(bbox_hull_screen, lit_bbox_hull_size, gl::TRIANGLE_FAN);
|
||||
|
||||
impl().directional_light_pass_program.bind();
|
||||
impl().directional_light_pass_program["u_camera_position"] = camera_position;
|
||||
impl().directional_light_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
gl::ActiveTexture(gl::TEXTURE4);
|
||||
impl().directional_shadow_texture.bind();
|
||||
|
||||
for (auto const & l : opts.directional_lights)
|
||||
{
|
||||
geom::matrix<float, 4, 4> light_transform;
|
||||
|
||||
if (l.shadowed)
|
||||
{
|
||||
geom::vector<float, 3> light_axes[3];
|
||||
|
||||
light_axes[2] = -geom::normalized(l.direction);
|
||||
light_axes[1] = {0.f, 0.f, 1.f};
|
||||
|
||||
if (light_axes[2][2] > 0.5f)
|
||||
light_axes[1] = {0.f, 1.f, 0.f};
|
||||
|
||||
geom::gram_schmidt(light_axes[2], light_axes[1]);
|
||||
|
||||
light_axes[0] = geom::cross(light_axes[2], light_axes[1]);
|
||||
|
||||
geom::box<float, 3> light_bbox;
|
||||
|
||||
geom::point<float, 3> origin = geom::point<float, 3>::zero();
|
||||
|
||||
for (auto const & v : geom::vertices(casts_shadow_bbox))
|
||||
{
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
light_bbox[i] |= geom::dot(light_axes[i], v - origin);
|
||||
}
|
||||
|
||||
light_transform = geom::orthographic_camera{light_bbox}.projection() * geom::homogeneous(geom::by_rows(light_axes[0], light_axes[1], light_axes[2]));
|
||||
|
||||
impl().directional_shadow_framebuffer.bind();
|
||||
gl::DrawBuffer(gl::NONE);
|
||||
gl::Viewport(0, 0, impl().directional_shadow_texture.width(), impl().directional_shadow_texture.height());
|
||||
|
||||
gl::Clear(gl::DEPTH_BUFFER_BIT);
|
||||
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
gl::DepthFunc(gl::LEQUAL);
|
||||
|
||||
gl::Enable(gl::CULL_FACE);
|
||||
gl::CullFace(gl::FRONT);
|
||||
|
||||
gl::Disable(gl::BLEND);
|
||||
|
||||
impl().shadow_builder_program.bind();
|
||||
impl().shadow_builder_program["u_light_transform"] = light_transform;
|
||||
|
||||
for (auto const & p : objects_by_mask)
|
||||
{
|
||||
if (p.second.empty()) continue;
|
||||
|
||||
std::uint32_t mask = p.first;
|
||||
|
||||
if (!(mask & O_CASTS_SHADOW)) continue;
|
||||
|
||||
impl().shadow_builder_program["u_flag_mask"] = mask;
|
||||
|
||||
for (std::size_t i : p.second)
|
||||
{
|
||||
auto const & o = objects[i];
|
||||
|
||||
if (mask & O_PRE_TRANSFORM)
|
||||
impl().shadow_builder_program["u_pre_transform"] = *o.pre_transform;
|
||||
|
||||
if (mask & O_POST_TRANSFORM)
|
||||
impl().shadow_builder_program["u_post_transform"] = *o.post_transform;
|
||||
|
||||
o.mesh->draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target.bind();
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
|
||||
gl::Disable(gl::DEPTH_TEST);
|
||||
gl::CullFace(gl::BACK);
|
||||
|
||||
impl().directional_light_pass_program.bind();
|
||||
impl().directional_light_pass_program["u_camera_position"] = camera_position;
|
||||
impl().directional_light_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
|
||||
impl().directional_light_pass_program["u_light_direction"] = geom::normalized(l.direction);
|
||||
impl().directional_light_pass_program["u_light_color"] = l.color;
|
||||
impl().directional_light_pass_program["u_shadowed"] = l.shadowed;
|
||||
if (l.shadowed) impl().directional_light_pass_program["u_light_transform"] = light_transform;
|
||||
impl().screen_mesh.draw();
|
||||
}
|
||||
|
||||
// Point lights
|
||||
|
||||
float min_intensity = opts.min_intensity.value_or(opts.max_intensity / 256.f);
|
||||
gl::Enable(gl::TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
gl::ActiveTexture(gl::TEXTURE4);
|
||||
impl().point_shadow_texture.bind();
|
||||
|
||||
impl().point_light_pass_program.bind();
|
||||
impl().point_light_pass_program["u_camera_position"] = camera_position;
|
||||
impl().point_light_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
float min_intensity = opts.min_intensity.value_or(opts.max_intensity / 256.f);
|
||||
|
||||
for (auto const & l : opts.point_lights)
|
||||
{
|
||||
float I = std::max({l.color[0], l.color[1], l.color[2]});
|
||||
auto r = geom::solve_quadratic(l.attenuation.c2, l.attenuation.c1, l.attenuation.c0 - I / min_intensity);
|
||||
|
||||
float near = l.min_shadow_distance;
|
||||
geom::vector<float, 3> far_positive;
|
||||
geom::vector<float, 3> far_negative;
|
||||
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
far_positive[i] = casts_shadow_bbox[i].max - l.position[i];
|
||||
far_negative[i] = l.position[i] - casts_shadow_bbox[i].min;
|
||||
|
||||
if (r)
|
||||
{
|
||||
far_positive[i] = std::min(far_positive[i], r->second);
|
||||
far_negative[i] = std::min(far_negative[i], r->second);
|
||||
}
|
||||
|
||||
far_positive[i] = std::max(far_positive[i], near);
|
||||
far_negative[i] = std::max(far_negative[i], near);
|
||||
}
|
||||
|
||||
if (l.shadowed)
|
||||
{
|
||||
geom::matrix<float, 4, 4> transform[6];
|
||||
|
||||
// +X
|
||||
{
|
||||
float far = far_positive[0];
|
||||
transform[0] = geom::matrix<float, 4, 4>::zero();
|
||||
|
||||
transform[0][0][2] = -1.f;
|
||||
transform[0][1][1] = -1.f;
|
||||
|
||||
transform[0][2][0] = (far + near) / (far - near);
|
||||
transform[0][2][3] = - 2.f * far * near / (far - near);
|
||||
transform[0][3][0] = 1.f;
|
||||
}
|
||||
|
||||
// -X
|
||||
{
|
||||
float far = far_negative[0];
|
||||
transform[1] = geom::matrix<float, 4, 4>::zero();
|
||||
|
||||
transform[1][0][2] = 1.f;
|
||||
transform[1][1][1] = -1.f;
|
||||
|
||||
transform[1][2][0] = - (far + near) / (far - near);
|
||||
transform[1][2][3] = - 2.f * far * near / (far - near);
|
||||
transform[1][3][0] = - 1.f;
|
||||
}
|
||||
|
||||
// +Y
|
||||
{
|
||||
float far = far_positive[1];
|
||||
transform[2] = geom::matrix<float, 4, 4>::zero();
|
||||
|
||||
transform[2][0][0] = 1.f;
|
||||
transform[2][1][2] = 1.f;
|
||||
|
||||
transform[2][2][1] = (far + near) / (far - near);
|
||||
transform[2][2][3] = - 2.f * far * near / (far - near);
|
||||
transform[2][3][1] = 1.f;
|
||||
}
|
||||
|
||||
// -Y
|
||||
{
|
||||
float far = far_negative[1];
|
||||
transform[3] = geom::matrix<float, 4, 4>::zero();
|
||||
|
||||
transform[3][0][0] = 1.f;
|
||||
transform[3][1][2] = -1.f;
|
||||
|
||||
transform[3][2][1] = - (far + near) / (far - near);
|
||||
transform[3][2][3] = - 2.f * far * near / (far - near);
|
||||
transform[3][3][1] = - 1.f;
|
||||
}
|
||||
|
||||
// +Z
|
||||
{
|
||||
float far = far_positive[2];
|
||||
transform[4] = geom::matrix<float, 4, 4>::zero();
|
||||
|
||||
transform[4][0][0] = 1.f;
|
||||
transform[4][1][1] = -1.f;
|
||||
|
||||
transform[4][2][2] = (far + near) / (far - near);
|
||||
transform[4][2][3] = - 2.f * far * near / (far - near);
|
||||
transform[4][3][2] = 1.f;
|
||||
}
|
||||
|
||||
// -Z
|
||||
{
|
||||
float far = far_negative[2];
|
||||
transform[5] = geom::matrix<float, 4, 4>::zero();
|
||||
|
||||
transform[5][0][0] = -1.f;
|
||||
transform[5][1][1] = -1.f;
|
||||
|
||||
transform[5][2][2] = - (far + near) / (far - near);
|
||||
transform[5][2][3] = - 2.f * far * near / (far - near);
|
||||
transform[5][3][2] = - 1.f;
|
||||
}
|
||||
|
||||
geom::matrix<float, 4, 4> const translate_by_light = geom::translation<float, 3>(geom::point<float, 3>::zero() - l.position).homogeneous_matrix();
|
||||
|
||||
impl().point_shadow_framebuffer.bind();
|
||||
gl::DrawBuffer(gl::NONE);
|
||||
gl::Viewport(0, 0, impl().point_shadow_texture.width(), impl().point_shadow_texture.height());
|
||||
|
||||
gl::Clear(gl::DEPTH_BUFFER_BIT);
|
||||
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
gl::DepthFunc(gl::LEQUAL);
|
||||
|
||||
gl::Enable(gl::CULL_FACE);
|
||||
gl::CullFace(gl::FRONT);
|
||||
|
||||
gl::Disable(gl::BLEND);
|
||||
|
||||
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;
|
||||
impl().cubemap_shadow_builder_program["u_layer_transform[2]"] = transform[2] * translate_by_light;
|
||||
impl().cubemap_shadow_builder_program["u_layer_transform[3]"] = transform[3] * translate_by_light;
|
||||
impl().cubemap_shadow_builder_program["u_layer_transform[4]"] = transform[4] * translate_by_light;
|
||||
impl().cubemap_shadow_builder_program["u_layer_transform[5]"] = transform[5] * translate_by_light;
|
||||
|
||||
for (auto const & p : objects_by_mask)
|
||||
{
|
||||
if (p.second.empty()) continue;
|
||||
|
||||
std::uint32_t mask = p.first;
|
||||
|
||||
if (!(mask & O_CASTS_SHADOW)) continue;
|
||||
|
||||
impl().cubemap_shadow_builder_program["u_flag_mask"] = mask;
|
||||
|
||||
for (std::size_t i : p.second)
|
||||
{
|
||||
auto const & o = objects[i];
|
||||
|
||||
if (mask & O_PRE_TRANSFORM)
|
||||
impl().cubemap_shadow_builder_program["u_pre_transform"] = *o.pre_transform;
|
||||
|
||||
if (mask & O_POST_TRANSFORM)
|
||||
impl().cubemap_shadow_builder_program["u_post_transform"] = *o.post_transform;
|
||||
|
||||
o.mesh->draw();
|
||||
}
|
||||
}
|
||||
/*
|
||||
gfx::pixmap_float pixmap({impl().point_shadow_texture.width(), impl().point_shadow_texture.height()});
|
||||
impl().point_shadow_texture.pixels(1, gl::DEPTH_COMPONENT, gl::FLOAT, pixmap.data());
|
||||
|
||||
auto pixels = util::map([](float x){ return std::uint8_t(x * 255); }, pixmap);
|
||||
|
||||
std::ofstream out{"/home/lisyarus/depth.pgm"};
|
||||
gfx::write_pgm(pixels, out);
|
||||
//*/
|
||||
}
|
||||
|
||||
target.bind();
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
|
||||
gl::Disable(gl::DEPTH_TEST);
|
||||
gl::CullFace(gl::BACK);
|
||||
|
||||
impl().point_light_pass_program.bind();
|
||||
impl().point_light_pass_program["u_camera_position"] = camera_position;
|
||||
impl().point_light_pass_program["u_max_intensity"] = opts.max_intensity;
|
||||
impl().point_light_pass_program["u_shadowed"] = l.shadowed;
|
||||
|
||||
if (l.shadowed)
|
||||
{
|
||||
impl().point_light_pass_program["u_shadow_near"] = near;
|
||||
impl().point_light_pass_program["u_shadow_far_positive"] = far_positive;
|
||||
impl().point_light_pass_program["u_shadow_far_negative"] = far_negative;
|
||||
}
|
||||
|
||||
geom::box<float, 3> light_bbox;
|
||||
if (r)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue