diff --git a/src/forwardmodule.cpp b/src/forwardmodule.cpp index 9501440..c8b87a5 100644 --- a/src/forwardmodule.cpp +++ b/src/forwardmodule.cpp @@ -34,31 +34,7 @@ void ForwardModule::renderGL(Camera* myCamera, Scene* scene) } Shader *shader = p.shader; shader->bind(); - switch(light->getType()) - { - 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; - } + light->bindAttributes(shader, myCamera); unsigned int id = 2; 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 mvp = myCamera->getProjectionMatrix() * 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("modelViewMatrix"), modelViewMatrix); shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix)); diff --git a/src/forwardmodule.h b/src/forwardmodule.h index 4998b38..b7fc8ac 100644 --- a/src/forwardmodule.h +++ b/src/forwardmodule.h @@ -21,7 +21,7 @@ class ForwardModule : public Module public: ForwardModule() : shaderSources(NULL) { - ambientLight.initAmbientLight(); + } virtual void renderGL(Camera* myCamera, Scene* scene); @@ -48,7 +48,7 @@ private: std::unordered_map> geometry; std::unordered_map> lights; - Light ambientLight; + AmbientLight ambientLight; std::vector passes; ShaderSource* shaderSources; diff --git a/src/light.cpp b/src/light.cpp index 012bca2..4bfffc8 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -6,6 +6,7 @@ #include "shadersource.h" #include "phongmaterial.h" #include "mesh.h" +#include "camera.h" #include #include @@ -16,7 +17,8 @@ const char* Light::flagStr[] = { "DIRECTIONNAL_LIGHT", "POINT_LIGHT", "SPOT_LIGHT", - "SHADOWMAP" + "SHADOWMAP", + "CASCADED" }; const glm::mat4 Light::biasMatrix( @@ -25,55 +27,192 @@ const glm::mat4 Light::biasMatrix( 0.0, 0.0, 0.5, 0.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_attenuation = 0; // not used - m_shadowCaster = false; // not used + m_shadowMap = NULL; } -void Light::initDirectionnalLight(glm::vec3 dir, glm::vec3 lightColor) +void DirectionnalLight::bindAttributes(Shader *shader, Camera *camera) { - m_type = DIRECTIONNAL; - m_position = glm::vec3(0); // not used - m_direction = dir; - m_cutOffAngle = 0; // not used - m_color = lightColor; - m_attenuation = 0; // not used - m_shadowCaster = false; + glm::vec4 direction = glm::vec4(m_direction, 0.f); + shader->bindVec3(shader->getLocation("dirLight"), glm::normalize(glm::vec3(camera->getViewMatrix()*direction))); + if(m_shadowCaster) + { + switch(m_projectionMatrices.size()) + { + 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; - m_position = pos; - m_direction = glm::vec3(0, 0, 1); // used to orient the shadowmap - m_cutOffAngle = 0; // not used - m_color = lightColor; - m_attenuation = att; - m_shadowCaster = false; + unsigned int flag = 1 << DIRECTIONNAL_FLAG; + if(m_shadowCaster) + flag |= 1 << SHADOWMAP_FLAG; + if(m_projectionMatrices.size() == 3) + flag |= 1 << CASCADED_FLAG; + return flag; } -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_position = pos; - m_direction = dir; - m_cutOffAngle = spotAngle; - m_color = lightColor; - m_attenuation = att; - m_shadowCaster = false; + m_shadowMapResolution = resolution; + + // shader compilation + if(m_shaderRefCounter == 0) + { + ShaderSource source; + 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* 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) { m_shadowMapResolution = resolution; @@ -212,3 +351,4 @@ unsigned int Light::getFlags() flags |= 1 << SHADOWMAP_FLAG; return flags; } +*/ diff --git a/src/light.h b/src/light.h index dc5ec2f..ffd5ed7 100644 --- a/src/light.h +++ b/src/light.h @@ -10,6 +10,7 @@ class FrameBuffer; class Shader; class Scene; class Texture; +class Camera; class Light { @@ -27,6 +28,7 @@ public: POINT_FLAG, SPOT_FLAG, SHADOWMAP_FLAG, + CASCADED_FLAG, NB_FLAGS }; static const char* flagStr[]; @@ -38,7 +40,7 @@ public: virtual bool isShadowCaster() { return false; } - virtual void bindAttributes(Shader *shader) = 0; + virtual void bindAttributes(Shader *shader, Camera *camera) = 0; virtual unsigned int getFlags() = 0; @@ -49,81 +51,42 @@ protected: class AmbientLight : public Light { 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 void bindAttributes(Shader *shader) - { shader->bindVec3(shader->getLocation("lightColor"), m_color); } + virtual void bindAttributes(Shader *shader, Camera *camera); virtual unsigned int getFlags() { return 1 << AMBIENT_FLAG; } }; -class ShadowableLight : public Light +class DirectionnalLight : public Light { public: - // enables shadowmapping on this light - 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); - + DirectionnalLight(glm::vec3 dir = glm::vec3(0, -1, 0), glm::vec3 lightColor = glm::vec3(1)); glm::vec3 getDir() { return m_direction; } - glm::vec3 getPos() { return m_position; } - glm::vec3 getColor() { return m_color; } - float getAttenuation() { return m_attenuation; } - float getCutoffAngle() { return m_cutOffAngle; } - - bool isShadowCaster() {return m_shadowCaster;} - void initShadowMap(int resolution, glm::vec3 dim = glm::vec3(1)); - void generateShadowMap(Scene* scene); - void bindShadowMap(Shader *shader); - Texture* getShadowMapTexture(); - - 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(); + + virtual LightType getType() { return DIRECTIONNAL; } + virtual void bindAttributes(Shader *shader, Camera *camera); + virtual unsigned int getFlags(); + + void initShadowMap(int resolution, bool isCascaded = false); + void destroyShadowMap(); + void setShadowView(glm::vec3 dim = glm::vec3(1), glm::vec3 center = glm::vec3(0)); + void setCascadedShadowView(Camera *camera); + void updateShadowMap(Scene* scene); + private: - // standard attributes - LightType m_type; - - glm::vec3 m_position; glm::vec3 m_direction; - float m_cutOffAngle; - float m_attenuation; - glm::vec3 m_color; - - // shadowmap attributes + + glm::vec3 m_center; + bool m_shadowCaster; int m_shadowMapResolution; FrameBuffer* m_shadowMap; - Shader* m_shaders[2]; std::vector m_viewMatrices; - glm::mat4 m_projectionMatrix; + std::vector m_projectionMatrices; + + static int m_shaderRefCounter; + static Shader* m_shaders[4]; }; #endif // LIGHT_H diff --git a/src/texture.cpp b/src/texture.cpp index 108073f..2c3ee07 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -8,7 +8,7 @@ Texture::Texture(GLenum format, int height, GLenum dataType, GLenum texTarget) : - m_texSlot(0), + m_texUnit(0), m_target(texTarget), m_format(format), m_internal_format(internal_format), @@ -37,11 +37,13 @@ Texture::Texture(GLenum format, setWrap(GL_CLAMP_TO_EDGE); setFiltering(GL_LINEAR); break; + default: + break; } } Texture::Texture(Image* myImage, bool makeMipMaps) : - m_texSlot(0), + m_texUnit(0), m_target(GL_TEXTURE_2D), m_width(myImage->width), m_height(myImage->height), @@ -58,7 +60,7 @@ Texture::Texture(Image* myImage, bool makeMipMaps) : } Texture::Texture(Image* myCubemapImages[6], bool makeMipMaps) : - m_texSlot(0), + m_texUnit(0), m_target(GL_TEXTURE_CUBE_MAP), m_width(myCubemapImages[0]->width), m_height(myCubemapImages[0]->height), @@ -76,7 +78,7 @@ Texture::Texture(Image* myCubemapImages[6], bool makeMipMaps) : } Texture::Texture(Texture* tex, bool halfDim) : - m_texSlot(0), + m_texUnit(0), m_target(tex->m_target), m_format(tex->m_format), m_internal_format(tex->m_internal_format), @@ -135,7 +137,9 @@ void Texture::setFiltering(GLint filter) 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() @@ -145,16 +149,16 @@ void Texture::createMipMaps() setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } -void Texture::bind(int slot) +void Texture::bind(int unit) { - if(slot >= 0) - m_texSlot = slot; - glActiveTexture(GL_TEXTURE0+m_texSlot); + if(unit >= 0) + m_texUnit = unit; + glActiveTexture(GL_TEXTURE0+m_texUnit); glBindTexture(m_target, m_texId); } void Texture::unbind() { - glActiveTexture(GL_TEXTURE0+m_texSlot); + glActiveTexture(GL_TEXTURE0+m_texUnit); glBindTexture(m_target, 0); } diff --git a/src/texture.h b/src/texture.h index 66cb642..e598fca 100644 --- a/src/texture.h +++ b/src/texture.h @@ -10,7 +10,7 @@ class Texture { private: GLuint m_texId; - int m_texSlot; + int m_texUnit; GLenum m_target; GLenum m_format; GLenum m_internal_format; @@ -19,7 +19,7 @@ private: GLenum m_dataType; bool m_hasMipMaps; - void initPixels(Image* myImage, GLenum textureSlot); + void initPixels(Image* myImage, GLenum target); public: // creates a 2D texture from perlin noise Texture(); @@ -38,8 +38,8 @@ public: Texture(Texture* tex, bool halfDim = false); ~Texture(); - void setSlot(int slot) { m_texSlot = slot; } - void bind(int slot = -1); + void setUnit(int unit) { m_texUnit = unit; } + void bind(int unit = -1); void unbind(); GLuint getId() {return m_texId;} GLenum getTarget() {return m_target;}