diff --git a/Texture.cpp b/Texture.cpp index 29d6720a..fee02ad5 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -815,7 +815,7 @@ texture_manager::bind( texture_handle const Texture ) { #ifndef EU07_DEFERRED_TEXTURE_UPLOAD // NOTE: we could bind dedicated 'error' texture here if the id isn't valid ::glBindTexture( GL_TEXTURE_2D, texture(Texture).id ); - m_activetexture = texture(Texture).id; + m_activetexture = Texture; #else if( texture( Texture ).bind() == resource_state::good ) { m_activetexture = Texture; diff --git a/openglmatrixstack.h b/openglmatrixstack.h index b57f545b..c8131b3e 100644 --- a/openglmatrixstack.h +++ b/openglmatrixstack.h @@ -51,6 +51,10 @@ public: translate( glm::vec3 const &Translation ) { m_stack.top() = glm::translate( m_stack.top(), Translation ); upload(); } + void + load(glm::mat4 const &Matrix) { + m_stack.top() = Matrix; + upload(); } void multiply( glm::mat4 const &Matrix ) { m_stack.top() *= Matrix; @@ -131,6 +135,11 @@ public: multiply( Type_ const *Matrix ) { m_stacks[ m_mode ].multiply( glm::make_mat4( Matrix ) ); } + template + void + load(Type_ const *Matrix) { + m_stacks[m_mode].load( + glm::make_mat4(Matrix)); } template void perspective( Type_ const Fovy, Type_ const Aspect, Type_ const Znear, Type_ const Zfar ) { @@ -179,5 +188,6 @@ extern opengl_matrices OpenGLMatrices; #define glMultMatrixf OpenGLMatrices.multiply #define gluPerspective OpenGLMatrices.perspective #define gluLookAt OpenGLMatrices.look_at +#define glLoadMatrixf OpenGLMatrices.load //--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index 4b65d11a..a1bdf8d6 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -22,6 +22,8 @@ http://mozilla.org/MPL/2.0/. #include "usefull.h" #include "World.h" +#include + opengl_renderer GfxRenderer; extern TWorld World; @@ -101,10 +103,29 @@ opengl_renderer::Init( GLFWwindow *Window ) { Global::daylight.color.x = 255.0f / 255.0f; Global::daylight.color.y = 242.0f / 255.0f; Global::daylight.color.z = 231.0f / 255.0f; - - shader = gl_program_light({ gl_shader("lighting.vert"), gl_shader("blinnphong.frag") }); Global::daylight.intensity = 1.0f; //m7todo: przenieść + shader = gl_program_light({ gl_shader("lighting.vert"), gl_shader("blinnphong.frag") }); + depth_shader = gl_program_mvp({ gl_shader("shadowmap.vert"), gl_shader("empty.frag") }); + active_shader = &shader; + + glGenFramebuffers(1, &depth_fbo); + glGenTextures(1, &depth_tex); + glBindTexture(GL_TEXTURE_2D, depth_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, + 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, depth_tex); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); // preload some common textures WriteLog( "Loading common gfx data..." ); @@ -139,30 +160,68 @@ opengl_renderer::Render() { ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); ::glDepthFunc( GL_LEQUAL ); - ::glMatrixMode( GL_PROJECTION ); // select the Projection Matrix - ::gluPerspective( - Global::FieldOfView / Global::ZoomFactor, + ::glMatrixMode( GL_PROJECTION ); + glm::mat4 perspective = glm::perspective( + glm::radians(Global::FieldOfView / Global::ZoomFactor), std::max( 1.0f, (float)Global::ScreenWidth ) / std::max( 1.0f, (float)Global::ScreenHeight ), 0.1f * Global::ZoomFactor, m_drawrange * Global::fDistanceFactor ); + glLoadMatrixf(glm::value_ptr(perspective)); - ::glMatrixMode( GL_MODELVIEW ); // Select The Modelview Matrix + ::glMatrixMode( GL_MODELVIEW ); ::glLoadIdentity(); if( World.InitPerformed() ) { + glDebug("rendering shadow map"); + glDisable(GL_FRAMEBUFFER_SRGB); + glViewport(0, 0, 1024, 1024); + + glm::mat4 depthproj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 0.1f, 100.0f); + glm::vec3 playerpos = glm::vec3(World.Camera.Pos.x, World.Camera.Pos.y, World.Camera.Pos.z); + glm::vec3 shadoweye = playerpos - Global::daylight.direction * 50.0f; + Global::SetCameraPosition(Math3D::vector3(shadoweye)); + glm::mat4 depthcam = glm::lookAt(shadoweye, + playerpos, + glm::vec3(0.0f, 1.0f, 0.0f)); + m_camera.update_frustum(depthproj, depthcam); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glm::value_ptr(depthproj)); + glMatrixMode(GL_MODELVIEW); + glMultMatrixf(glm::value_ptr(glm::mat4(glm::mat3(depthcam)))); + + glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo); + glClear(GL_DEPTH_BUFFER_BIT); + active_shader = &depth_shader; depth_shader.bind(); + Render(&World.Ground); + active_shader = nullptr; depth_shader.unbind(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, Global::ScreenWidth, Global::ScreenHeight); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glm::value_ptr(perspective)); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, depth_tex); + glActiveTexture(GL_TEXTURE0); glm::dmat4 worldcamera; World.Camera.SetMatrix( worldcamera ); - m_camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), worldcamera ); - // frustum tests are performed in 'world space' but after we set up frustum - // we no longer need camera translation, only rotation - ::glMultMatrixd( glm::value_ptr( glm::dmat4( glm::dmat3( worldcamera )))); + m_camera.update_frustum( OpenGLMatrices.data( GL_PROJECTION ), worldcamera); + ::glMultMatrixd(glm::value_ptr(glm::dmat4(glm::dmat3(worldcamera)))); glDebug("rendering environment"); glDisable(GL_FRAMEBUFFER_SRGB); Render( &World.Environment ); glDebug("rendering world"); - shader.bind(); glEnable(GL_FRAMEBUFFER_SRGB); + shader.bind(); active_shader = &shader; + + glm::vec3 transdiff = Global::daylight.direction * 50.0f; + glm::mat3 rotdiff = glm::inverse(glm::mat3(depthcam)) * glm::mat3(worldcamera); + glm::mat4 lv = depthproj * glm::translate(glm::mat4(rotdiff), transdiff); + + shader.set_lightview(lv); Render( &World.Ground ); glDebug("rendering cab"); @@ -174,7 +233,7 @@ opengl_renderer::Render() { } glDebug("rendering ui"); - shader.unbind(); + gl_program::unbind(); active_shader = nullptr; glEnable(GL_FRAMEBUFFER_SRGB); UILayer.render(); glDebug("rendering end"); @@ -364,7 +423,7 @@ opengl_renderer::Texture( texture_handle const Texture ) { bool opengl_renderer::Render( TGround *Ground ) { - shader.set_p(OpenGLMatrices.data(GL_PROJECTION)); + active_shader->set_p(OpenGLMatrices.data(GL_PROJECTION)); ::glEnable( GL_LIGHTING ); ::glDisable( GL_BLEND ); @@ -525,7 +584,7 @@ opengl_renderer::Render( TGroundNode *Node ) { } auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - shader.set_mv(glm::translate(OpenGLMatrices.data(GL_MODELVIEW), glm::vec3(originoffset.x, originoffset.y, originoffset.z))); + active_shader->set_mv(glm::translate(OpenGLMatrices.data(GL_MODELVIEW), glm::vec3(originoffset.x, originoffset.y, originoffset.z))); switch (Node->iType) { @@ -722,16 +781,14 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, Math3D: void opengl_renderer::Render(TSubModel *Submodel) { - shader.set_mv(OpenGLMatrices.data(GL_MODELVIEW)); - shader.set_p(OpenGLMatrices.data(GL_PROJECTION)); + active_shader->copy_gl_mvp(); Render(Submodel, OpenGLMatrices.data(GL_MODELVIEW)); shader.set_material(0.0f, glm::vec3(0.0f)); } void opengl_renderer::Render_Alpha(TSubModel *Submodel) { - shader.set_mv(OpenGLMatrices.data(GL_MODELVIEW)); - shader.set_p(OpenGLMatrices.data(GL_PROJECTION)); + active_shader->copy_gl_mvp();; Render_Alpha(Submodel, OpenGLMatrices.data(GL_MODELVIEW)); shader.set_material(0.0f, glm::vec3(0.0f)); } @@ -750,7 +807,7 @@ opengl_renderer::Render( TSubModel *Submodel, glm::mat4 m) { mm *= glm::make_mat4(Submodel->fMatrix->e); if (Submodel->b_Anim) Submodel->RaAnimation(mm, Submodel->b_Anim); - shader.set_mv(mm); + active_shader->set_mv(mm); } if( Submodel->eType < TP_ROTATOR ) { @@ -796,6 +853,7 @@ opengl_renderer::Render( TSubModel *Submodel, glm::mat4 m) { gl_program::unbind(); glEnableClientState(GL_VERTEX_ARRAY); + glPushMatrix(); glLoadMatrixf(glm::value_ptr(mm)); glVertexPointer(3, GL_FLOAT, sizeof(basic_vertex), static_cast(nullptr)); // pozycje @@ -814,6 +872,7 @@ opengl_renderer::Render( TSubModel *Submodel, glm::mat4 m) { // post-draw reset ::glPopAttrib(); glDisableClientState(GL_VERTEX_ARRAY); + glPopMatrix(); gl_program::bind_last(); } @@ -848,7 +907,7 @@ opengl_renderer::Render( TSubModel *Submodel, glm::mat4 m) { Render( Submodel->Child, mm ); if( Submodel->iFlags & 0xC000 ) - shader.set_mv(m); + active_shader->set_mv(m); } if( Submodel->b_Anim < at_SecondsJump ) @@ -960,7 +1019,7 @@ opengl_renderer::Render_Alpha( TGroundNode *Node ) { } auto const originoffset = Node->m_rootposition - Global::pCameraPosition; - shader.set_mv(glm::translate(OpenGLMatrices.data(GL_MODELVIEW), glm::vec3(originoffset.x, originoffset.y, originoffset.z))); + active_shader->set_mv(glm::translate(OpenGLMatrices.data(GL_MODELVIEW), glm::vec3(originoffset.x, originoffset.y, originoffset.z))); switch (Node->iType) { @@ -1196,7 +1255,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel, glm::mat4 m) { mm *= glm::make_mat4(Submodel->fMatrix->e); if (Submodel->b_Anim) Submodel->RaAnimation(mm, Submodel->b_Anim); - shader.set_mv(mm); + active_shader->set_mv(mm); } if( Submodel->eType < TP_ROTATOR ) { @@ -1250,6 +1309,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel, glm::mat4 m) { glm::mat4 x = glm::mat4(1.0f); x = glm::translate(x, glm::vec3(lightcenter.x, lightcenter.y, lightcenter.z)); // początek układu zostaje bez zmian x = glm::rotate(x, atan2(lightcenter.x, lightcenter.y), glm::vec3(0.0f, 1.0f, 0.0f)); // jedynie obracamy w pionie o kąt + glPushMatrix(); glLoadMatrixf(glm::value_ptr(x)); // main draw call @@ -1262,6 +1322,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel, glm::mat4 m) { + CameraUp_worldspace * squareVertices.y * BillboardSize.y; // ...etc instead IF we had easy access to camera's forward and right vectors. TODO: check if Camera matrix is accessible */ + glPopMatrix(); ::glPopAttrib(); glDisableClientState(GL_VERTEX_ARRAY); @@ -1276,7 +1337,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel, glm::mat4 m) { Render_Alpha( Submodel->Child, mm ); if( Submodel->iFlags & 0xC000 ) - shader.set_mv(m); + active_shader->set_mv(m); } if( Submodel->b_aAnim < at_SecondsJump ) diff --git a/renderer.h b/renderer.h index 47629987..b931a8ab 100644 --- a/renderer.h +++ b/renderer.h @@ -61,6 +61,9 @@ class opengl_renderer { public: gl_program_light shader; + gl_program_mvp depth_shader; + gl_program_mvp *active_shader = nullptr; + GLuint depth_tex, depth_fbo; // types diff --git a/shader.cpp b/shader.cpp index 384ef958..eae3d2ee 100644 --- a/shader.cpp +++ b/shader.cpp @@ -131,9 +131,12 @@ void gl_program_mvp::copy_gl_mvp() void gl_program_mvp::set_mv(const glm::mat4 &m) { - glm::mat3 mvn = glm::mat3(glm::transpose(glm::inverse(m))); + if (mvn_uniform != -1) + { + glm::mat3 mvn = glm::mat3(glm::transpose(glm::inverse(m))); + glUniformMatrix3fv(mvn_uniform, 1, GL_FALSE, glm::value_ptr(mvn)); + } glUniformMatrix4fv(mv_uniform, 1, GL_FALSE, glm::value_ptr(m)); - glUniformMatrix3fv(mvn_uniform, 1, GL_FALSE, glm::value_ptr(mvn)); } void gl_program_mvp::set_p(const glm::mat4 &m) @@ -145,6 +148,9 @@ gl_program_light::gl_program_light(std::vector v) : gl_program_mvp(v) { bind(); + 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"); @@ -167,22 +173,36 @@ gl_program_light::gl_program_light(std::vector v) : gl_program_mvp(v) glUniform1ui(lcount_uniform, 0); } +void gl_program_light::set_lightview(glm::mat4 &lightview) +{ + if (current_program != this) + return; + + glUniformMatrix4fv(lightview_uniform, 1, GL_FALSE, glm::value_ptr(lightview)); +} + void gl_program_light::set_ambient(glm::vec3 &ambient) { - bind(); + if (current_program != this) + return; + glUniform3fv(ambient_uniform, 1, glm::value_ptr(ambient)); } void gl_program_light::set_fog(float density, glm::vec3 &color) { - bind(); + 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) { - bind(); + if (current_program != this) + return; + glUniform1ui(lcount_uniform, count); } @@ -190,12 +210,14 @@ void gl_program_light::set_light(GLuint i, type t, glm::vec3 &pos, glm::vec3 &di float in_cutoff, float out_cutoff, 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); - bind(); 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)); @@ -208,7 +230,9 @@ void gl_program_light::set_light(GLuint i, type t, glm::vec3 &pos, glm::vec3 &di void gl_program_light::set_material(float specular, glm::vec3 &emission) { - bind(); + if (current_program != this) + return; + glUniform1f(specular_uniform, specular); glUniform3fv(emission_uniform, 1, glm::value_ptr(emission)); } \ No newline at end of file diff --git a/shader.h b/shader.h index ccfecb4e..c25de290 100644 --- a/shader.h +++ b/shader.h @@ -35,7 +35,7 @@ public: class gl_program_mvp : public gl_program { GLuint mv_uniform; - GLuint mvn_uniform; + GLint mvn_uniform; GLuint p_uniform; public: @@ -62,6 +62,7 @@ public: gl_program_light() = default; gl_program_light(std::vector); + void set_lightview(glm::mat4 &lightview); void set_ambient(glm::vec3 &ambient); void gl_program_light::set_fog(float density, glm::vec3 &color); void set_material(float specular, glm::vec3 &emission); @@ -70,6 +71,7 @@ public: glm::vec3 &color, float linear, float quadratic); private: + GLuint lightview_uniform; GLuint ambient_uniform; GLuint specular_uniform; GLuint fog_color_uniform; diff --git a/shaders/blinnphong.frag b/shaders/blinnphong.frag index a0c7619b..01fd8593 100644 --- a/shaders/blinnphong.frag +++ b/shaders/blinnphong.frag @@ -23,10 +23,12 @@ struct light_s in vec3 f_normal; in vec2 f_coord; in vec3 f_pos; +in vec4 f_light_pos; out vec4 color; uniform sampler2D tex; +uniform sampler2D shadowmap; uniform vec3 ambient; uniform vec3 emission; @@ -37,6 +39,16 @@ uniform float specular; uniform light_s lights[8]; uniform uint lights_count; +float calc_shadow() +{ + vec3 coords = f_light_pos.xyz / f_light_pos.w; + coords = coords * 0.5 + 0.5; + float closest_depth = texture(shadowmap, coords.xy).r; + float current_depth = coords.z; + float shadow = current_depth > closest_depth ? 0.0 : 1.0; + return shadow; +} + vec3 apply_fog(vec3 color) { float sun_amount = 0.0; @@ -90,6 +102,7 @@ float calc_dir_light(light_s light) void main() { + float shadow = calc_shadow(); vec3 result = ambient * 0.3 + emission; for (uint i = 0U; i < lights_count; i++) { @@ -103,7 +116,7 @@ void main() else if (light.type == LIGHT_DIR) part = calc_dir_light(light); - result += light.color * part; + result += light.color * part * shadow; } vec4 tex_color = texture(tex, f_coord); diff --git a/shaders/empty.frag b/shaders/empty.frag new file mode 100644 index 00000000..67abb5f7 --- /dev/null +++ b/shaders/empty.frag @@ -0,0 +1,7 @@ +#version 330 + +in vec3 f_pos; + +void main() +{ +} \ No newline at end of file diff --git a/shaders/lighting.vert b/shaders/lighting.vert index 6d0d2139..e5ddf030 100644 --- a/shaders/lighting.vert +++ b/shaders/lighting.vert @@ -7,7 +7,9 @@ layout (location = 2) in vec2 v_coord; out vec3 f_normal; out vec2 f_coord; out vec3 f_pos; +out vec4 f_light_pos; +uniform mat4 lightview; uniform mat4 modelview; uniform mat3 modelviewnormal; uniform mat4 projection; @@ -18,4 +20,6 @@ void main() f_normal = modelviewnormal * v_normal; f_coord = v_coord; f_pos = vec3(modelview * vec4(v_vert, 1.0f)); + //f_light_pos = lightview * vec4(f_pos, 1.0f); + f_light_pos = lightview * vec4(f_pos, 1.0f); } \ No newline at end of file diff --git a/shaders/shadowmap.vert b/shaders/shadowmap.vert new file mode 100644 index 00000000..6911bde9 --- /dev/null +++ b/shaders/shadowmap.vert @@ -0,0 +1,13 @@ +#version 330 + +layout (location = 0) in vec3 v_vert; + +out vec3 f_pos; + +uniform mat4 modelview; +uniform mat4 projection; + +void main() +{ + gl_Position = (projection * modelview) * vec4(v_vert, 1.0f); +} \ No newline at end of file