From 726a83423201f1fd9ab911f7581c46026a888d43 Mon Sep 17 00:00:00 2001 From: milek7 Date: Wed, 2 Aug 2017 23:26:40 +0200 Subject: [PATCH] ubo for light settings --- World.cpp | 6 +-- renderer.cpp | 46 +++++++++++------ renderer.h | 1 + shader.cpp | 110 +++++++++++++++++----------------------- shader.h | 96 +++++++++++++++++++++++++---------- shaders/blinnphong.frag | 24 +++++---- 6 files changed, 163 insertions(+), 120 deletions(-) diff --git a/World.cpp b/World.cpp index 3a7f6d7b..89e0d316 100644 --- a/World.cpp +++ b/World.cpp @@ -1325,8 +1325,7 @@ TWorld::Render_Cab() { if( dynamic->InteriorLightLevel > 0.0f ) { // crude way to light the cabin, until we have something more complete in place auto const cablight = dynamic->InteriorLight * dynamic->InteriorLightLevel; - glm::vec3 cablight_glm = glm::make_vec3(&cablight.x); - GfxRenderer.shader.set_ambient(cablight_glm); + GfxRenderer.ubo.data.ambient = glm::make_vec3(&cablight.x); } // render GfxRenderer.Render( dynamic->mdKabina, dynamic->Material(), 0.0 ); @@ -1338,8 +1337,7 @@ TWorld::Render_Cab() { } if( dynamic->InteriorLightLevel > 0.0f ) { // reset the overall ambient - glm::vec3 ambient(0.0f, 0.0f, 0.0f); - GfxRenderer.shader.set_ambient(ambient); + GfxRenderer.ubo.data.ambient = glm::vec3(0.0f); } } glPopMatrix(); diff --git a/renderer.cpp b/renderer.cpp index 9c268f75..fa254a11 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -105,7 +105,9 @@ opengl_renderer::Init( GLFWwindow *Window ) { Global::daylight.color.z = 231.0f / 255.0f; Global::daylight.intensity = 1.0f; //m7todo: przenieść + ubo.init(); shader = gl_program_light({ gl_shader("lighting.vert"), gl_shader("blinnphong.frag") }); + shader.bind_ubodata(ubo.get_binding_point()); depth_shader = gl_program_mvp({ gl_shader("shadowmap.vert"), gl_shader("empty.frag") }); active_shader = &shader; @@ -267,12 +269,14 @@ opengl_renderer::Render( world_environment *Environment ) { ::glDisable( GL_DEPTH_TEST ); ::glDepthMask( GL_FALSE ); ::glPushMatrix(); + + ubo.data.fog_color = glm::make_vec3(Global::FogColor); // setup fog - if( Global::fFogEnd > 0 ) { - // fog setup - shader.set_fog(1.0f / Global::fFogEnd, glm::make_vec3(Global::FogColor)); - } - else { shader.set_fog(0.0f, glm::make_vec3(Global::FogColor)); } + if( Global::fFogEnd > 0 ) + ubo.data.fog_density = 1.0f / Global::fFogEnd; + else + ubo.data.fog_density = 0.0f; + ubo.update(); Environment->m_skydome.Render(); // skydome uses a custom vbo which could potentially confuse the main geometry system. hardly elegant but, eh @@ -444,6 +448,7 @@ opengl_renderer::Render( TGround *Ground ) { ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) Update_Lights( Ground->m_lights ); + ubo.update(); m_drawqueue.clear(); @@ -705,14 +710,14 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) { // crude way to light the cabin, until we have something more complete in place auto const cablight = Dynamic->InteriorLight * Dynamic->InteriorLightLevel; - shader.set_ambient(glm::make_vec3(&cablight.x)); + ubo.data.ambient = glm::make_vec3(&cablight.x); } Render( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); if( Dynamic->InteriorLightLevel > 0.0f ) { // reset the overall ambient - shader.set_ambient(glm::vec3(m_baseambient)); + ubo.data.ambient = glm::vec3(m_baseambient); } } } @@ -1182,14 +1187,14 @@ opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { // crude way to light the cabin, until we have something more complete in place auto const cablight = Dynamic->InteriorLight * Dynamic->InteriorLightLevel; - shader.set_ambient(glm::make_vec3(&cablight.x)); + ubo.data.ambient = glm::make_vec3(&cablight.x); } Render_Alpha( Dynamic->mdLowPolyInt, Dynamic->Material(), squaredistance ); if( Dynamic->InteriorLightLevel > 0.0f ) { // reset the overall ambient - shader.set_ambient(glm::vec3(m_baseambient)); + ubo.data.ambient = glm::vec3(m_baseambient); } } } @@ -1457,6 +1462,8 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { size_t renderlight = 0; + glm::mat4 mv = OpenGLMatrices.data(GL_MODELVIEW); + for( auto const &scenelight : Lights.data ) { if( renderlight == Global::DynamicLightCount ) { @@ -1483,21 +1490,30 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { scenelight.color.y, scenelight.color.z); - shader.set_light((GLuint)renderlight + 1, gl_program_light::SPOT, position, direction, 0.906f, 0.866f, color, 0.007f, 0.0002f); + gl_ubodata_light *light = &ubo.data.lights[renderlight + 1]; + light->type = gl_ubodata_light::SPOT; + light->pos = mv * glm::vec4(position, 1.0f); + light->dir = mv * glm::vec4(direction, 0.0f); + light->in_cutoff = 0.906f; + light->out_cutoff = 0.866f; + light->color = color; + light->linear = 0.007f; + light->quadratic = 0.0002f; ++renderlight; } - shader.set_ambient(Global::daylight.ambient); - shader.set_light(0, gl_program_light::DIR, glm::vec3(0.0f), Global::daylight.direction, - 0.0f, 0.0f, Global::daylight.color, 0.0f, 0.0f); - shader.set_light_count((GLuint)renderlight + 1); + ubo.data.ambient = Global::daylight.ambient; + ubo.data.lights[0].type = gl_ubodata_light::DIR; + ubo.data.lights[0].dir = mv * glm::vec4(Global::daylight.direction, 0.0f); + ubo.data.lights[0].color = Global::daylight.color; + ubo.data.lights_count = renderlight + 1; } void opengl_renderer::Disable_Lights() { - shader.set_light_count(0); + ubo.data.lights_count = 0; } bool diff --git a/renderer.h b/renderer.h index 4f406967..b858396e 100644 --- a/renderer.h +++ b/renderer.h @@ -67,6 +67,7 @@ private: class opengl_renderer { public: + gl_ubo ubo; gl_program_light shader; gl_program_mvp depth_shader; gl_program_mvp *active_shader = nullptr; diff --git a/shader.cpp b/shader.cpp index 35d11c87..84c18a41 100644 --- a/shader.cpp +++ b/shader.cpp @@ -66,6 +66,11 @@ gl_shader::operator GLuint() return id; } +gl_shader::~gl_shader() +{ + //glDeleteShader(*this); //m7todo: something is broken +} + gl_program::gl_program(std::vector shaders) { id = glCreateProgram(); @@ -116,6 +121,11 @@ gl_program::operator GLuint() return id; } +gl_program::~gl_program() +{ + //glDeleteProgram(*this); //m7todo: something is broken +} + gl_program_mvp::gl_program_mvp(std::vector v) : gl_program(v) { mv_uniform = glGetUniformLocation(id, "modelview"); @@ -151,26 +161,14 @@ gl_program_light::gl_program_light(std::vector v) : gl_program_mvp(v) glUniform1i(glGetUniformLocation(id, "tex"), 0); glUniform1i(glGetUniformLocation(id, "shadowmap"), 1); lightview_uniform = glGetUniformLocation(id, "lightview"); - ambient_uniform = glGetUniformLocation(id, "ambient"); emission_uniform = glGetUniformLocation(id, "emission"); specular_uniform = glGetUniformLocation(id, "specular"); - fog_color_uniform = glGetUniformLocation(id, "fog_color"); - fog_density_uniform = glGetUniformLocation(id, "fog_density"); - lcount_uniform = glGetUniformLocation(id, "lights_count"); +} - for (size_t i = 0; i < MAX_LIGHTS; i++) - { - lights_uniform[i].type = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].type").c_str()); - lights_uniform[i].pos = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].pos").c_str()); - lights_uniform[i].dir = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].dir").c_str()); - lights_uniform[i].in_cutoff = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].in_cutoff").c_str()); - lights_uniform[i].out_cutoff = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].out_cutoff").c_str()); - lights_uniform[i].color = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].color").c_str()); - lights_uniform[i].linear = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].linear").c_str()); - lights_uniform[i].quadratic = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].quadratic").c_str()); - } - - glUniform1ui(lcount_uniform, 0); +void gl_program_light::bind_ubodata(GLuint point) +{ + GLuint index = glGetUniformBlockIndex(*this, "ubodata"); + glUniformBlockBinding(*this, index, point); } void gl_program_light::set_lightview(const glm::mat4 &lightview) @@ -181,53 +179,6 @@ void gl_program_light::set_lightview(const glm::mat4 &lightview) glUniformMatrix4fv(lightview_uniform, 1, GL_FALSE, glm::value_ptr(lightview)); } -void gl_program_light::set_ambient(const glm::vec3 &ambient) -{ - if (current_program != this) - return; - - glUniform3fv(ambient_uniform, 1, glm::value_ptr(ambient)); -} - -void gl_program_light::set_fog(float density, const glm::vec3 &color) -{ - if (current_program != this) - return; - - glUniform1f(fog_density_uniform, density); - glUniform3fv(fog_color_uniform, 1, glm::value_ptr(color)); -} - -void gl_program_light::set_light_count(GLuint count) -{ - if (current_program != this) - return; - - glUniform1ui(lcount_uniform, count); -} - -void gl_program_light::set_light(GLuint i, type t, const glm::vec3 &pos, const glm::vec3 &dir, - float in_cutoff, float out_cutoff, - const glm::vec3 &color, float linear, float quadratic) -{ - if (current_program != this) - return; - - glm::mat4 mv = OpenGLMatrices.data(GL_MODELVIEW); - - glm::vec3 trans_pos = mv * glm::vec4(pos.x, pos.y, pos.z, 1.0f); - glm::vec3 trans_dir = mv * glm::vec4(dir.x, dir.y, dir.z, 0.0f); - - glUniform1ui(lights_uniform[i].type, (GLuint)t); - glUniform3fv(lights_uniform[i].pos, 1, glm::value_ptr(trans_pos)); - glUniform3fv(lights_uniform[i].dir, 1, glm::value_ptr(trans_dir)); - glUniform1f(lights_uniform[i].in_cutoff, in_cutoff); - glUniform1f(lights_uniform[i].out_cutoff, out_cutoff); - glUniform3fv(lights_uniform[i].color, 1, glm::value_ptr(color)); - glUniform1f(lights_uniform[i].linear, linear); - glUniform1f(lights_uniform[i].quadratic, quadratic); -} - void gl_program_light::set_material(float specular, const glm::vec3 &emission) { if (current_program != this) @@ -236,3 +187,34 @@ void gl_program_light::set_material(float specular, const glm::vec3 &emission) glUniform1f(specular_uniform, specular); glUniform3fv(emission_uniform, 1, glm::value_ptr(emission)); } + +template +GLuint gl_ubo::binding_point_cnt = 0; + +template +void gl_ubo::init() +{ + glGenBuffers(1, &buffer_id); + glBindBuffer(GL_UNIFORM_BUFFER, buffer_id); + glBufferData(GL_UNIFORM_BUFFER, sizeof(T), nullptr, GL_DYNAMIC_DRAW); + binding_point = binding_point_cnt++; + glBindBufferBase(GL_UNIFORM_BUFFER, binding_point, buffer_id); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +template +void gl_ubo::update() +{ + glBindBuffer(GL_UNIFORM_BUFFER, buffer_id); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(T), &data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +template +gl_ubo::~gl_ubo() +{ + if (buffer_id) + glDeleteBuffers(1, &buffer_id); +} + +template class gl_ubo; \ No newline at end of file diff --git a/shader.h b/shader.h index 36c3d0d4..cec881ba 100644 --- a/shader.h +++ b/shader.h @@ -7,10 +7,11 @@ class gl_shader { - GLuint id; + GLuint id = 0; public: gl_shader(); gl_shader(std::string); + ~gl_shader(); operator GLuint(); }; @@ -18,10 +19,12 @@ public: class gl_program { protected: - GLuint id; + GLuint id = 0; + public: gl_program() = default; gl_program(std::vector); + ~gl_program(); static gl_program* current_program; static gl_program* last_program; @@ -47,46 +50,85 @@ public: void copy_gl_mvp(); }; -class gl_program_light : public gl_program_mvp -{ -public: - static const size_t MAX_LIGHTS = 8; +// layout std140 +// structs must match with GLSL +// weird order to minimize padding - enum type +#define PAD(x) uint64_t : x * 4; uint64_t : x * 4; +#pragma pack(push, 1) +struct gl_ubodata_light +{ + enum type_e { SPOT = 0, POINT, DIR }; + glm::vec3 pos; + type_e type; + + glm::vec3 dir; + float in_cutoff; + + glm::vec3 color; + float out_cutoff; + + float linear; + float quadratic; + + PAD(8); +}; + +static_assert(sizeof(gl_ubodata_light) == 64); + +struct gl_ubodata_light_params +{ + static const size_t MAX_LIGHTS = 8; + + glm::vec3 ambient; + float fog_density; + + glm::vec3 fog_color; + GLuint lights_count; + + gl_ubodata_light lights[MAX_LIGHTS]; +}; + +static_assert(sizeof(gl_ubodata_light_params) == 544); + +#pragma pack(pop) + +template +class gl_ubo +{ + GLuint buffer_id = 0; + GLuint binding_point; + static GLuint binding_point_cnt; + +public: + T data; + void init(); + ~gl_ubo(); + void update(); + GLuint get_binding_point() + { + return binding_point; + }; +}; + +class gl_program_light : public gl_program_mvp +{ +public: gl_program_light() = default; gl_program_light(std::vector); void set_lightview(const glm::mat4 &lightview); - void set_ambient(const glm::vec3 &ambient); - void set_fog(float density, const glm::vec3 &color); void set_material(float specular, const glm::vec3 &emission); - void set_light_count(GLuint count); - void set_light(GLuint id, type t, const glm::vec3 &pos, const glm::vec3 &dir, float in_cutoff, float out_cutoff, - const glm::vec3 &color, float linear, float quadratic); + void bind_ubodata(GLuint point); private: GLuint lightview_uniform; - GLuint ambient_uniform; GLuint specular_uniform; - GLuint fog_color_uniform; - GLuint fog_density_uniform; GLuint emission_uniform; - GLuint lcount_uniform; - struct light_s - { - GLuint type; - GLuint pos; - GLuint dir; - GLuint in_cutoff; - GLuint out_cutoff; - GLuint color; - GLuint linear; - GLuint quadratic; - } lights_uniform[MAX_LIGHTS]; }; diff --git a/shaders/blinnphong.frag b/shaders/blinnphong.frag index 13eaff77..b672d5a0 100644 --- a/shaders/blinnphong.frag +++ b/shaders/blinnphong.frag @@ -6,15 +6,14 @@ const uint LIGHT_DIR = 2U; struct light_s { + vec3 pos; uint type; - vec3 pos; - vec3 dir; - + vec3 dir; float in_cutoff; - float out_cutoff; vec3 color; + float out_cutoff; float linear; float quadratic; @@ -30,14 +29,19 @@ out vec4 color; uniform sampler2D tex; uniform sampler2DShadow shadowmap; -uniform vec3 ambient; uniform vec3 emission; -uniform vec3 fog_color; -uniform float fog_density; uniform float specular; -uniform light_s lights[8]; -uniform uint lights_count; +layout(std140) uniform ubodata +{ + vec3 ambient; + float fog_density; + + vec3 fog_color; + uint lights_count; + + light_s lights[8]; +}; float calc_shadow() { @@ -132,4 +136,4 @@ void main() vec4 tex_color = texture(tex, f_coord); color = vec4(apply_fog(result * tex_color.xyz), tex_color.w); -} \ No newline at end of file +}