]> git.tdb.fi Git - libs/gl.git/commitdiff
Add tetrahedron shadow maps for point lights
authorMikko Rasa <tdb@tdb.fi>
Mon, 11 Oct 2021 13:14:00 +0000 (16:14 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 11 Oct 2021 13:14:31 +0000 (16:14 +0300)
shaderlib/occluder.glsl
shaderlib/occluder_thsm.glsl [new file with mode: 0644]
shaderlib/shadow.glsl
source/effects/shadowmap.cpp
source/effects/shadowmap.h

index 84f667a88f0d07e93aeb40b3a57a7c05db525ef9..b5d05f09ad25dee7b98563dac8564dd0ff98bb82 100644 (file)
@@ -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 (file)
index 0000000..13a78c0
--- /dev/null
@@ -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));
+}
index 438af68d45181a86b6ec16f3cef065ba91ab88c4..d6e2b385f8955009abf737d998fbe7dd984f8996 100644 (file)
@@ -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;
index 465243973f3c87a702b23727c5bdea3a5a3266d5..c8c1e6ebd77df30dcdfc77f55d95a55b56a11c9d 100644 (file)
@@ -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; i<n_views; ++i)
+       {
+               ShadowView &view = views[sl.view_index+i];
+               view.light_index = lights.size()-1;
+               view.face = i;
+
+               if(type==TETRAHEDRON)
+               {
+                       if(i>0)
+                               view.face_matrix = Matrix().rotate(Geometry::Angle<float>::from_turns((i-0.5f)/3.0f), Vector3(0, 0, 1))
+                                       .rotate(Geometry::Angle<float>::straight()-Geometry::acos<float>(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<float>(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<float>::from_turns(i/4.0f));
+               }
+       }
 
        string base = format("shadows[%d]", index);
        shdata.uniform(base+".type", static_cast<int>(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<Matrix> 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());
index cf2dec01bc69e90afda1255dd63918fd5b8d5ebc..0acb1b64657bc2cc0c5d0837717883fb0bd1b77f 100644 (file)
@@ -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 &);