From c455d3194890742a7da536db96085a0cfeaa9b7f Mon Sep 17 00:00:00 2001 From: Anselme Date: Sun, 13 Dec 2015 17:10:44 +0100 Subject: [PATCH] implemented most of shadowmaps code in the shaders and in forwardmodule.cpp --- deferredmodule.cpp | 2 +- forward.frag.glsl | 19 ++++- forward.vert.glsl | 9 +++ forwardmodule.cpp | 174 +++++++++++++++++++++++++++---------------- forwardmodule.h | 15 +--- framebuffer.cpp | 7 +- framebuffer.h | 2 +- light.cpp | 55 ++++++++++++-- light.h | 66 +++++++++++----- posteffectmodule.cpp | 2 +- shadersource.cpp | 26 +++++-- 11 files changed, 261 insertions(+), 116 deletions(-) diff --git a/deferredmodule.cpp b/deferredmodule.cpp index 22feb0e..2c83463 100644 --- a/deferredmodule.cpp +++ b/deferredmodule.cpp @@ -25,7 +25,7 @@ GBuffer::GBuffer(int width, int height) : FrameBuffer() tex->setFiltering(GL_NEAREST); addTexture(tex, GL_DEPTH_ATTACHMENT); - initGL(); + initColorAttachments(); } GBuffer::~GBuffer() diff --git a/forward.frag.glsl b/forward.frag.glsl index a9ed8de..e77ea04 100644 --- a/forward.frag.glsl +++ b/forward.frag.glsl @@ -35,6 +35,11 @@ in mat3 tangentSpace; in vec3 varNormal; #endif +#ifdef SHADOWMAP +uniform sampler2D shadowMap; +in vec4 posInLightSpace; +#endif + in vec2 varTexCoord; in vec3 lightDirInView; @@ -48,6 +53,11 @@ vec3 phongLighting(in vec3 kd, in vec3 ks, in float ns, in vec3 color, in vec3 n return color*diffuseComponent*(kd+ks*pow(specularComponent, ns)); } +float computeShadow(sampler2D shadowmap, vec3 shadow){ + float lightFragDepth = texture(shadowmap, shadow.xy).r; + return lightFragDepth < shadow.z ? 0 : 1; +} + void main(void) { #ifdef ALPHA_MASK if(texture(alphaMask, varTexCoord).r < 0.5) @@ -56,6 +66,7 @@ void main(void) { #ifdef NORMAL_MAP vec3 normal = normalize(texture(normalMap, varTexCoord).xyz * tangentSpace); + normal = normalize(vec3(0, 0, 1) * tangentSpace); #else vec3 normal = normalize(varNormal); #endif @@ -78,10 +89,16 @@ void main(void) { vec3 specular = materialKs; #endif +#ifdef SHADOWMAP + float shadow = computeShadow(shadowMap, posInLightSpace.xyz/posInLightSpace.w); +#else + float shadow = 1; +#endif + #ifdef AMBIENT_LIGHT outColor = vec4(0, 0, 0, 1); #else vec3 light = phongLighting(diffuse, specular, materialNs, lightColor, normal, lightDirInView, halfVecInView); - outColor = vec4(light, 1); + outColor = vec4(shadow*light, 1); #endif } diff --git a/forward.vert.glsl b/forward.vert.glsl index ce90c07..2309270 100644 --- a/forward.vert.glsl +++ b/forward.vert.glsl @@ -34,6 +34,11 @@ out vec3 lightDirInView; out vec3 halfVecInView; #endif +#ifdef SHADOWMAP +uniform mat4 lightMVP; +out vec4 posInLightSpace; +#endif + void main(void) { vec3 posInView = vec3(modelViewMatrix*vec4(inPosition, 1.0)); @@ -42,6 +47,10 @@ void main(void) { halfVecInView = normalize(lightDirInView - normalize(posInView)); #endif +#ifdef SHADOWMAP + posInLightSpace = lightMVP * vec4(inPosition, 1.0); +#endif + #ifdef POINT_LIGHT vec4 lightPosInView = viewMatrix*vec4(pointLight, 1); lightDirInView = normalize(lightPosInView.xyz - posInView); diff --git a/forwardmodule.cpp b/forwardmodule.cpp index 20ce682..05132fd 100644 --- a/forwardmodule.cpp +++ b/forwardmodule.cpp @@ -5,6 +5,7 @@ #include "shader.h" #include "light.h" #include "glassert.h" +#include "texture.h" #include const char* const ForwardModule::flagStr[] = @@ -16,13 +17,6 @@ const char* const ForwardModule::flagStr[] = "ALPHA_MASK" }; -const char* const ForwardModule::lightStr[] = -{ - "AMBIENT_LIGHT", - "DIRECTIONNAL_LIGHT", - "POINT_LIGHT" -}; - void ForwardModule::renderGL(Camera* myCamera, Scene* scene) { // bind target @@ -32,7 +26,7 @@ void ForwardModule::renderGL(Camera* myCamera, Scene* scene) glAssert(glDepthFunc(GL_LESS)); glAssert(glDisable(GL_BLEND)); - lightPass(myCamera, scene, NULL, AMBIENT_LIGHT); + lightPass(myCamera, scene, NULL); // render directionnal lighting and point lighting glAssert(glDepthFunc(GL_LEQUAL)); @@ -40,38 +34,56 @@ void ForwardModule::renderGL(Camera* myCamera, Scene* scene) glAssert(glBlendFunc(GL_ONE, GL_ONE)); glAssert(glDepthMask(GL_FALSE)); - for(SceneIterator* lightIt = scene->getLights(); - lightIt->isValid(); lightIt->next()) - { - Light* l = lightIt->getItem(); - unsigned int type = l->isDirectionnal() ? DIRECTIONNAL_LIGHT : POINT_LIGHT; - lightPass(myCamera, scene, l, type); - } + for(SceneIterator* lightIt = scene->getLights(); lightIt->isValid(); lightIt->next()) + lightPass(myCamera, scene, lightIt->getItem()); glAssert(glDisable(GL_BLEND)); glAssert(glDepthFunc(GL_LESS)); glAssert(glDepthMask(GL_TRUE)); } -void ForwardModule::lightPass(Camera* myCamera, Scene* scene, Light* light, unsigned int type) +void ForwardModule::lightPass(Camera* myCamera, Scene* scene, Light* light) { // loop over all types of geometry - for(int i=0; ibind(); + // bind light attributes - if(type == DIRECTIONNAL_LIGHT) - shader->bindVec3(shader->getLocation("dirLight"), light->getDir()); - if(type == POINT_LIGHT) - shader->bindVec3(shader->getLocation("pointLight"), light->getPos()); - glm::vec3 color; - if(type == AMBIENT_LIGHT) - color = glm::vec3(0.1f); // add attribute, and setter for ambient lighting + if(light == NULL) + { + // ambient light + shader->bindVec3(shader->getLocation("lightColor"), glm::vec3(0.1f)); // add attribute, and setter for ambient lighting + } else - color = light->getColor(); - shader->bindVec3(shader->getLocation("lightColor"), color); + { + switch(light->getType()) + { + case Light::DIRECTIONNAL: + shader->bindVec3(shader->getLocation("dirLight"), light->getDir()); + shader->bindVec3(shader->getLocation("lightColor"), light->getColor()); + if(light->isShadowCaster()) + { + light->getShadowMap()->bind(NB_FLAGS); // NB_FLAGS has the value of the first available slot after the phong material texture slots + shader->bindInteger(shader->getLocation("shadowMap"), NB_FLAGS); + } + break; + case Light::POINT: + shader->bindVec3(shader->getLocation("pointLight"), light->getPos()); + shader->bindVec3(shader->getLocation("lightColor"), light->getColor()); + // TODO add attenuation + break; + case Light::SPOT: + shader->bindVec3(shader->getLocation("lightColor"), light->getColor()); + // TODO add cutoff and attenuation + break; + } + } for(SceneIterator* entityIt = scene->getGeometry(); entityIt->isValid(); entityIt->next()) { @@ -80,18 +92,23 @@ void ForwardModule::lightPass(Camera* myCamera, Scene* scene, Light* light, unsi glm::mat4 modelViewMatrix = myCamera->getViewMatrix() * entity->modelMatrix; glm::mat4 mvp = myCamera->getProjectionMatrix() * modelViewMatrix; glm::mat4 normalMatrix = glm::transpose(glm::inverse(modelViewMatrix)); + if(light != NULL && light->isShadowCaster()) + { + glm::mat4 lightMVP = light->getProjectionMatrix() * (light->getViewMatrix() * entity->modelMatrix); + shader->bindMat4(shader->getLocation("lightMVP"), lightMVP); + } + shader->bindMat4(shader->getLocation("viewMatrix"), myCamera->getViewMatrix()); + shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix); + shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix)); + shader->bindMat4(shader->getLocation("MVP"), mvp); // loop over material groups for(int j=0; jgetMesh()->indiceGroups.size(); ++j) { Material* mat = entity->getMesh()->indiceGroups[j].material; - if(mat->getFlags() == flags[i]) + if(mat->getFlags() == geometryFlagList[i]) { // bind material attributes mat->bindAttributes(shader); - shader->bindMat4(shader->getLocation("viewMatrix"), myCamera->getViewMatrix()); - shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix); - shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix)); - shader->bindMat4(shader->getLocation("MVP"), mvp); // draw geometry entity->drawGroup(j); } @@ -111,17 +128,18 @@ void ForwardModule::setShaderSource(ShaderSource* source) void ForwardModule::compileShaders(Scene* scene) { - flags.clear(); + geometryFlagList.clear(); + lightFlagList.clear(); for(Shader* s : shaders) delete(s); shaders.clear(); - int size = 1 << NB_FLAGS; - bool geometryFlags[size]; - for(int i=0; i* entityIt = scene->getGeometry(); entityIt->isValid(); entityIt->next()) { @@ -129,36 +147,62 @@ void ForwardModule::compileShaders(Scene* scene) for(Mesh::Group &g : m->indiceGroups) geometryFlags[g.material->getFlags()] = true; } - - // shader compilation - for(int i=0; i* lightIt = scene->getLights(); + lightIt->isValid(); lightIt->next()) + { + Light* l = lightIt->getItem(); + lightFlags[Light::getFlags(l)] = true; + } + for(int i=0; i defines; + + // set geometry defines + if(i & NORMAL_MAP_FLAG) + defines.push_back(flagStr[NORMAL_MAP]); + if(i & AMBIENT_TEXTURE_FLAG) + defines.push_back(flagStr[AMBIENT_TEXTURE]); + if(i & DIFFUSE_TEXTURE_FLAG) + defines.push_back(flagStr[DIFFUSE_TEXTURE]); + if(i & SPECULAR_TEXTURE_FLAG) + defines.push_back(flagStr[SPECULAR_TEXTURE]); + if(i & ALPHA_MASK_FLAG) + defines.push_back(flagStr[ALPHA_MASK]); + + int boundary = defines.size(); + for(int j : lightFlagList) { - std::vector defines; - defines.push_back(lightStr[AMBIENT_LIGHT]); - - // set defines - if(i & NORMAL_MAP_FLAG) - defines.push_back(flagStr[NORMAL_MAP]); - if(i & AMBIENT_TEXTURE_FLAG) - defines.push_back(flagStr[AMBIENT_TEXTURE]); - if(i & DIFFUSE_TEXTURE_FLAG) - defines.push_back(flagStr[DIFFUSE_TEXTURE]); - if(i & SPECULAR_TEXTURE_FLAG) - defines.push_back(flagStr[SPECULAR_TEXTURE]); - if(i & ALPHA_MASK_FLAG) - defines.push_back(flagStr[ALPHA_MASK]); - - // for each geometry flag, 3 shaders are compiled, one for each kind of lighting - flags.push_back(i); - // ambient - shaders.push_back(shaderSources->compile(defines.size(), defines.data())); - // directionnal - defines[0] = lightStr[DIRECTIONNAL_LIGHT]; - shaders.push_back(shaderSources->compile(defines.size(), defines.data())); - // point - defines[0] = lightStr[POINT_LIGHT]; + while(defines.size() > boundary) + defines.pop_back(); + // set light defines + for(int k=0; kcompile(defines.size(), defines.data())); } } diff --git a/forwardmodule.h b/forwardmodule.h index 2cf3605..027fc4b 100644 --- a/forwardmodule.h +++ b/forwardmodule.h @@ -32,24 +32,15 @@ public: void setRenderTarget(FrameBuffer* target); private: - enum { - // light flags - AMBIENT_LIGHT, - DIRECTIONNAL_LIGHT, - POINT_LIGHT, - // count - NB_LIGHT_FLAGS - }; - static const char* const flagStr[NB_FLAGS]; - static const char* const lightStr[NB_LIGHT_FLAGS]; ShaderSource* shaderSources; std::vector shaders; - std::vector flags; + std::vector geometryFlagList; + std::vector lightFlagList; const FrameBuffer* renderTarget; - void lightPass(Camera* myCamera, Scene* scene, Light* light, unsigned int type); + void lightPass(Camera* myCamera, Scene* scene, Light* light); }; #endif // FORWARDMODULE_H diff --git a/framebuffer.cpp b/framebuffer.cpp index 36d4b93..7771a31 100644 --- a/framebuffer.cpp +++ b/framebuffer.cpp @@ -22,13 +22,14 @@ void FrameBuffer::addTexture(Texture* tex, GLenum attachment) textures.push_back(tex); bindFBO(); glAssert(glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, tex->getTarget(), tex->getId(), 0)); - attachments.push_back(attachment); + if(attachment != GL_DEPTH_ATTACHMENT) + attachments.push_back(attachment); } } -void FrameBuffer::initGL() +void FrameBuffer::initColorAttachments() { - if(fbo != 0) + if(fbo != 0 && attachments.size() != 0) { bindFBO(); glAssert(glDrawBuffers(attachments.size(), attachments.data())); diff --git a/framebuffer.h b/framebuffer.h index cea23c6..962ec4e 100644 --- a/framebuffer.h +++ b/framebuffer.h @@ -20,7 +20,7 @@ public: FrameBuffer(); ~FrameBuffer(); void addTexture(Texture* tex, GLenum attachment); - void initGL(); + void initColorAttachments(); void bindFBO() const; Texture* getTexture(int texId); diff --git a/light.cpp b/light.cpp index 0034197..8dced5a 100644 --- a/light.cpp +++ b/light.cpp @@ -9,6 +9,14 @@ #include "glassert.h" #include +const char* Light::flagStr[] = { + "AMBIENT_LIGHT", + "DIRECTIONNAL_LIGHT", + "POINT_LIGHT", + "SPOT_LIGHT", + "SHADOWMAP" +}; + Light::Light() { initPointLight(); @@ -16,37 +24,43 @@ Light::Light() void Light::initDirectionnalLight(glm::vec3 dir, glm::vec3 lightColor) { + type = DIRECTIONNAL; + position = glm::vec3(0); direction = dir; color = lightColor; shadowCaster = false; isDir = true; + viewMatrix = glm::lookAt(position, position+direction, glm::vec3(0, 1, 0)); } void Light::initPointLight(glm::vec3 pos, glm::vec3 lightColor) { + type = POINT; position = pos; - angle = 360; + cutOffAngle = 360; color = lightColor; shadowCaster = false; isDir = false; + viewMatrix = glm::mat4(); } -/* + void Light::initSpotLight(glm::vec3 pos, glm::vec3 dir, float spotAngle, glm::vec3 lightColor) { + type = SPOT; position = pos; direction = dir; - angle = spotAngle; + cutOffAngle = spotAngle; color = lightColor; shadowCaster = false; isDir = false; } -*/ + bool Light::isDirectionnal() { return isDir; } -void Light::initShadowMap(int resWidth, int resHeight) +void Light::initShadowMap(int resWidth, int resHeight, glm::vec3 dim) { shadowCaster = true; shadowMap = new FrameBuffer(); @@ -54,7 +68,7 @@ void Light::initShadowMap(int resWidth, int resHeight) Texture* tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resWidth, resHeight, GL_FLOAT); tex->setFiltering(GL_NEAREST); shadowMap->addTexture(tex, GL_DEPTH_ATTACHMENT); - shadowMap->initGL(); + shadowMap->initColorAttachments(); ShaderSource source; source.setSource(vertSource, ShaderSource::VERTEX); @@ -67,7 +81,7 @@ void Light::initShadowMap(int resWidth, int resHeight) void Light::generateShadowMap(Scene* scene) { - glm::mat4 viewMatrix = glm::lookAt(position, position+direction, glm::vec3(0, 1, 0)); + viewMatrix = glm::lookAt(position, position+direction, glm::vec3(0, 1, 0)); shadowMap->bindFBO(); glAssert(glEnable(GL_DEPTH_TEST)); @@ -77,7 +91,7 @@ void Light::generateShadowMap(Scene* scene) // compute matrix attributes PhongEntity* entity = entityIt->getItem(); glm::mat4 modelViewMatrix = viewMatrix * entity->modelMatrix; - glm::mat4 mvp = /*myCamera->getProjectionMatrix() * */modelViewMatrix; + glm::mat4 mvp = projectionMatrix * modelViewMatrix; // loop over material groups for(int j=0; jgetMesh()->indiceGroups.size(); ++j) { @@ -104,6 +118,31 @@ Texture* Light::getShadowMap() return shadowMap->getTexture(0); } +unsigned int Light::getFlags(Light* l) +{ + if(l == NULL) + return 1 << AMBIENT_FLAG; + else + { + unsigned int flags = 0; + switch(l->getType()) + { + case DIRECTIONNAL : + flags |= 1 << DIRECTIONNAL_FLAG; + break; + case POINT : + flags |= 1 << POINT_FLAG; + break; + case SPOT : + flags |= 1 << SPOT_FLAG; + break; + } + if(l->isShadowCaster()) + flags |= 1 << SHADOWMAP_FLAG; + return flags; + } +} + const char* Light::vertSource = "#version 330 core\n\ layout(location = 0)in vec3 inPosition;\n\ diff --git a/light.h b/light.h index 0d1a3de..58eb127 100644 --- a/light.h +++ b/light.h @@ -2,20 +2,65 @@ #define LIGHT_H #include +#include #include +#include "camera.h" class FrameBuffer; class Shader; class Scene; class Texture; -class Light +class Light : public Camera { +public: + enum LightType { + DIRECTIONNAL, + POINT, + SPOT + }; + + enum LightFlags { + AMBIENT_FLAG, + DIRECTIONNAL_FLAG, + POINT_FLAG, + SPOT_FLAG, + SHADOWMAP_FLAG, + NB_LIGHT_FLAGS + }; + static const char* flagStr[]; + + Light(); + void initDirectionnalLight(glm::vec3 dir = glm::vec3(1, 0, 0), glm::vec3 lightColor = glm::vec3(1)); + void initPointLight(glm::vec3 pos = glm::vec3(0), glm::vec3 lightColor = glm::vec3(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)); + + bool isDirectionnal(); + LightType getType() {return type;} + glm::vec3 getDir() {return direction;} + glm::vec3 getPos() {return position;} + glm::vec3 getColor() {return color;} + + bool isShadowCaster() {return shadowCaster;} + void initShadowMap(int resWidth, int resHeight); + void generateShadowMap(Scene* scene); + Texture* getShadowMap(); + + // camera inheritance + virtual glm::mat4 getProjectionMatrix() {return projectionMatrix;} + virtual glm::mat4 getViewMatrix() {return viewMatrix;} + // does nothing, just required for inheriting Camera + virtual void resize(int width, int height) {} + + static unsigned int getFlags(Light* l); private: // standard attributes + LightType type; + glm::vec3 position; glm::vec3 direction; - float angle; // spotlight not supported yet + float cutOffAngle; + float attenuation; glm::vec3 color; bool isDir; @@ -24,23 +69,10 @@ private: bool shadowCaster; FrameBuffer* shadowMap; Shader* shaders[2]; + glm::mat4 viewMatrix; + glm::mat4 projectionMatrix; static const char* vertSource; static const char* fragSource; -public: - Light(); - void initDirectionnalLight(glm::vec3 dir = glm::vec3(1, 0, 0), glm::vec3 lightColor = glm::vec3(1)); - void initPointLight(glm::vec3 pos = glm::vec3(0), glm::vec3 lightColor = glm::vec3(1)); - // spotlight not supported yet - //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)); - - bool isDirectionnal(); - glm::vec3 getDir() {return direction;} - glm::vec3 getPos() {return position;} - glm::vec3 getColor() {return color;} - - void initShadowMap(int resWidth, int resHeight); - void generateShadowMap(Scene* scene); - Texture* getShadowMap(); }; #endif // LIGHT_H diff --git a/posteffectmodule.cpp b/posteffectmodule.cpp index 03c4334..e2bd001 100644 --- a/posteffectmodule.cpp +++ b/posteffectmodule.cpp @@ -27,7 +27,7 @@ PostEffectModule::PostEffectModule(int width, int height) tex->setFiltering(GL_NEAREST); inputFBO->addTexture(tex, GL_DEPTH_ATTACHMENT); - inputFBO->initGL(); + inputFBO->initColorAttachments(); outputFBO = FrameBuffer::screen; diff --git a/shadersource.cpp b/shadersource.cpp index 6d27e2d..16b1a00 100644 --- a/shadersource.cpp +++ b/shadersource.cpp @@ -1,5 +1,6 @@ #include "shadersource.h" #include +#include #include #include "shader.h" @@ -58,23 +59,34 @@ std::string ShaderSource::preprocess(std::string source, int nbDefines, const ch std::string compiled = ""; std::istringstream ss(source); std::string line; - bool allowed = true; + std::vector allowedStack; while (std::getline(ss, line)) { if(line.size() > 0 && line.at(0) == '#') { if(line.compare(0, 8, "#version") == 0) compiled.append(line+'\n'); else if(line.compare(0, 7, "#ifdef ") == 0) - allowed = isDefined(line.substr(7), nbDefines, defines); + allowedStack.push_back(isDefined(line.substr(7), nbDefines, defines)); else if(line.compare(0, 8, "#ifndef ") == 0) - allowed = !isDefined(line.substr(8), nbDefines, defines); + allowedStack.push_back(!isDefined(line.substr(8), nbDefines, defines)); else if(line.compare("#endif") == 0) - allowed = true; + allowedStack.pop_back(); else if(line.compare("#else") == 0) - allowed = !allowed; + allowedStack.back() = !allowedStack.back(); + } + else + { + bool ok = true; + for(bool allowed : allowedStack) + { + if(!allowed) + { + ok = false; break; + } + } + if(ok) + compiled.append(line+'\n'); } - else if(allowed) - compiled.append(line+'\n'); } return compiled; }