From a275d25eccad43716c5dcf91f8bc4af2a53c0445 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 8 May 2021 17:58:11 +0300 Subject: [PATCH] Use persistent uniform blocks for Camera, Lighting and Clipping 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. --- source/core/clipping.cpp | 17 ++++++--- source/core/clipping.h | 15 ++++++-- source/core/clipplane.cpp | 14 ++++--- source/core/clipplane.h | 5 ++- source/materials/light.cpp | 17 +++++++-- source/materials/light.h | 9 +++-- source/materials/lighting.cpp | 66 ++++++++++++++++++++++---------- source/materials/lighting.h | 19 ++++++++-- source/render/camera.cpp | 15 ++++++++ source/render/camera.h | 7 ++++ source/render/renderer.cpp | 69 ++++++++++++---------------------- source/render/renderer.h | 5 ++- source/resources/resources.cpp | 6 ++- 13 files changed, 172 insertions(+), 92 deletions(-) diff --git a/source/core/clipping.cpp b/source/core/clipping.cpp index c286b7e5..18b706e7 100644 --- a/source/core/clipping.cpp +++ b/source/core/clipping.cpp @@ -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::iterator i = find(planes, &p); + vector::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(iupdate_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 diff --git a/source/core/clipping.h b/source/core/clipping.h index 319a8d98..d74763ab 100644 --- a/source/core/clipping.h +++ b/source/core/clipping.h @@ -4,18 +4,27 @@ #include #include #include "bindable.h" +#include "programdata.h" namespace Msp { namespace GL { class ClipPlane; class Matrix; -class ProgramData; class Clipping: public Bindable { private: - std::vector planes; + struct AttachedPlane + { + const ClipPlane *plane; + mutable unsigned generation; + + AttachedPlane(const ClipPlane *p): plane(p), generation(0) { } + }; + + std::vector 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; diff --git a/source/core/clipplane.cpp b/source/core/clipplane.cpp index 4adf2bf5..b27464ca 100644 --- a/source/core/clipplane.cpp +++ b/source/core/clipplane.cpp @@ -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 diff --git a/source/core/clipplane.h b/source/core/clipplane.h index 98c633b7..f9dca0de 100644 --- a/source/core/clipplane.h +++ b/source/core/clipplane.h @@ -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 diff --git a/source/materials/light.cpp b/source/materials/light.cpp index 2825b81e..3d3cba0a 100644 --- a/source/materials/light.cpp +++ b/source/materials/light.cpp @@ -16,7 +16,8 @@ Light::Light(): position(0, 0, 1, 0), spot_dir(0, 0, -1), spot_exp(0), - spot_cutoff(Geometry::Angle::straight()) + spot_cutoff(Geometry::Angle::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 &c) @@ -89,11 +96,13 @@ void Light::set_spot_cutoff(const Geometry::Angle &c) throw invalid_argument("Light::set_spot_cutoff"); spot_cutoff = c; + ++generation; } void Light::disable_spot_cutoff() { set_spot_cutoff(Geometry::Angle::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); } diff --git a/source/materials/light.h b/source/materials/light.h index d4b66077..4532d0d4 100644 --- a/source/materials/light.h +++ b/source/materials/light.h @@ -51,6 +51,7 @@ private: float spot_exp; Geometry::Angle 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 diff --git a/source/materials/lighting.cpp b/source/materials/lighting.cpp index 70b819ce..b19ebab0 100644 --- a/source/materials/lighting.cpp +++ b/source/materials/lighting.cpp @@ -13,12 +13,13 @@ namespace Msp { namespace GL { Lighting::Lighting(): - ambient(0.2), zenith_direction(0, 0, 1), - horizon_angle(Geometry::Angle::zero()), - fog_color(0.0f, 0.0f, 0.0f, 0.0f), - fog_density(0.0f) -{ } + horizon_angle(Geometry::Angle::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 &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::iterator i = find(lights, &l); + vector::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 iupdate_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; iget_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) diff --git a/source/materials/lighting.h b/source/materials/lighting.h index 2a8756c3..833e7d2b 100644 --- a/source/materials/lighting.h +++ b/source/materials/lighting.h @@ -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 horizon_angle; Color fog_color; float fog_density; - std::vector lights; + std::vector lights; std::vector 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 &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 diff --git a/source/render/camera.cpp b/source/render/camera.cpp index 3bba0eaf..9b8b0c77 100644 --- a/source/render/camera.cpp +++ b/source/render/camera.cpp @@ -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 } diff --git a/source/render/camera.h b/source/render/camera.h index b10ccb93..844ec0d8 100644 --- a/source/render/camera.h +++ b/source/render/camera.h @@ -3,6 +3,7 @@ #include #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 diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index 5d0bf6b8..2da4bd78 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -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(); diff --git a/source/render/renderer.h b/source/render/renderer.h index 27087197..197cf95a 100644 --- a/source/render/renderer.h +++ b/source/render/renderer.h @@ -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; diff --git a/source/resources/resources.cpp b/source/resources/resources.cpp index 79c95932..682acde2 100644 --- a/source/resources/resources.cpp +++ b/source/resources/resources.cpp @@ -44,11 +44,13 @@ Resources::Resources(bool set_as_global): { add_type().suffix(".anim").keyword("animation"); add_type().suffix(".arma").keyword("armature"); - add_type().keyword("camera"); + add_type().keyword("camera") + .notify(&Resources::set_debug_name); add_type().keyword("font"); add_type().suffix(".kframe").keyword("keyframe"); add_type().keyword("light"); - add_type().suffix(".lightn").keyword("lighting"); + add_type().suffix(".lightn").keyword("lighting") + .notify(&Resources::set_debug_name); add_type().suffix(".mat") .creator(&Resources::create_material).notify(&Resources::set_debug_name); add_type().keyword("mesh") -- 2.43.0