diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index 174732010..0c2c9a1cf 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -1,23 +1,16 @@ uniform sampler2D ntex; uniform sampler2D dtex; - -uniform vec4 center[16]; -uniform vec4 col[16]; -uniform float energy[16]; uniform float spec; uniform mat4 invproj; -uniform mat4 viewm; +uniform mat4 ViewMatrix; +uniform vec2 screen; + +flat in vec3 center; +flat in float energy; +flat in vec3 col; -#if __VERSION__ >= 130 -in vec2 uv; out vec4 Diffuse; out vec4 Specular; -#else -varying vec2 uv; -#define Diffuse gl_FragData[0] -#define Specular gl_FragData[1] -#endif - vec3 DecodeNormal(vec2 n) { @@ -27,7 +20,7 @@ vec3 DecodeNormal(vec2 n) } void main() { - vec2 texc = uv; + vec2 texc = gl_FragCoord.xy / screen; float z = texture(dtex, texc).x; vec3 norm = normalize(DecodeNormal(2. * texture(ntex, texc).xy - 1.)); @@ -38,25 +31,23 @@ void main() { vec3 diffuse = vec3(0.), specular = vec3(0.); - for (int i = 0; i < 16; ++i) { - vec4 pseudocenter = viewm * vec4(center[i].xyz, 1.0); - pseudocenter /= pseudocenter.w; - vec3 light_pos = pseudocenter.xyz; - vec3 light_col = col[i].xyz; - float d = distance(light_pos, xpos.xyz); - float att = energy[i] * 200. / (4. * 3.14 * d * d); - float spec_att = (energy[i] + 10.) * 200. / (4. * 3.14 * d * d); + vec4 pseudocenter = ViewMatrix * vec4(center.xyz, 1.0); + pseudocenter /= pseudocenter.w; + vec3 light_pos = pseudocenter.xyz; + vec3 light_col = col.xyz; + float d = distance(light_pos, xpos.xyz); + float att = energy * 200. / (4. * 3.14 * d * d); + float spec_att = (energy + 10.) * 200. / (4. * 3.14 * d * d); - // Light Direction - vec3 L = normalize(xpos.xyz - light_pos); + // Light Direction + vec3 L = normalize(xpos.xyz - light_pos); - float NdotL = max(0.0, dot(norm, -L)); - diffuse += NdotL * light_col * att; - // Reflected light dir - vec3 R = reflect(-L, norm); - float RdotE = max(0.0, dot(R, eyedir)); - specular += pow(RdotE, spec) * light_col * spec_att; - } + float NdotL = max(0.0, dot(norm, -L)); + diffuse += NdotL * light_col * att; + // Reflected light dir + vec3 R = reflect(-L, norm); + float RdotE = max(0.0, dot(R, eyedir)); + specular += pow(RdotE, spec) * light_col * spec_att; Diffuse = vec4(diffuse, 1.); Specular = vec4(specular , 1.); diff --git a/data/shaders/pointlight.vert b/data/shaders/pointlight.vert new file mode 100644 index 000000000..540584c4c --- /dev/null +++ b/data/shaders/pointlight.vert @@ -0,0 +1,38 @@ +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +in vec3 Position; +in float Energy; +in vec3 Color; + +in vec2 Corner; + +flat out vec3 center; +flat out float energy; +flat out vec3 col; + +const float zNear = 1.; + +void main(void) +{ + // Beyond that value, light is too attenuated + float r = 40 * Energy; + center = Position; + energy = Energy; + vec4 Center = ViewMatrix * vec4(Position, 1.); + if (Center.z > zNear) // Light is in front of the cam + { + vec3 UnitCenter = normalize(-Center.xyz); + float clampedR = min(r, Center.z - 1.); + float cosTheta = dot(UnitCenter, vec3(0., 0., -1)); + float d = clampedR / cosTheta; + Center.xyz += d * UnitCenter; + } + else if (Center.z + r > zNear) // Light is behind the cam but in range + { + Center.z = zNear; + // TODO: Change r so that we make the screen aligned quad fits light range. + } + col = Color; + gl_Position = ProjectionMatrix * (Center + r * vec4(Corner, 0., 0.)); +} diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index b03fc3ff9..e4fa28b4a 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -280,28 +280,6 @@ void renderColorLevel(ITexture *in) glEnable(GL_DEPTH_TEST); } -void PostProcessing::renderPointlight(const std::vector &positions, const std::vector &colors, const std::vector &energy) -{ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_DEPTH_TEST); - - glUseProgram(FullScreenShader::PointLightShader::Program); - glBindVertexArray(FullScreenShader::PointLightShader::vao); - - setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); - setTexture(1, getDepthTexture(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); - FullScreenShader::PointLightShader::setUniforms(irr_driver->getInvProjMatrix(), irr_driver->getViewMatrix(), positions, colors, energy, 200, 0, 1); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); -} - void PostProcessing::renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff) { glDisable(GL_DEPTH_TEST); diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index 260a2ee26..bac7bdb5c 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -73,7 +73,6 @@ public: void update(float dt); /** Generate diffuse and specular map */ - void renderPointlight(const std::vector &positions, const std::vector &colors, const std::vector &energy); void renderSunlight(); void renderShadowedSunlight(const std::vector &sun_ortho_matrix, unsigned depthtex); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index d64ef292a..aba3241fa 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -744,6 +744,73 @@ void IrrDriver::renderGlow(video::SOverrideMaterial &overridemat, // ---------------------------------------------------------------------------- #define MAXLIGHT 16 // to be adjusted in pointlight.frag too + + +static GLuint pointlightvbo = 0; +static GLuint pointlightsvao = 0; + +struct PointLightInfo +{ + float posX; + float posY; + float posZ; + float energy; + float red; + float green; + float blue; + float padding; +}; + +void createPointLightVAO() +{ + glGenVertexArrays(1, &pointlightsvao); + glBindVertexArray(pointlightsvao); + + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo); + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Corner); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); + + glGenBuffers(1, &pointlightvbo); + glBindBuffer(GL_ARRAY_BUFFER, pointlightvbo); + glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW); + + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Position); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), 0); + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Energy); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Energy, 1, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(3 * sizeof(float))); + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Color); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Color, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(4 * sizeof(float))); + + glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Position, 1); + glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Energy, 1); + glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Color, 1); +} + +static void renderPointLights() +{ + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glUseProgram(MeshShader::PointLightShader::Program); + glBindVertexArray(pointlightsvao); + + setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); + setTexture(1, getDepthTexture(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); + MeshShader::PointLightShader::setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(), irr_driver->getInvProjMatrix(), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 200, 0, 1); + + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, MAXLIGHT); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); +} + +PointLightInfo PointLightsInfo[MAXLIGHT]; + void IrrDriver::renderLights(const core::aabbox3df& cambox, scene::ICameraSceneNode * const camnode, video::SOverrideMaterial &overridemat, @@ -765,9 +832,7 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, const u32 lightcount = m_lights.size(); const core::vector3df &campos = irr_driver->getSceneManager()->getActiveCamera()->getAbsolutePosition(); - std::vector accumulatedLightPos; - std::vector accumulatedLightColor; - std::vector accumulatedLightEnergy; + std::vector BucketedLN[15]; for (unsigned int i = 0; i < lightcount; i++) { @@ -793,7 +858,7 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, { for (unsigned j = 0; j < BucketedLN[i].size(); j++) { - if (++lightnum > MAXLIGHT) + if (++lightnum >= MAXLIGHT) { LightNode* light_node = BucketedLN[i].at(j); light_node->setEnergyMultiplier(0.0f); @@ -809,17 +874,16 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, } const core::vector3df &pos = light_node->getAbsolutePosition(); - accumulatedLightPos.push_back(pos.X); - accumulatedLightPos.push_back(pos.Y); - accumulatedLightPos.push_back(pos.Z); - accumulatedLightPos.push_back(0.); - const core::vector3df &col = light_node->getColor(); + PointLightsInfo[lightnum].posX = pos.X; + PointLightsInfo[lightnum].posY = pos.Y; + PointLightsInfo[lightnum].posZ = pos.Z; - accumulatedLightColor.push_back(col.X); - accumulatedLightColor.push_back(col.Y); - accumulatedLightColor.push_back(col.Z); - accumulatedLightColor.push_back(0.); - accumulatedLightEnergy.push_back(light_node->getEffectiveEnergy()); + PointLightsInfo[lightnum].energy = light_node->getEffectiveEnergy(); + + const core::vector3df &col = light_node->getColor(); + PointLightsInfo[lightnum].red = col.X; + PointLightsInfo[lightnum].green = col.Y; + PointLightsInfo[lightnum].blue = col.Z; } } if (lightnum > MAXLIGHT) @@ -828,19 +892,20 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, break; } } + + lightnum++; + // Fill lights for (; lightnum < MAXLIGHT; lightnum++) { - accumulatedLightPos.push_back(0.); - accumulatedLightPos.push_back(0.); - accumulatedLightPos.push_back(0.); - accumulatedLightPos.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightEnergy.push_back(0.); + PointLightsInfo[lightnum].energy = 0; } - m_post_processing->renderPointlight(accumulatedLightPos, accumulatedLightColor, accumulatedLightEnergy); + + if (!pointlightsvao) + createPointLightVAO(); + glBindVertexArray(pointlightsvao); + glBindBuffer(GL_ARRAY_BUFFER, pointlightvbo); + glBufferSubData(GL_ARRAY_BUFFER, 0, MAXLIGHT * sizeof(PointLightInfo), PointLightsInfo); + renderPointLights(); if (SkyboxCubeMap) m_post_processing->renderDiffuseEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff); // Handle SSAO diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index fcaadc662..f6e3c280e 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -89,6 +89,21 @@ static void initQuadBuffer() glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad_vertex, GL_STATIC_DRAW); } +GLuint SharedObject::billboardvbo = 0; + +static void initBillboardVBO() +{ + float quad[] = { + -.5, -.5, 0., 1., + -.5, .5, 0., 0., + .5, -.5, 1., 1., + .5, .5, 1., 0., + }; + glGenBuffers(1, &(SharedObject::billboardvbo)); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo); + glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad, GL_STATIC_DRAW); +} + void Shaders::loadShaders() { const std::string &dir = file_manager->getAsset(FileManager::SHADER, ""); @@ -215,6 +230,7 @@ void Shaders::loadShaders() initGL(); initQuadVBO(); initQuadBuffer(); + initBillboardVBO(); FullScreenShader::BloomBlendShader::init(); FullScreenShader::BloomShader::init(); FullScreenShader::ColorLevelShader::init(); @@ -227,7 +243,6 @@ void Shaders::loadShaders() FullScreenShader::PenumbraVShader::init(); FullScreenShader::GlowShader::init(); FullScreenShader::PassThroughShader::init(); - FullScreenShader::PointLightShader::init(); FullScreenShader::SSAOShader::init(); FullScreenShader::SunLightShader::init(); FullScreenShader::DiffuseEnvMapShader::init(); @@ -254,6 +269,7 @@ void Shaders::loadShaders() MeshShader::TransparentShader::init(); MeshShader::TransparentFogShader::init(); MeshShader::BillboardShader::init(); + MeshShader::PointLightShader::init(); MeshShader::DisplaceShader::init(); MeshShader::DisplaceMaskShader::init(); MeshShader::ShadowShader::init(); @@ -921,6 +937,47 @@ namespace MeshShader glUniformMatrix4fv(uniform_ipvmat, 1, GL_FALSE, ipvmat.pointer()); glUniform1i(uniform_tex, TU_tex); } + + GLuint PointLightShader::Program; + GLuint PointLightShader::attrib_Position; + GLuint PointLightShader::attrib_Color; + GLuint PointLightShader::attrib_Energy; + GLuint PointLightShader::attrib_Corner; + GLuint PointLightShader::uniform_ntex; + GLuint PointLightShader::uniform_dtex; + GLuint PointLightShader::uniform_spec; + GLuint PointLightShader::uniform_screen; + GLuint PointLightShader::uniform_invproj; + GLuint PointLightShader::uniform_VM; + GLuint PointLightShader::uniform_PM; + + void PointLightShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/pointlight.vert").c_str(), file_manager->getAsset("shaders/pointlight.frag").c_str()); + attrib_Position = glGetAttribLocation(Program, "Position"); + attrib_Color = glGetAttribLocation(Program, "Color"); + attrib_Energy = glGetAttribLocation(Program, "Energy"); + attrib_Corner = glGetAttribLocation(Program, "Corner"); + uniform_ntex = glGetUniformLocation(Program, "ntex"); + uniform_dtex = glGetUniformLocation(Program, "dtex"); + uniform_spec = glGetUniformLocation(Program, "spec"); + uniform_invproj = glGetUniformLocation(Program, "invproj"); + uniform_screen = glGetUniformLocation(Program, "screen"); + uniform_VM = glGetUniformLocation(Program, "ViewMatrix"); + uniform_PM = glGetUniformLocation(Program, "ProjectionMatrix"); + } + + void PointLightShader::setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex) + { + glUniform1f(uniform_spec, 200); + glUniform2f(uniform_screen, screen.X, screen.Y); + glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer()); + glUniformMatrix4fv(uniform_VM, 1, GL_FALSE, ViewMatrix.pointer()); + glUniformMatrix4fv(uniform_PM, 1, GL_FALSE, ProjMatrix.pointer()); + + glUniform1i(uniform_ntex, TU_ntex); + glUniform1i(uniform_dtex, TU_dtex); + } GLuint BillboardShader::Program; GLuint BillboardShader::attrib_corner; @@ -1366,44 +1423,6 @@ namespace FullScreenShader vao = createVAO(Program); } - GLuint PointLightShader::Program; - GLuint PointLightShader::uniform_ntex; - GLuint PointLightShader::uniform_dtex; - GLuint PointLightShader::uniform_center; - GLuint PointLightShader::uniform_col; - GLuint PointLightShader::uniform_energy; - GLuint PointLightShader::uniform_spec; - GLuint PointLightShader::uniform_invproj; - GLuint PointLightShader::uniform_viewm; - GLuint PointLightShader::vao; - - void PointLightShader::init() - { - Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/pointlight.frag").c_str()); - uniform_ntex = glGetUniformLocation(Program, "ntex"); - uniform_dtex = glGetUniformLocation(Program, "dtex"); - uniform_center = glGetUniformLocation(Program, "center[0]"); - uniform_col = glGetUniformLocation(Program, "col[0]"); - uniform_energy = glGetUniformLocation(Program, "energy[0]"); - uniform_spec = glGetUniformLocation(Program, "spec"); - uniform_invproj = glGetUniformLocation(Program, "invproj"); - uniform_viewm = glGetUniformLocation(Program, "viewm"); - vao = createVAO(Program); - } - - void PointLightShader::setUniforms(const core::matrix4 &InvProjMatrix, const core::matrix4 &ViewMatrix, const std::vector &positions, const std::vector &colors, const std::vector &energy, unsigned spec, unsigned TU_ntex, unsigned TU_dtex) - { - glUniform4fv(FullScreenShader::PointLightShader::uniform_center, 16, positions.data()); - glUniform4fv(FullScreenShader::PointLightShader::uniform_col, 16, colors.data()); - glUniform1fv(FullScreenShader::PointLightShader::uniform_energy, 16, energy.data()); - glUniform1f(FullScreenShader::PointLightShader::uniform_spec, 200); - glUniformMatrix4fv(FullScreenShader::PointLightShader::uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer()); - glUniformMatrix4fv(FullScreenShader::PointLightShader::uniform_viewm, 1, GL_FALSE, ViewMatrix.pointer()); - - glUniform1i(FullScreenShader::PointLightShader::uniform_ntex, TU_ntex); - glUniform1i(FullScreenShader::PointLightShader::uniform_dtex, TU_dtex); - } - GLuint SunLightShader::Program; GLuint SunLightShader::uniform_ntex; GLuint SunLightShader::uniform_dtex; diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 8a039fe35..4015fdb3e 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -24,6 +24,11 @@ typedef unsigned int GLuint; using namespace irr; +class SharedObject +{ +public: + static GLuint billboardvbo; +}; namespace MeshShader { class ObjectPass1Shader @@ -222,6 +227,18 @@ public: static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix, const core::matrix4 &ipvmat, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos, unsigned TU_tex); }; +class PointLightShader +{ +public: + static GLuint Program; + static GLuint attrib_Position, attrib_Energy, attrib_Color; + static GLuint attrib_Corner; + static GLuint uniform_ntex, uniform_dtex, uniform_spec, uniform_screen, uniform_invproj, uniform_VM, uniform_PM; + + static void init(); + static void setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex); +}; + class BillboardShader { public: @@ -395,17 +412,6 @@ public: static void init(); }; -class PointLightShader -{ -public: - static GLuint Program; - static GLuint uniform_ntex, uniform_dtex, uniform_center, uniform_col, uniform_energy, uniform_spec, uniform_invproj, uniform_viewm; - static GLuint vao; - - static void init(); - static void setUniforms(const core::matrix4 &InvProjMatrix, const core::matrix4 &ViewMatrix, const std::vector &positions, const std::vector &colors, const std::vector &energy, unsigned spec, unsigned TU_ntex, unsigned TU_dtex); -}; - class SunLightShader { public: diff --git a/src/graphics/stkbillboard.cpp b/src/graphics/stkbillboard.cpp index ee24b1270..2f4d5f578 100644 --- a/src/graphics/stkbillboard.cpp +++ b/src/graphics/stkbillboard.cpp @@ -5,23 +5,13 @@ using namespace irr; -static GLuint billboardvbo; static GLuint billboardvao = 0; static void createbillboardvao() { - float quad[] = { - -.5, -.5, 0., 1., - -.5, .5, 0., 0., - .5, -.5, 1., 1., - .5, .5, 1., 0., - }; - - glGenBuffers(1, &billboardvbo); glGenVertexArrays(1, &billboardvao); glBindVertexArray(billboardvao); - glBindBuffer(GL_ARRAY_BUFFER, billboardvbo); - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo); glEnableVertexAttribArray(MeshShader::BillboardShader::attrib_corner); glEnableVertexAttribArray(MeshShader::BillboardShader::attrib_texcoord); glVertexAttribPointer(MeshShader::BillboardShader::attrib_corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);