second iteration of Light refactoring

This commit is contained in:
Anselme 2016-06-13 16:52:11 +02:00
parent dcb95d1644
commit 4f4d4da876
6 changed files with 220 additions and 139 deletions

View File

@ -34,31 +34,7 @@ void ForwardModule::renderGL(Camera* myCamera, Scene* scene)
} }
Shader *shader = p.shader; Shader *shader = p.shader;
shader->bind(); shader->bind();
switch(light->getType()) light->bindAttributes(shader, myCamera);
{
case Light::AMBIENT:
shader->bindVec3(shader->getLocation("lightColor"), light->getColor()); // add attribute, and setter for ambient lighting
break;
case Light::DIRECTIONNAL:
shader->bindVec3(shader->getLocation("dirLight"), -light->getDir());
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
if(light->isShadowCaster())
{
light->getShadowMapTexture()->bind(PhongMaterial::NB_PHONG_SLOTS); // NB_PHONG_SLOTS has the value of the first available slot after the phong material texture slots
shader->bindInteger(shader->getLocation("shadowMap"), PhongMaterial::NB_PHONG_SLOTS);
}
break;
case Light::POINT:
shader->bindVec3(shader->getLocation("pointLight"), light->getPos());
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
shader->bindFloat(shader->getLocation("attenuation"), light->getAttenuation());
break;
case Light::SPOT:
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
shader->bindFloat(shader->getLocation("attenuation"), light->getAttenuation());
shader->bindFloat(shader->getLocation("cutoff"), light->getCutoffAngle());
break;
}
unsigned int id = 2; unsigned int id = 2;
for(GeometryNode *node : p.geometry) for(GeometryNode *node : p.geometry)
{ {
@ -71,8 +47,6 @@ void ForwardModule::renderGL(Camera* myCamera, Scene* scene)
glm::mat4 modelViewMatrix = myCamera->getViewMatrix() * node->modelMatrix; glm::mat4 modelViewMatrix = myCamera->getViewMatrix() * node->modelMatrix;
glm::mat4 mvp = myCamera->getProjectionMatrix() * modelViewMatrix; glm::mat4 mvp = myCamera->getProjectionMatrix() * modelViewMatrix;
glm::mat4 normalMatrix = glm::transpose(glm::inverse(modelViewMatrix)); glm::mat4 normalMatrix = glm::transpose(glm::inverse(modelViewMatrix));
if(light != NULL && light->isShadowCaster())
light->bindShadowMap(Shader *shader);
shader->bindMat4(shader->getLocation("viewMatrix"), myCamera->getViewMatrix()); shader->bindMat4(shader->getLocation("viewMatrix"), myCamera->getViewMatrix());
shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix); shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix);
shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix)); shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix));

View File

@ -21,7 +21,7 @@ class ForwardModule : public Module
public: public:
ForwardModule() : shaderSources(NULL) ForwardModule() : shaderSources(NULL)
{ {
ambientLight.initAmbientLight();
} }
virtual void renderGL(Camera* myCamera, Scene* scene); virtual void renderGL(Camera* myCamera, Scene* scene);
@ -48,7 +48,7 @@ private:
std::unordered_map<unsigned int, std::vector<GeometryNode*>> geometry; std::unordered_map<unsigned int, std::vector<GeometryNode*>> geometry;
std::unordered_map<unsigned int, std::vector<Light*>> lights; std::unordered_map<unsigned int, std::vector<Light*>> lights;
Light ambientLight; AmbientLight ambientLight;
std::vector<Pass> passes; std::vector<Pass> passes;
ShaderSource* shaderSources; ShaderSource* shaderSources;

View File

@ -6,6 +6,7 @@
#include "shadersource.h" #include "shadersource.h"
#include "phongmaterial.h" #include "phongmaterial.h"
#include "mesh.h" #include "mesh.h"
#include "camera.h"
#include <resource.h> #include <resource.h>
#include <glm/ext.hpp> #include <glm/ext.hpp>
@ -16,7 +17,8 @@ const char* Light::flagStr[] = {
"DIRECTIONNAL_LIGHT", "DIRECTIONNAL_LIGHT",
"POINT_LIGHT", "POINT_LIGHT",
"SPOT_LIGHT", "SPOT_LIGHT",
"SHADOWMAP" "SHADOWMAP",
"CASCADED"
}; };
const glm::mat4 Light::biasMatrix( const glm::mat4 Light::biasMatrix(
@ -25,55 +27,192 @@ const glm::mat4 Light::biasMatrix(
0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0); 0.5, 0.5, 0.5, 1.0);
Light::Light() void AmbientLight::bindAttributes(Shader *shader, Camera *camera)
{ {
initAmbientLight(); shader->bindVec3(shader->getLocation("lightColor"), m_color);
} }
void Light::initAmbientLight(glm::vec3 lightColor) int DirectionnalLight::m_shaderRefCounter = 0;
DirectionnalLight::DirectionnalLight(glm::vec3 dir, glm::vec3 lightColor) :
m_direction(dir),
m_shadowCaster(false)
{ {
m_type = AMBIENT;
m_position = glm::vec3(0); // not used
m_direction = glm::vec3(0, 0, 1); // not used
m_cutOffAngle = 0; // not used
m_color = lightColor; m_color = lightColor;
m_attenuation = 0; // not used m_shadowMap = NULL;
m_shadowCaster = false; // not used
} }
void Light::initDirectionnalLight(glm::vec3 dir, glm::vec3 lightColor) void DirectionnalLight::bindAttributes(Shader *shader, Camera *camera)
{ {
m_type = DIRECTIONNAL; glm::vec4 direction = glm::vec4(m_direction, 0.f);
m_position = glm::vec3(0); // not used shader->bindVec3(shader->getLocation("dirLight"), glm::normalize(glm::vec3(camera->getViewMatrix()*direction)));
m_direction = dir; if(m_shadowCaster)
m_cutOffAngle = 0; // not used {
m_color = lightColor; switch(m_projectionMatrices.size())
m_attenuation = 0; // not used {
m_shadowCaster = false; case 1:
{
m_shadowMap->getTexture(0)->bind(5); // TODO use something else than 5
shader->bindInteger(shader->getLocation("shadowMap"), 5);
glm::mat4 viewToLightMatrix = Light::biasMatrix * m_projectionMatrices[0] * m_viewMatrices[0] * glm::inverse(camera->getViewMatrix());
shader->bindMat4(shader->getLocation("viewToLightMatrix"), viewToLightMatrix);
}
break;
case 3:
{
m_shadowMap->getTexture(0)->bind(5); // TODO use something else than 5
shader->bindInteger(shader->getLocation("shadowMap"), 5);
glm::mat4 lightMVP;
lightMVP = Light::biasMatrix * m_projectionMatrices[0] * (m_viewMatrices[0] * glm::inverse(camera->getViewMatrix()));
shader->bindMat4(shader->getLocation("frontShadowMVP"), lightMVP);
lightMVP = Light::biasMatrix * m_projectionMatrices[1] * (m_viewMatrices[1] * glm::inverse(camera->getViewMatrix()));
shader->bindMat4(shader->getLocation("midShadowMVP"), lightMVP);
lightMVP = Light::biasMatrix * m_projectionMatrices[2] * (m_viewMatrices[2] * glm::inverse(camera->getViewMatrix()));
shader->bindMat4(shader->getLocation("backShadowMVP"), lightMVP);
}
break;
default:
break;
}
}
} }
void Light::initPointLight(glm::vec3 pos, glm::vec3 lightColor, float att) unsigned int DirectionnalLight::getFlags()
{ {
m_type = POINT; unsigned int flag = 1 << DIRECTIONNAL_FLAG;
m_position = pos; if(m_shadowCaster)
m_direction = glm::vec3(0, 0, 1); // used to orient the shadowmap flag |= 1 << SHADOWMAP_FLAG;
m_cutOffAngle = 0; // not used if(m_projectionMatrices.size() == 3)
m_color = lightColor; flag |= 1 << CASCADED_FLAG;
m_attenuation = att; return flag;
m_shadowCaster = false;
} }
void Light::initSpotLight(glm::vec3 pos, glm::vec3 dir, float spotAngle, glm::vec3 lightColor, float att) void DirectionnalLight::initShadowMap(int resolution, bool isCascaded)
{ {
m_type = SPOT; m_shadowMapResolution = resolution;
m_position = pos;
m_direction = dir; // shader compilation
m_cutOffAngle = spotAngle; if(m_shaderRefCounter == 0)
m_color = lightColor; {
m_attenuation = att; ShaderSource source;
m_shadowCaster = false; Resource::ResourceMap shaderMap;
Resource::getResourcePack_shaders(shaderMap);
source.setSource(shaderMap["shaders/shadow.vert.glsl"], ShaderSource::VERTEX);
source.setSource(shaderMap["shaders/shadow.frag.glsl"], ShaderSource::FRAGMENT);
unsigned int flag = 1 << DIRECTIONNAL_FLAG;
m_shaders[0] = source.compile(Mesh::MESH_3D, flag);
m_shaders[1] = source.compile(Mesh::MESH_3D & Mesh::MATERIAL_ALPHA_MASK, flag);
source.setSource(shaderMap["shaders/shadow.geom.glsl"], ShaderSource::GEOMETRY);
flag |= 1 << CASCADED_FLAG;
m_shaders[2] = source.compile(Mesh::MESH_3D, flag);
m_shaders[3] = source.compile(Mesh::MESH_3D & Mesh::MATERIAL_ALPHA_MASK, flag);
}
if(!m_shadowCaster)
++m_shaderRefCounter;
m_shadowCaster = true;
if(isCascaded)
m_viewMatrices.resize(3);
else
m_viewMatrices.resize(1);
// Depth buffer
Texture *tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resolution, resolution, GL_FLOAT, isCascaded ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D);
if(isCascaded)
{
tex->bind();
for(int i=0; i<3; ++i)
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT, resolution, resolution, i, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
}
tex->setFiltering(GL_LINEAR);
tex->setWrap(GL_CLAMP_TO_EDGE);
tex->setParameter(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
tex->setParameter(GL_TEXTURE_COMPARE_FUNC, GL_LESS);
// framebuffer
m_shadowCaster = true;
m_shadowMap = new FrameBuffer();
m_shadowMap->addTexture(tex, GL_DEPTH_ATTACHMENT);
m_shadowMap->initColorAttachments();
} }
void DirectionnalLight::destroyShadowMap()
{
if(m_shadowCaster)
{
m_shadowCaster = false;
--m_shaderRefCounter;
if(m_shaderRefCounter == 0)
{
for(int i=0; i<4; ++i)
delete m_shaders[i];
}
if(m_shadowMap != NULL)
delete m_shadowMap;
}
m_viewMatrices.clear();
m_projectionMatrices.clear();
m_shadowMap = NULL;
}
void DirectionnalLight::setShadowView(glm::vec3 dim, glm::vec3 center)
{
m_viewMatrices[0] = glm::lookAt(center, center-m_direction, glm::vec3(0, 1, 0));
m_projectionMatrices[0] = glm::ortho(-dim.x/2, dim.x/2, -dim.y/2, dim.y/2, -dim.z/2, dim.z/2);
}
void DirectionnalLight::setCascadedShadowView(Camera *camera)
{
// TODO find projection bounding boxes and define the 3 shadowmap views
}
void DirectionnalLight::updateShadowMap(Scene* scene)
{
bool hasCascades = m_projectionMatrices.size() == 3;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glViewport(0, 0, m_shadowMapResolution, m_shadowMapResolution);
m_shadowMap->bindFBO();
glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
for(SceneIterator<GeometryNode*>* geometryIt = scene->getGeometry();
geometryIt->isValid(); geometryIt->next())
{
GeometryNode* node = geometryIt->getItem();
if(node->mesh->getFlags() & (1 << Mesh::MESH_SHADOWED))
{
int hasAlpha = (node->mesh->getFlags() & (1 << Mesh::MATERIAL_ALPHA_MASK)) > 0;
// compute matrix attributes
if(hasCascades)
{
m_shaders[hasAlpha+2]->bind();
glm::mat4 lightMVP;
lightMVP = m_projectionMatrices[0] * (m_viewMatrices[0] * node->modelMatrix);
m_shaders[hasAlpha]->bindMat4(m_shaders[hasAlpha]->getLocation("frontShadowMVP"), lightMVP);
lightMVP = m_projectionMatrices[1] * (m_viewMatrices[1] * node->modelMatrix);
m_shaders[hasAlpha]->bindMat4(m_shaders[hasAlpha]->getLocation("midShadowMVP"), lightMVP);
lightMVP = m_projectionMatrices[2] * (m_viewMatrices[2] * node->modelMatrix);
m_shaders[hasAlpha]->bindMat4(m_shaders[hasAlpha]->getLocation("backShadowMVP"), lightMVP);
node->mesh->draw(m_shaders[hasAlpha], false, hasAlpha, false);
}
else
{
m_shaders[hasAlpha]->bind();
glm::mat4 lightMVP = m_projectionMatrices[0] * (m_viewMatrices[0] * node->modelMatrix);
m_shaders[hasAlpha]->bindMat4(m_shaders[hasAlpha]->getLocation("MVP"), lightMVP);
node->mesh->draw(m_shaders[hasAlpha], false, hasAlpha, false);
}
}
}
}
// OLD IMPLEMENTATION
/*
void Light::initShadowMap(int resolution, glm::vec3 dim) void Light::initShadowMap(int resolution, glm::vec3 dim)
{ {
m_shadowMapResolution = resolution; m_shadowMapResolution = resolution;
@ -212,3 +351,4 @@ unsigned int Light::getFlags()
flags |= 1 << SHADOWMAP_FLAG; flags |= 1 << SHADOWMAP_FLAG;
return flags; return flags;
} }
*/

View File

@ -10,6 +10,7 @@ class FrameBuffer;
class Shader; class Shader;
class Scene; class Scene;
class Texture; class Texture;
class Camera;
class Light class Light
{ {
@ -27,6 +28,7 @@ public:
POINT_FLAG, POINT_FLAG,
SPOT_FLAG, SPOT_FLAG,
SHADOWMAP_FLAG, SHADOWMAP_FLAG,
CASCADED_FLAG,
NB_FLAGS NB_FLAGS
}; };
static const char* flagStr[]; static const char* flagStr[];
@ -38,7 +40,7 @@ public:
virtual bool isShadowCaster() { return false; } virtual bool isShadowCaster() { return false; }
virtual void bindAttributes(Shader *shader) = 0; virtual void bindAttributes(Shader *shader, Camera *camera) = 0;
virtual unsigned int getFlags() = 0; virtual unsigned int getFlags() = 0;
@ -49,81 +51,42 @@ protected:
class AmbientLight : public Light class AmbientLight : public Light
{ {
public: public:
AmbientLight(glm::vec3 lightColor = glm::vec3(0.1f)) : m_color(lightColor) {} AmbientLight(glm::vec3 lightColor = glm::vec3(0.1f)) { m_color = lightColor; }
virtual LightType getType() { return AMBIENT; } virtual LightType getType() { return AMBIENT; }
virtual void bindAttributes(Shader *shader) virtual void bindAttributes(Shader *shader, Camera *camera);
{ shader->bindVec3(shader->getLocation("lightColor"), m_color); }
virtual unsigned int getFlags() { return 1 << AMBIENT_FLAG; } virtual unsigned int getFlags() { return 1 << AMBIENT_FLAG; }
}; };
class ShadowableLight : public Light class DirectionnalLight : public Light
{ {
public: public:
// enables shadowmapping on this light DirectionnalLight(glm::vec3 dir = glm::vec3(0, -1, 0), glm::vec3 lightColor = glm::vec3(1));
virtual void initShadowMap(int resolution, glm::vec3 dim = glm::vec3(1)) = 0;
// disables shadowmapping on this light
virtual void destroyShadowMap() = 0;
// returns true is shadowmapping is enabled on this light
virtual bool isShadowCaster() { return m_shadowCaster; }
// updates the shadowmap if shadowmapping is enabled
virtual void updateShadowMap(Scene* scene) = 0;
protected:
bool m_shadowCaster;
};
class Light
{
public:
Light();
void initAmbientLight(glm::vec3 lightColor = glm::vec3(0.1f));
void initDirectionnalLight(glm::vec3 dir = glm::vec3(0, -1, 0), glm::vec3 lightColor = glm::vec3(1));
void initPointLight(glm::vec3 pos = glm::vec3(0), glm::vec3 lightColor = glm::vec3(1), float att = 1);
void initSpotLight(glm::vec3 pos = glm::vec3(0), glm::vec3 dir = glm::vec3(1, 0, 0), float spotAngle = 360, glm::vec3 lightColor = glm::vec3(1), float att = 1);
glm::vec3 getDir() { return m_direction; } glm::vec3 getDir() { return m_direction; }
glm::vec3 getPos() { return m_position; }
glm::vec3 getColor() { return m_color; } virtual LightType getType() { return DIRECTIONNAL; }
float getAttenuation() { return m_attenuation; } virtual void bindAttributes(Shader *shader, Camera *camera);
float getCutoffAngle() { return m_cutOffAngle; } virtual unsigned int getFlags();
bool isShadowCaster() {return m_shadowCaster;} void initShadowMap(int resolution, bool isCascaded = false);
void initShadowMap(int resolution, glm::vec3 dim = glm::vec3(1)); void destroyShadowMap();
void generateShadowMap(Scene* scene); void setShadowView(glm::vec3 dim = glm::vec3(1), glm::vec3 center = glm::vec3(0));
void bindShadowMap(Shader *shader); void setCascadedShadowView(Camera *camera);
Texture* getShadowMapTexture(); void updateShadowMap(Scene* scene);
void setAttenuation(float a) { m_attenuation = a; }
void setCutoffAngle(float c) { m_cutOffAngle = c; }
void setPosition(glm::vec3 new_pos);
void setColor(glm::vec3 new_color) {m_color = new_color;}
/**
* @brief getFlags returns the flags that defines the specificities of the light
*/
unsigned int getFlags();
private: private:
// standard attributes
LightType m_type;
glm::vec3 m_position;
glm::vec3 m_direction; glm::vec3 m_direction;
float m_cutOffAngle;
float m_attenuation; glm::vec3 m_center;
glm::vec3 m_color;
// shadowmap attributes
bool m_shadowCaster; bool m_shadowCaster;
int m_shadowMapResolution; int m_shadowMapResolution;
FrameBuffer* m_shadowMap; FrameBuffer* m_shadowMap;
Shader* m_shaders[2];
std::vector<glm::mat4> m_viewMatrices; std::vector<glm::mat4> m_viewMatrices;
glm::mat4 m_projectionMatrix; std::vector<glm::mat4> m_projectionMatrices;
static int m_shaderRefCounter;
static Shader* m_shaders[4];
}; };
#endif // LIGHT_H #endif // LIGHT_H

View File

@ -8,7 +8,7 @@ Texture::Texture(GLenum format,
int height, int height,
GLenum dataType, GLenum dataType,
GLenum texTarget) : GLenum texTarget) :
m_texSlot(0), m_texUnit(0),
m_target(texTarget), m_target(texTarget),
m_format(format), m_format(format),
m_internal_format(internal_format), m_internal_format(internal_format),
@ -37,11 +37,13 @@ Texture::Texture(GLenum format,
setWrap(GL_CLAMP_TO_EDGE); setWrap(GL_CLAMP_TO_EDGE);
setFiltering(GL_LINEAR); setFiltering(GL_LINEAR);
break; break;
default:
break;
} }
} }
Texture::Texture(Image* myImage, bool makeMipMaps) : Texture::Texture(Image* myImage, bool makeMipMaps) :
m_texSlot(0), m_texUnit(0),
m_target(GL_TEXTURE_2D), m_target(GL_TEXTURE_2D),
m_width(myImage->width), m_width(myImage->width),
m_height(myImage->height), m_height(myImage->height),
@ -58,7 +60,7 @@ Texture::Texture(Image* myImage, bool makeMipMaps) :
} }
Texture::Texture(Image* myCubemapImages[6], bool makeMipMaps) : Texture::Texture(Image* myCubemapImages[6], bool makeMipMaps) :
m_texSlot(0), m_texUnit(0),
m_target(GL_TEXTURE_CUBE_MAP), m_target(GL_TEXTURE_CUBE_MAP),
m_width(myCubemapImages[0]->width), m_width(myCubemapImages[0]->width),
m_height(myCubemapImages[0]->height), m_height(myCubemapImages[0]->height),
@ -76,7 +78,7 @@ Texture::Texture(Image* myCubemapImages[6], bool makeMipMaps) :
} }
Texture::Texture(Texture* tex, bool halfDim) : Texture::Texture(Texture* tex, bool halfDim) :
m_texSlot(0), m_texUnit(0),
m_target(tex->m_target), m_target(tex->m_target),
m_format(tex->m_format), m_format(tex->m_format),
m_internal_format(tex->m_internal_format), m_internal_format(tex->m_internal_format),
@ -135,7 +137,9 @@ void Texture::setFiltering(GLint filter)
void Texture::setParameter(GLenum parameter, GLenum value) void Texture::setParameter(GLenum parameter, GLenum value)
{ {
glTextureParameteri(m_texId, parameter, value); glBindTexture(m_target, m_texId);
glTexParameteri(m_target, parameter, value);
glBindTexture(m_target, 0);
} }
void Texture::createMipMaps() void Texture::createMipMaps()
@ -145,16 +149,16 @@ void Texture::createMipMaps()
setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} }
void Texture::bind(int slot) void Texture::bind(int unit)
{ {
if(slot >= 0) if(unit >= 0)
m_texSlot = slot; m_texUnit = unit;
glActiveTexture(GL_TEXTURE0+m_texSlot); glActiveTexture(GL_TEXTURE0+m_texUnit);
glBindTexture(m_target, m_texId); glBindTexture(m_target, m_texId);
} }
void Texture::unbind() void Texture::unbind()
{ {
glActiveTexture(GL_TEXTURE0+m_texSlot); glActiveTexture(GL_TEXTURE0+m_texUnit);
glBindTexture(m_target, 0); glBindTexture(m_target, 0);
} }

View File

@ -10,7 +10,7 @@ class Texture
{ {
private: private:
GLuint m_texId; GLuint m_texId;
int m_texSlot; int m_texUnit;
GLenum m_target; GLenum m_target;
GLenum m_format; GLenum m_format;
GLenum m_internal_format; GLenum m_internal_format;
@ -19,7 +19,7 @@ private:
GLenum m_dataType; GLenum m_dataType;
bool m_hasMipMaps; bool m_hasMipMaps;
void initPixels(Image* myImage, GLenum textureSlot); void initPixels(Image* myImage, GLenum target);
public: public:
// creates a 2D texture from perlin noise // creates a 2D texture from perlin noise
Texture(); Texture();
@ -38,8 +38,8 @@ public:
Texture(Texture* tex, bool halfDim = false); Texture(Texture* tex, bool halfDim = false);
~Texture(); ~Texture();
void setSlot(int slot) { m_texSlot = slot; } void setUnit(int unit) { m_texUnit = unit; }
void bind(int slot = -1); void bind(int unit = -1);
void unbind(); void unbind();
GLuint getId() {return m_texId;} GLuint getId() {return m_texId;}
GLenum getTarget() {return m_target;} GLenum getTarget() {return m_target;}