From 09fa1ee3cbce49ded728a568631745294c0d3101 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 8 Nov 2014 19:47:08 +0100 Subject: [PATCH] Implement scattering for point light --- data/shaders/pointlightscatter.frag | 46 +++++++++++++++++++++++++++++ src/graphics/irr_driver.hpp | 1 + src/graphics/render.cpp | 2 +- src/graphics/render_lighting.cpp | 35 ++++++++++++++++++++++ src/graphics/shaders.cpp | 35 ++++++++++++++++++++++ src/graphics/shaders.hpp | 8 +++++ 6 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 data/shaders/pointlightscatter.frag diff --git a/data/shaders/pointlightscatter.frag b/data/shaders/pointlightscatter.frag new file mode 100644 index 000000000..2d6ee6cba --- /dev/null +++ b/data/shaders/pointlightscatter.frag @@ -0,0 +1,46 @@ +uniform sampler2D dtex; +uniform float density; +uniform vec3 fogcol; + +flat in vec3 center; +flat in float energy; +flat in vec3 col; +flat in float radius; + +out vec4 Fog; + +vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix); + +void main() +{ + vec4 pseudocenter = ViewMatrix * vec4(center.xyz, 1.0); + pseudocenter /= pseudocenter.w; + vec3 light_pos = pseudocenter.xyz; + vec3 light_col = col.xyz; + + // Compute pixel position + vec2 texc = 2. * gl_FragCoord.xy / screen; + float z = texture(dtex, texc).x; + vec4 pixelpos = getPosFromUVDepth(vec3(texc, z), InverseProjectionMatrix); + vec3 eyedir = -normalize(pixelpos.xyz); + + vec3 farthestpoint = - eyedir * (min(dot(-eyedir, light_pos) + radius, length(pixelpos.xyz))); + vec3 closestpoint = - eyedir * (dot(-eyedir, light_pos) - radius); + if (closestpoint.z < 1.) closestpoint = vec3(0.); + + float stepsize = length(farthestpoint - closestpoint) / 16; + vec3 fog = vec3(0.); + vec3 xpos = farthestpoint; + + for (int i = 0; i < 16; i++) + { + float d = distance(light_pos, xpos); + float l = (16 - i) * stepsize; + float att = energy * 20. / (1. + d * d); + att *= max((radius - d) / radius, 0.); + fog += density * light_col * att * exp(- density * d) * exp(- density * l) * stepsize; + xpos += stepsize * eyedir; + } + + Fog = vec4(fogcol * fog, 1.); +} diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index ca1747a20..d530002af 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -408,6 +408,7 @@ private: void renderGlow(std::vector& glows); void renderSSAO(); void renderLights(unsigned pointlightCount, bool hasShadow); + void renderLightsScatter(unsigned pointlightCount); void renderShadowsDebug(); void doScreenShot(); void PrepareDrawCalls(scene::ICameraSceneNode *camnode); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 654f8d6f5..10d9e9530 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -420,7 +420,7 @@ void IrrDriver::renderScene(scene::ICameraSceneNode * const camnode, unsigned po World::getWorld()->isFogEnabled()) { PROFILER_PUSH_CPU_MARKER("- Fog", 0xFF, 0x00, 0x00); - m_post_processing->renderFog(); + renderLightsScatter(pointlightcount); PROFILER_POP_CPU_MARKER(); } diff --git a/src/graphics/render_lighting.cpp b/src/graphics/render_lighting.cpp index 0d0ac9a6e..32749a468 100644 --- a/src/graphics/render_lighting.cpp +++ b/src/graphics/render_lighting.cpp @@ -185,3 +185,38 @@ void IrrDriver::renderSSAO() m_post_processing->renderGaussian17TapBlur(irr_driver->getFBO(FBO_HALF1_R), irr_driver->getFBO(FBO_HALF2_R)); } + +void IrrDriver::renderLightsScatter(unsigned pointlightcount) +{ + getFBO(FBO_HALF1).Bind(); + glClearColor(0., 0., 0., 0.); + glClear(GL_COLOR_BUFFER_BIT); + m_post_processing->renderFog(); + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + const Track * const track = World::getWorld()->getTrack(); + + const float start = track->getFogStart(); + const video::SColor tmpcol = track->getFogColor(); + core::vector3df col(1., 1., 1.); + + glUseProgram(LightShader::PointLightScatterShader::getInstance()->Program); + glBindVertexArray(LightShader::PointLightScatterShader::getInstance()->vao); + + LightShader::PointLightScatterShader::getInstance()->SetTextureUnits(irr_driver->getDepthStencilTexture()); + LightShader::PointLightScatterShader::getInstance()->setUniforms(1. / (40. * start), col); + + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, pointlightcount); + + glDisable(GL_BLEND); + m_post_processing->renderGaussian6Blur(getFBO(FBO_HALF1), getFBO(FBO_HALF2), 5., 5.); + + glEnable(GL_BLEND); + getFBO(FBO_COLORS).Bind(); + m_post_processing->renderPassThrough(getRenderTargetTexture(RTT_HALF1)); +} \ No newline at end of file diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 14f2cf4cf..9a575159f 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -1468,6 +1468,41 @@ namespace LightShader glVertexAttribDivisorARB(attrib_Color, 1); glVertexAttribDivisorARB(attrib_Radius, 1); } + + PointLightScatterShader::PointLightScatterShader() + { + Program = LoadProgram(OBJECT, + GL_VERTEX_SHADER, file_manager->getAsset("shaders/pointlight.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/pointlightscatter.frag").c_str()); + + AssignUniforms("density", "fogcol"); + AssignSamplerNames(Program, 0, "dtex"); + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glBindBuffer(GL_ARRAY_BUFFER, PointLightShader::getInstance()->vbo); + + GLuint attrib_Position = glGetAttribLocation(Program, "Position"); + GLuint attrib_Color = glGetAttribLocation(Program, "Color"); + GLuint attrib_Energy = glGetAttribLocation(Program, "Energy"); + GLuint attrib_Radius = glGetAttribLocation(Program, "Radius"); + + glEnableVertexAttribArray(attrib_Position); + glVertexAttribPointer(attrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), 0); + glEnableVertexAttribArray(attrib_Energy); + glVertexAttribPointer(attrib_Energy, 1, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(3 * sizeof(float))); + glEnableVertexAttribArray(attrib_Color); + glVertexAttribPointer(attrib_Color, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(4 * sizeof(float))); + glEnableVertexAttribArray(attrib_Radius); + glVertexAttribPointer(attrib_Radius, 1, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(7 * sizeof(float))); + + glVertexAttribDivisorARB(attrib_Position, 1); + glVertexAttribDivisorARB(attrib_Energy, 1); + glVertexAttribDivisorARB(attrib_Color, 1); + glVertexAttribDivisorARB(attrib_Radius, 1); + } } diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index e6bb2e07f..de0eb71bf 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -328,6 +328,14 @@ namespace LightShader GLuint vao; PointLightShader(); }; + + class PointLightScatterShader : public ShaderHelperSingleton, public TextureRead + { + public: + GLuint vbo; + GLuint vao; + PointLightScatterShader(); + }; } namespace ParticleShader