]> git.tdb.fi Git - libs/gl.git/commitdiff
Use persistent uniform blocks for Camera, Lighting and Clipping
authorMikko Rasa <tdb@tdb.fi>
Sat, 8 May 2021 14:58:11 +0000 (17:58 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 9 May 2021 07:53:56 +0000 (10:53 +0300)
Now that the relevant calculations are done in world space, the values
of these uniforms don't need to be calculated on a per-frame basis.

13 files changed:
source/core/clipping.cpp
source/core/clipping.h
source/core/clipplane.cpp
source/core/clipplane.h
source/materials/light.cpp
source/materials/light.h
source/materials/lighting.cpp
source/materials/lighting.h
source/render/camera.cpp
source/render/camera.h
source/render/renderer.cpp
source/render/renderer.h
source/resources/resources.cpp

index c286b7e57677e7880a56908e3dda0f3ff90a15be..18b706e78b1b34e9205879acd51cf83d10ad9cbb 100644 (file)
@@ -20,7 +20,7 @@ unsigned Clipping::get_n_attach_points()
 
 void Clipping::attach(const ClipPlane &p)
 {
-       if(find(planes, &p)!=planes.end())
+       if(find_member(planes, &p, &AttachedPlane::plane)!=planes.end())
                return;
        if(planes.size()>=get_n_attach_points())
                throw invalid_operation("Clipping::attach");
@@ -32,7 +32,7 @@ void Clipping::attach(const ClipPlane &p)
 
 void Clipping::detach(const ClipPlane &p)
 {
-       vector<const ClipPlane *>::iterator i = find(planes, &p);
+       vector<AttachedPlane>::iterator i = find_member(planes, &p, &AttachedPlane::plane);
        if(i!=planes.end())
        {
                planes.erase(i);
@@ -45,14 +45,19 @@ void Clipping::detach(const ClipPlane &p)
 void Clipping::detach(unsigned i)
 {
        if(i<planes.size())
-               detach(*planes[i]);
+               detach(*planes[i].plane);
 }
 
-void Clipping::update_shader_data(ProgramData &shdata, const Matrix &view_matrix) const
+const ProgramData &Clipping::get_shader_data() const
 {
-       Matrix view_inverse = invert(view_matrix);
        for(unsigned i=0; i<planes.size(); ++i)
-               planes[i]->update_shader_data(shdata, view_inverse, i);
+               if(planes[i].plane->get_generation()!=planes[i].generation)
+               {
+                       planes[i].plane->update_shader_data(shdata, i);
+                       planes[i].generation = planes[i].plane->get_generation();
+               }
+
+       return shdata;
 }
 
 void Clipping::bind() const
index 319a8d98ff765a9cfb4e1c7b3fd57ba825b60b75..d74763ab7c697f9cade4e94ab4b15bdb518e0a10 100644 (file)
@@ -4,18 +4,27 @@
 #include <vector>
 #include <msp/core/attributes.h>
 #include "bindable.h"
+#include "programdata.h"
 
 namespace Msp {
 namespace GL {
 
 class ClipPlane;
 class Matrix;
-class ProgramData;
 
 class Clipping: public Bindable<Clipping>
 {
 private:
-       std::vector<const ClipPlane *> planes;
+       struct AttachedPlane
+       {
+               const ClipPlane *plane;
+               mutable unsigned generation;
+
+               AttachedPlane(const ClipPlane *p): plane(p), generation(0) { }
+       };
+
+       std::vector<AttachedPlane> planes;
+       mutable ProgramData shdata;
 
 public:
        static unsigned get_n_attach_points();
@@ -26,7 +35,7 @@ public:
        DEPRECATED void attach(unsigned, const ClipPlane &p) { attach(p); }
        DEPRECATED void detach(unsigned);
 
-       void update_shader_data(ProgramData &, const Matrix &) const;
+       const ProgramData &get_shader_data() const;
 
        void bind() const;
 
index 4adf2bf5a45d55b1707b85f40629cd7597189ee7..b27464ca20249cffa5fe0c70affed87195ab3390 100644 (file)
@@ -9,20 +9,24 @@ namespace Msp {
 namespace GL {
 
 ClipPlane::ClipPlane():
-       eq(0, 0, 0, 1)
+       eq(0, 0, 0, 1),
+       generation(0)
 { }
 
 ClipPlane::ClipPlane(const Vector4 &e):
-       eq(e)
+       eq(e),
+       generation(0)
 { }
 
 ClipPlane::ClipPlane(const Vector3 &p, const Vector3 &d):
-       eq(compose(d, -dot(p, d)))
+       eq(compose(d, -dot(p, d))),
+       generation(0)
 { }
 
 void ClipPlane::set_equation(const Vector4 &e)
 {
        eq = e;
+       ++generation;
 }
 
 void ClipPlane::set_plane(const Vector3 &p, const Vector3 &d)
@@ -31,9 +35,9 @@ void ClipPlane::set_plane(const Vector3 &p, const Vector3 &d)
        set_equation(compose(nd, -dot(p, nd)));
 }
 
-void ClipPlane::update_shader_data(ProgramData &shdata, const Matrix &view_inverse, unsigned i) const
+void ClipPlane::update_shader_data(ProgramData &shdata, unsigned i) const
 {
-       shdata.uniform(format("clip_planes[%d].equation", i), eq*view_inverse);
+       shdata.uniform(format("clip_planes[%d].equation", i), eq);
 }
 
 } // namespace GL
index 98c633b70fd7933bedf39824aa0abe851b2f6412..f9dca0de5b6257d641a3bb63a5a86d45fe459e26 100644 (file)
@@ -13,6 +13,7 @@ class ClipPlane
 {
 private:
        Vector4 eq;
+       unsigned generation;
 
 public:
        ClipPlane();
@@ -21,7 +22,9 @@ public:
 
        void set_equation(const Vector4 &);
        void set_plane(const Vector3 &, const Vector3 &);
-       void update_shader_data(ProgramData &, const Matrix &, unsigned) const;
+       void update_shader_data(ProgramData &, unsigned) const;
+
+       unsigned get_generation() const { return generation; }
 };
 
 } // namespace GL
index 2825b81eaa745f70b9d5aa4ed6009e499c4dce5c..3d3cba0a87127116068aa85900e24656e1f83841 100644 (file)
@@ -16,7 +16,8 @@ Light::Light():
        position(0, 0, 1, 0),
        spot_dir(0, 0, -1),
        spot_exp(0),
-       spot_cutoff(Geometry::Angle<float>::straight())
+       spot_cutoff(Geometry::Angle<float>::straight()),
+       generation(0)
 {
        attenuation[0] = 1;
        attenuation[1] = 0;
@@ -43,11 +44,13 @@ void Light::update_matrix()
 void Light::set_color(const Color &c)
 {
        color = c;
+       ++generation;
 }
 
 void Light::set_transmittance(const Color &t)
 {
        transmittance = t;
+       ++generation;
 }
 
 void Light::set_matrix(const Matrix &m)
@@ -57,6 +60,7 @@ void Light::set_matrix(const Matrix &m)
        spot_dir = normalize(-matrix.column(2).slice<3>(0));
        direction = (position.w ? spot_dir : normalize(-position.slice<3>(0)));
        update_matrix();
+       ++generation;
 }
 
 void Light::set_position(const Vector4 &p)
@@ -65,6 +69,7 @@ void Light::set_position(const Vector4 &p)
        if(!position.w)
                direction = normalize(-position.slice<3>(0));
        update_matrix();
+       ++generation;
 }
 
 void Light::set_spot_direction(const Vector3 &d)
@@ -73,6 +78,7 @@ void Light::set_spot_direction(const Vector3 &d)
        if(position.w)
                direction = spot_dir;
        update_matrix();
+       ++generation;
 }
 
 void Light::set_spot_exponent(float e)
@@ -81,6 +87,7 @@ void Light::set_spot_exponent(float e)
                throw invalid_argument("Light::set_spot_exponent");
 
        spot_exp = e;
+       ++generation;
 }
 
 void Light::set_spot_cutoff(const Geometry::Angle<float> &c)
@@ -89,11 +96,13 @@ void Light::set_spot_cutoff(const Geometry::Angle<float> &c)
                throw invalid_argument("Light::set_spot_cutoff");
 
        spot_cutoff = c;
+       ++generation;
 }
 
 void Light::disable_spot_cutoff()
 {
        set_spot_cutoff(Geometry::Angle<float>::straight());
+       ++generation;
 }
 
 void Light::set_attenuation(float c, float l, float q)
@@ -101,13 +110,15 @@ void Light::set_attenuation(float c, float l, float q)
        attenuation[0] = c;
        attenuation[1] = l;
        attenuation[2] = q;
+       ++generation;
 }
 
-void Light::update_shader_data(ProgramData &shdata, const Matrix &view_matrix, unsigned i) const
+void Light::update_shader_data(ProgramData &shdata, unsigned i) const
 {
        string base = format("light_sources[%d]", i);
-       shdata.uniform(base+".position", view_matrix*position);
+       shdata.uniform(base+".position", position);
        shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
+       shdata.uniform(base+".enabled", 1);
 }
 
 
index d4b66077928188076b44974d6eaf6c36d4e2ccc2..4532d0d42c4035c2442fbcaf2e1eea414ce6c164 100644 (file)
@@ -51,6 +51,7 @@ private:
        float spot_exp;
        Geometry::Angle<float> spot_cutoff;
        float attenuation[3];
+       unsigned generation;
 
 public:
        Light();
@@ -107,9 +108,11 @@ public:
        void set_attenuation(float, float, float);
        const float *get_attenuation() const { return attenuation; }
 
-       /** Updates a ProgramData object with the uniforms for the Light.  A view
-       matrix and light source index must be passed in. */
-       void update_shader_data(ProgramData &, const Matrix &, unsigned) const;
+       unsigned get_generation() const { return generation; }
+
+       /** Updates a ProgramData object with the uniforms for the Light.  A light
+       source index must be passed in.  Primarily used by Lighting. */
+       void update_shader_data(ProgramData &, unsigned) const;
 };
 
 } // namespace GL
index 70b819cec8c3101b5379f1cb26b284e4a5d8bd98..b19ebab014c56379fc77fd3abf246d6d1381e215 100644 (file)
@@ -13,12 +13,13 @@ namespace Msp {
 namespace GL {
 
 Lighting::Lighting():
-       ambient(0.2),
        zenith_direction(0, 0, 1),
-       horizon_angle(Geometry::Angle<float>::zero()),
-       fog_color(0.0f, 0.0f, 0.0f, 0.0f),
-       fog_density(0.0f)
-{ }
+       horizon_angle(Geometry::Angle<float>::zero())
+{
+       set_ambient(0.2f);
+       set_fog_color(Color(0.0f, 0.0f, 0.0f, 0.0f));
+       set_fog_density(0.0f);
+}
 
 Lighting::~Lighting()
 {
@@ -29,26 +30,31 @@ Lighting::~Lighting()
 void Lighting::set_ambient(const Color &a)
 {
        ambient = a;
+       shdata.uniform("ambient_color", ambient);
 }
 
 void Lighting::set_sky_color(const Color &s)
 {
        sky_color = s;
+       shdata.uniform("sky_color", sky_color);
 }
 
 void Lighting::set_zenith_direction(const Vector3 &d)
 {
        zenith_direction = d;
+       shdata.uniform("world_zenith_dir", zenith_direction);
 }
 
 void Lighting::set_horizon_angle(const Geometry::Angle<float> &a)
 {
        horizon_angle = a;
+       shdata.uniform("horizon_limit", horizon_angle.radians());
 }
 
 void Lighting::set_fog_color(const Color &c)
 {
        fog_color = c;
+       shdata.uniform("fog_color", fog_color);
 }
 
 void Lighting::set_fog_density(float d)
@@ -57,6 +63,7 @@ void Lighting::set_fog_density(float d)
                throw invalid_argument("Lighting::set_fog_density");
 
        fog_density = d;
+       shdata.uniform("fog_density", fog_density);
 }
 
 void Lighting::set_fog_half_distance(float d)
@@ -66,13 +73,13 @@ void Lighting::set_fog_half_distance(float d)
 
 void Lighting::attach(const Light &l)
 {
-       if(find(lights, &l)==lights.end())
+       if(find_member(lights, &l, &AttachedLight::light)==lights.end())
                lights.push_back(&l);
 }
 
 void Lighting::detach(const Light &l)
 {
-       vector<const Light *>::iterator i = find(lights, &l);
+       vector<AttachedLight>::iterator i = find_member(lights, &l, &AttachedLight::light);
        if(i!=lights.end())
                lights.erase(i);
 }
@@ -82,26 +89,47 @@ void Lighting::detach(unsigned i)
        if(i>=lights.size())
                return;
 
-       detach(*lights[i]);
+       detach(*lights[i].light);
 }
 
 const Light *Lighting::get_attached_light(unsigned i) const
 {
-       return i<lights.size() ? lights[i] : 0;
+       return i<lights.size() ? lights[i].light : 0;
 }
 
-void Lighting::update_shader_data(ProgramData &shdata, const Matrix &view_matrix) const
+void Lighting::update_shader_data(ProgramData &sd, const Matrix &) const
 {
-       shdata.uniform("ambient_color", ambient);
-       shdata.uniform("sky_color", sky_color);
-       shdata.uniform("world_zenith_dir", zenith_direction);
-       shdata.uniform("horizon_limit", horizon_angle.radians());
-       shdata.uniform("fog_color", fog_color);
-       shdata.uniform("fog_density", fog_density);
+       sd.uniform("ambient_color", ambient);
+       sd.uniform("sky_color", sky_color);
+       sd.uniform("world_zenith_dir", zenith_direction);
+       sd.uniform("horizon_limit", horizon_angle.radians());
+       sd.uniform("fog_color", fog_color);
+       sd.uniform("fog_density", fog_density);
 
        for(unsigned i=0; i<lights.size(); ++i)
-               if(lights[i])
-                       lights[i]->update_shader_data(shdata, view_matrix, i);
+               if(lights[i].light)
+                       lights[i].light->update_shader_data(sd, i);
+}
+
+const ProgramData &Lighting::get_shader_data() const
+{
+       for(unsigned i=0; i<lights.size(); ++i)
+               if(lights[i].light->get_generation()!=lights[i].generation)
+               {
+                       lights[i].light->update_shader_data(shdata, i);
+                       lights[i].generation = lights[i].light->get_generation();
+               }
+
+       return shdata;
+}
+
+void Lighting::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+       shdata.set_debug_name(name+" [UBO]");
+#else
+       (void)name;
+#endif
 }
 
 
@@ -137,7 +165,7 @@ void Lighting::Loader::init_actions()
 
 void Lighting::Loader::ambient(float r, float g, float b)
 {
-       obj.ambient = Color(r, g, b);
+       obj.set_ambient(Color(r, g, b));
 }
 
 void Lighting::Loader::fog_color(float r, float g, float b)
index 2a8756c3e567442758a9372932d7e958c7214ee6..833e7d2ba1277e916f6dd3f6f8c917c30f9d428b 100644 (file)
@@ -44,14 +44,23 @@ public:
        };
 
 private:
+       struct AttachedLight
+       {
+               const Light *light;
+               mutable unsigned generation;
+
+               AttachedLight(const Light *l): light(l), generation(0) { }
+       };
+
        Color ambient;
        Color sky_color;
        Vector3 zenith_direction;
        Geometry::Angle<float> horizon_angle;
        Color fog_color;
        float fog_density;
-       std::vector<const Light *> lights;
+       std::vector<AttachedLight> lights;
        std::vector<Light *> owned_data;
+       mutable ProgramData shdata;
 
 public:
        Lighting();
@@ -97,11 +106,13 @@ public:
        is returned. */
        DEPRECATED const Light *get_attached_light(unsigned) const;
 
-       const std::vector<const Light *> &get_attached_lights() const { return lights; }
-
        /** Updates a ProgramData object with the uniforms for the Lighting,
        including all attached light sources.  A view matrix must be passed in. */
-       void update_shader_data(ProgramData &, const Matrix &) const;
+       DEPRECATED void update_shader_data(ProgramData &, const Matrix &) const;
+
+       const ProgramData &get_shader_data() const;
+
+       void set_debug_name(const std::string &);
 };
 
 } // namespace GL
index 3bba0eaf38e00385e68a077474095a980a10f340..9b8b0c778d0c5fc68f784efaee4c74b886801ddb 100644 (file)
@@ -2,6 +2,8 @@
 #include "camera.h"
 #include "matrix.h"
 
+using namespace std;
+
 namespace Msp {
 namespace GL {
 
@@ -129,6 +131,8 @@ void Camera::update_projection_matrix()
        else
                proj_matrix = Matrix::ortho(left, right, bottom, top, clip_near, clip_far);
        proj_matrix = Matrix::rotation(rotate, Vector3(0, 0, 1))*proj_matrix;
+
+       shdata.uniform("clip_eye_matrix", proj_matrix);
 }
 
 void Camera::update_object_matrix()
@@ -141,6 +145,17 @@ void Camera::update_object_matrix()
        columns[3] = compose(position, 1.0f);
        matrix = Matrix::from_columns(columns);
        view_matrix = invert(matrix);
+
+       shdata.uniform("eye_world_matrix", view_matrix);
+}
+
+void Camera::set_debug_name(const string &name)
+{
+#ifdef DEBUG
+       shdata.set_debug_name(name+" [UBO]");
+#else
+       (void)name;
+#endif
 }
 
 
index b10ccb93e200ceaadbe62e8498c7cb69e427409a..844ec0d8ef521311b0714fd470996f7e611c7d6e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <msp/datafile/objectloader.h>
 #include "placeable.h"
+#include "programdata.h"
 
 namespace Msp {
 namespace GL {
@@ -41,6 +42,7 @@ private:
        Vector3 up_dir;
        Matrix view_matrix;
        Matrix proj_matrix;
+       ProgramData shdata;
 
 public:
        Camera();
@@ -89,9 +91,14 @@ public:
        Vector4 unproject(const Vector4 &) const;
        Vector3 unproject(const Vector3 &) const;
 
+       const ProgramData &get_shader_data() const { return shdata; }
+
 private:
        void update_projection_matrix();
        void update_object_matrix();
+
+public:
+       void set_debug_name(const std::string &);
 };
 
 } // namespace GL
index 5d0bf6b8dab2bf78b995ff18584bc0351902fc01..2da4bd78f4969a016ee71099ac2655567ca051f0 100644 (file)
@@ -43,9 +43,6 @@ void Renderer::init()
        state_stack.push_back(State());
        shdata_stack.reserve(32);
        state = &state_stack.back();
-
-       standard_shdata.uniform("clip_eye_matrix", Matrix());
-       standard_shdata.uniform("eye_world_matrix", Matrix());
 }
 
 Renderer::~Renderer()
@@ -56,9 +53,7 @@ Renderer::~Renderer()
 void Renderer::set_camera(const Camera &c)
 {
        state->camera = &c;
-       standard_shdata.uniform("clip_eye_matrix", state->camera->get_projection_matrix());
-       standard_shdata.uniform("eye_world_matrix", state->camera->get_view_matrix());
-       changed |= STANDARD_SHDATA;
+       changed |= CAMERA_SHDATA;
        set_matrix(Matrix());
 }
 
@@ -159,21 +154,13 @@ void Renderer::set_material(const Material *m)
 void Renderer::set_lighting(const Lighting *l)
 {
        state->lighting = l;
-       if(l)
-       {
-               l->update_shader_data(standard_shdata, Matrix());
-               changed |= STANDARD_SHDATA;
-       }
+       changed |= LIGHTING_SHDATA;
 }
 
 void Renderer::set_clipping(const Clipping *c)
 {
        state->clipping = c;
-       if(c)
-       {
-               c->update_shader_data(standard_shdata, Matrix());
-               changed |= STANDARD_SHDATA;
-       }
+       changed |= CLIPPING_SHDATA;
 }
 
 void Renderer::set_shader_program(const Program *p, const ProgramData *d)
@@ -246,35 +233,11 @@ void Renderer::pop_state()
        changed |= MATRIX;
        bool camera_changed = (state->camera!=old_camera);
        if(camera_changed)
-       {
-               if(state->camera)
-               {
-                       standard_shdata.uniform("clip_eye_matrix", state->camera->get_projection_matrix());
-                       standard_shdata.uniform("eye_world_matrix", state->camera->get_view_matrix());
-               }
-               else
-               {
-                       standard_shdata.uniform("clip_eye_matrix", Matrix());
-                       standard_shdata.uniform("eye_world_matrix", Matrix());
-               }
-               changed |= STANDARD_SHDATA;
-       }
+               changed |= CAMERA_SHDATA;
        if(state->lighting!=old_lighting)
-       {
-               if(state->lighting)
-               {
-                       state->lighting->update_shader_data(standard_shdata, Matrix());
-                       changed |= STANDARD_SHDATA;
-               }
-       }
+               changed |= LIGHTING_SHDATA;
        if(state->clipping!=old_clipping)
-       {
-               if(state->clipping)
-               {
-                       state->clipping->update_shader_data(standard_shdata, Matrix());
-                       changed |= STANDARD_SHDATA;
-               }
-       }
+               changed |= CLIPPING_SHDATA;
 }
 
 void Renderer::end()
@@ -285,8 +248,6 @@ void Renderer::end()
        *state = State();
        if(default_camera)
                set_camera(*default_camera);
-       else
-               standard_shdata.uniform("clip_eye_matrix", Matrix());
        shdata_stack.clear();
        excluded.clear();
 
@@ -374,12 +335,30 @@ void Renderer::apply_state()
                changed = (changed&~MATRIX)|STANDARD_SHDATA;
        }
 
+       if(state->camera && ((changed&CAMERA_SHDATA) || shprog_changed))
+       {
+               state->camera->get_shader_data().apply();
+               changed &= ~CAMERA_SHDATA;
+       }
+
        if(state->material && ((changed&MATERIAL_SHDATA) || shprog_changed))
        {
                state->material->get_shader_data().apply();
                changed &= ~MATERIAL_SHDATA;
        }
 
+       if(state->lighting && ((changed&LIGHTING_SHDATA) || shprog_changed))
+       {
+               state->lighting->get_shader_data().apply();
+               changed &= ~LIGHTING_SHDATA;
+       }
+
+       if(state->clipping && ((changed&CLIPPING_SHDATA) || shprog_changed))
+       {
+               state->clipping->get_shader_data().apply();
+               changed &= ~CLIPPING_SHDATA;
+       }
+
        if((changed&STANDARD_SHDATA) || shprog_changed)
        {
                standard_shdata.apply();
index 27087197690fca5bd7da7e784dc2fd11f5b88a13..197cf95a5c6b09090adc6ccd5e4505c2a1f44617 100644 (file)
@@ -107,7 +107,10 @@ private:
                MATRIX = 2,
                SHADER_DATA = 16,
                MATERIAL_SHDATA = 32,
-               STANDARD_SHDATA = 64
+               STANDARD_SHDATA = 64,
+               CAMERA_SHDATA = 128,
+               LIGHTING_SHDATA = 256,
+               CLIPPING_SHDATA = 512
        };
 
        const Camera *default_camera;
index 79c95932b6c52b03f45c669d58a68f71d5e2bbeb..682acde23d6603604f411193e7407d9cb09d530b 100644 (file)
@@ -44,11 +44,13 @@ Resources::Resources(bool set_as_global):
 {
        add_type<Animation>().suffix(".anim").keyword("animation");
        add_type<Armature>().suffix(".arma").keyword("armature");
-       add_type<Camera>().keyword("camera");
+       add_type<Camera>().keyword("camera")
+               .notify(&Resources::set_debug_name<Camera>);
        add_type<Font>().keyword("font");
        add_type<KeyFrame>().suffix(".kframe").keyword("keyframe");
        add_type<Light>().keyword("light");
-       add_type<Lighting>().suffix(".lightn").keyword("lighting");
+       add_type<Lighting>().suffix(".lightn").keyword("lighting")
+               .notify(&Resources::set_debug_name<Lighting>);
        add_type<Material>().suffix(".mat")
                .creator(&Resources::create_material).notify(&Resources::set_debug_name<Material>);
        add_type<Mesh>().keyword("mesh")