From 57588abbefc8f0162332ac2310c69b62a14b2404 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 11 Oct 2021 16:14:00 +0300 Subject: [PATCH] Add tetrahedron shadow maps for point lights --- shaderlib/occluder.glsl | 8 +++++- shaderlib/occluder_thsm.glsl | 11 ++++++++ shaderlib/shadow.glsl | 20 ++++++++++++--- source/effects/shadowmap.cpp | 49 +++++++++++++++++++++++++++++++----- source/effects/shadowmap.h | 6 ++++- 5 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 shaderlib/occluder_thsm.glsl diff --git a/shaderlib/occluder.glsl b/shaderlib/occluder.glsl index 84f667a8..b5d05f09 100644 --- a/shaderlib/occluder.glsl +++ b/shaderlib/occluder.glsl @@ -11,7 +11,13 @@ virtual mat4 get_vertex_transform() return world_obj_matrix; } +virtual void clipping(vec3 eye_vertex) +{ +} + void main() { - gl_Position = clip_eye_matrix*eye_world_matrix*get_vertex_transform()*get_vertex_position(); + vec4 eye_vertex = eye_world_matrix*get_vertex_transform()*get_vertex_position(); + clipping(eye_vertex.xyz); + gl_Position = clip_eye_matrix*eye_vertex; } diff --git a/shaderlib/occluder_thsm.glsl b/shaderlib/occluder_thsm.glsl new file mode 100644 index 00000000..13a78c05 --- /dev/null +++ b/shaderlib/occluder_thsm.glsl @@ -0,0 +1,11 @@ +import msp_interface; +import occluder; + +#pragma MSP stage(vertex) +out float gl_ClipDistance[2]; + +void clipping(vec3 eye_vertex) override +{ + gl_ClipDistance[0] = dot(eye_vertex.xyz, vec3(0.5, -0.288675, -0.816497)); + gl_ClipDistance[1] = dot(eye_vertex.xyz, vec3(-0.5, -0.288675, -0.816497)); +} diff --git a/shaderlib/shadow.glsl b/shaderlib/shadow.glsl index 438af68d..d6e2b385 100644 --- a/shaderlib/shadow.glsl +++ b/shaderlib/shadow.glsl @@ -6,13 +6,13 @@ struct ShadowParameters float darkness; int matrix_index; vec4 region; - float bias; + vec2 bias; }; uniform ShadowMap { ShadowParameters shadows[max_lights]; - mat4 shd_world_matrix[max_lights]; + mat4 shd_world_matrix[max_lights*4]; }; uniform sampler2DShadow shadow_map; @@ -29,7 +29,21 @@ virtual float get_shadow_factor(int index, vec4 world_pos) if(type==1) { shadow_coord = (shd_world_matrix[shadows[index].matrix_index]*world_pos).xyz; - shadow_coord.z -= shadows[index].bias; + shadow_coord.z -= shadows[index].bias.x; + } + else if(type==2) + { + int base = shadows[index].matrix_index; + vec4 clip_coord = shd_world_matrix[base]*world_pos; + for(int i=1; i<4; ++i) + { + vec4 c = shd_world_matrix[base+i]*world_pos; + if(c.w>clip_coord.w) + clip_coord = c; + } + shadow_coord = clip_coord.xyz/clip_coord.w; + vec2 bias = shadows[index].bias; + shadow_coord.z = (shadow_coord.z+bias.x)/bias.y-bias.x; } else return 1.0; diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index 46524397..c8c1e6eb 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -2,6 +2,7 @@ #include "directionallight.h" #include "error.h" #include "lighting.h" +#include "pointlight.h" #include "renderer.h" #include "resources.h" #include "shadowmap.h" @@ -30,7 +31,7 @@ ShadowMap::ShadowMap(unsigned w, unsigned h, Renderable &r, const Lighting *l): shdata.uniform(base+".darkness", 1.0f); shdata.uniform(base+".matrix_index", 0); shdata.uniform(base+".region", Vector4(0.0f, 0.0f, 1.0f, 1.0f)); - shdata.uniform(base+".bias", 0.0f); + shdata.uniform(base+".bias", 0.0f, 1.0f); } Matrix dummy_matrix; @@ -52,6 +53,11 @@ void ShadowMap::add_light(const DirectionalLight &light, unsigned s, Renderable add_light(light, s, DIRECTIONAL, c); } +void ShadowMap::add_light(const PointLight &light, unsigned s, Renderable &c) +{ + add_light(light, s, TETRAHEDRON, c); +} + void ShadowMap::add_light(const Light &light, unsigned s, ShadowType type, Renderable &c) { if(!lighting && !lights.empty()) @@ -93,6 +99,8 @@ void ShadowMap::add_light(const Light &light, unsigned s, ShadowType type, Rende region.left = next_left; } + unsigned n_views = (type==TETRAHEDRON ? 4 : 1); + lights.emplace_back(); ShadowedLight &sl = lights.back(); sl.light = &light; @@ -102,10 +110,28 @@ void ShadowMap::add_light(const Light &light, unsigned s, ShadowType type, Rende sl.view_index = views.size(); sl.shadow_caster = &c; - views.emplace_back(); - ShadowView &view = views[sl.view_index]; - view.light_index = lights.size()-1; - view.face = 0; + views.resize(views.size()+n_views); + for(unsigned i=0; i0) + view.face_matrix = Matrix().rotate(Geometry::Angle::from_turns((i-0.5f)/3.0f), Vector3(0, 0, 1)) + .rotate(Geometry::Angle::straight()-Geometry::acos(1.0f/3.0f), Vector3(1, 0, 0)); + + float triangle_h = sqrt(0.75f)*2.0f; + float bottom = 0.5f/sqrt(0.75f); + float distance = (sqrt(2.0f/3.0f)-sqrt(3.0f/8.0f))*2.0f; + view.camera.set_field_of_view(Geometry::atan(triangle_h/distance)*2.0f); + view.camera.set_aspect_ratio(1.0f/triangle_h); + view.camera.set_frustum_axis(0.0f, 1.0f-bottom/triangle_h); + view.camera.set_frustum_rotation(-Geometry::Angle::from_turns(i/4.0f)); + } + } string base = format("shadows[%d]", index); shdata.uniform(base+".type", static_cast(type)); @@ -165,7 +191,13 @@ void ShadowMap::setup_frame(Renderer &renderer) { string base = format("shadows[%d]", l.index); if(l.type==DIRECTIONAL) - shdata.uniform(base+".bias", depth_bias/l.region.width); + shdata.uniform(base+".bias", depth_bias/l.region.width, 0.0f); + else if(l.type==TETRAHEDRON) + { + float distance = (sqrt(2.0f/3.0f)-sqrt(3.0f/8.0f))*2.0f; + float bias = depth_bias*2.0f/(distance*l.region.width); + shdata.uniform(base+".bias", -1001.0f/999.0f, 1.0f-bias); + } } vector shadow_matrices; @@ -181,6 +213,11 @@ void ShadowMap::setup_frame(Renderer &renderer) v.camera.set_orthographic(radius*2, radius*2); v.camera.set_depth_clip(-radius, radius); } + else if(light.type==TETRAHEDRON) + { + v.camera.set_object_matrix((*light.light->get_matrix())*v.face_matrix); + v.camera.set_depth_clip(radius/1000.0f, radius); + } Matrix to_texcoord = Matrix().translate(Vector3(0.5f, 0.5f, 0.5f)).scale(0.5f); shadow_matrices.push_back(to_texcoord*v.camera.get_projection_matrix()*v.camera.get_view_matrix()); diff --git a/source/effects/shadowmap.h b/source/effects/shadowmap.h index cf2dec01..0acb1b64 100644 --- a/source/effects/shadowmap.h +++ b/source/effects/shadowmap.h @@ -14,6 +14,7 @@ namespace GL { class DirectionalLight; class Light; +class PointLight; /** Creates shadows on a renderable through a shadow map texture. In the setup @@ -27,7 +28,8 @@ private: enum ShadowType { NONE, - DIRECTIONAL + DIRECTIONAL, + TETRAHEDRON }; struct ShadowedLight @@ -45,6 +47,7 @@ private: unsigned light_index; unsigned face; Camera camera; + Matrix face_matrix; }; unsigned width; @@ -69,6 +72,7 @@ public: ShadowMap(unsigned, unsigned, Renderable &, const Lighting &); void add_light(const DirectionalLight &, unsigned, Renderable &); + void add_light(const PointLight &, unsigned, Renderable &); private: void add_light(const Light &, unsigned, ShadowType, Renderable &); -- 2.43.0