Use Instancing for lights.

This commit is contained in:
Vincent Lejeune 2014-03-10 23:29:37 +01:00
parent 6cad7339e3
commit 740c251808
8 changed files with 225 additions and 139 deletions

View File

@ -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.);

View File

@ -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.));
}

View File

@ -280,28 +280,6 @@ void renderColorLevel(ITexture *in)
glEnable(GL_DEPTH_TEST);
}
void PostProcessing::renderPointlight(const std::vector<float> &positions, const std::vector<float> &colors, const std::vector<float> &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);

View File

@ -73,7 +73,6 @@ public:
void update(float dt);
/** Generate diffuse and specular map */
void renderPointlight(const std::vector<float> &positions, const std::vector<float> &colors, const std::vector<float> &energy);
void renderSunlight();
void renderShadowedSunlight(const std::vector<core::matrix4> &sun_ortho_matrix, unsigned depthtex);

View File

@ -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<float> accumulatedLightPos;
std::vector<float> accumulatedLightColor;
std::vector<float> accumulatedLightEnergy;
std::vector<LightNode *> 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

View File

@ -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<float> &positions, const std::vector<float> &colors, const std::vector<float> &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;

View File

@ -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<float> &positions, const std::vector<float> &colors, const std::vector<float> &energy, unsigned spec, unsigned TU_ntex, unsigned TU_dtex);
};
class SunLightShader
{
public:

View File

@ -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);