diff --git a/shaders/gbuffer.geom.glsl b/shaders/gbuffer.geom.glsl new file mode 100644 index 0000000..103bf08 --- /dev/null +++ b/shaders/gbuffer.geom.glsl @@ -0,0 +1,22 @@ +#version 330 core + +layout(triangles) in; +layout(triangle_strip, max_vertices = 18) out; + +uniform mat4 view[6]; +uniform mat4 proj; + +// debug parameter +flat out int fcolor_idx; + +void main(void){ + for (int layerId = 0; layerId < 6; ++layerId){ + for (int i = 0; i < gl_in.length(); ++i){ + gl_Layer = layerId; + fcolor_idx = layerId; + gl_Position = proj * view[layerId] * gl_in[i].gl_Position; + EmitVertex(); + } + EndPrimitive(); + } +} diff --git a/src/deferredmodule.cpp b/src/deferredmodule.cpp index 1565024..e4ecef9 100644 --- a/src/deferredmodule.cpp +++ b/src/deferredmodule.cpp @@ -30,6 +30,6 @@ GBuffer::GBuffer(int width, int height) : FrameBuffer() GBuffer::~GBuffer() { - for(Texture* t : textures) + for(Texture* t : m_textures) delete(t); } diff --git a/src/framebuffer.cpp b/src/framebuffer.cpp index c1a1a37..78ed02d 100644 --- a/src/framebuffer.cpp +++ b/src/framebuffer.cpp @@ -6,16 +6,17 @@ const FrameBuffer* FrameBuffer::screen = new FrameBuffer(0); FrameBuffer::FrameBuffer() : - allocated(true) + allocated(true), + m_target(GL_FRAMEBUFFER) { - glGenFramebuffers(1, &fbo); + glGenFramebuffers(1, &m_frameBufferId); } FrameBuffer::~FrameBuffer() { if(allocated) - glDeleteFramebuffers(1, &fbo); - for(Texture* t : textures) + glDeleteFramebuffers(1, &m_frameBufferId); + for(Texture* t : m_textures) { t->unbind(); delete(t); @@ -24,48 +25,45 @@ FrameBuffer::~FrameBuffer() void FrameBuffer::addTexture(Texture* tex, GLenum attachment) { - if(fbo != 0) + if(m_frameBufferId != 0) { - textures.push_back(tex); + m_textures.push_back(tex); bindFBO(); if(tex->isCubeMap()) - { - // TODO - // http://cg.siomax.ru/index.php/computer-graphics/10-one-pass-rendering-to-cube-map - } + glFramebufferTexture(m_target, attachment, tex->getId(), 0); else - { glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, tex->getTarget(), tex->getId(), 0); - if(attachment != GL_DEPTH_ATTACHMENT) // TODO stencil attachment must be tested too - attachments.push_back(attachment); - } - + if((attachment != GL_DEPTH_ATTACHMENT && attachment != GL_STENCIL_ATTACHMENT) && attachment != GL_DEPTH_STENCIL_ATTACHMENT) + m_attachments.push_back(attachment); } } void FrameBuffer::initColorAttachments() { - if(fbo != 0 && attachments.size() != 0) + if(m_frameBufferId != 0 && m_attachments.size() != 0) { bindFBO(); - glDrawBuffers(attachments.size(), attachments.data()); + glDrawBuffers(m_attachments.size(), m_attachments.data()); } else + { glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } check(); } void FrameBuffer::deleteTextures() { - for(Texture* t : textures) + for(Texture* t : m_textures) delete(t); - textures.clear(); + m_textures.clear(); glDrawBuffer(GL_NONE); } -void FrameBuffer::bindFBO(GLenum target) const +void FrameBuffer::bindFBO() const { - glBindFramebuffer(target, fbo); + glBindFramebuffer(m_target, m_frameBufferId); } bool FrameBuffer::check() @@ -100,8 +98,8 @@ bool FrameBuffer::check() Texture* FrameBuffer::getTexture(int texId) { - if(fbo != 0) - return textures[texId]; + if(m_frameBufferId != 0) + return m_textures[texId]; else return NULL; } diff --git a/src/framebuffer.h b/src/framebuffer.h index 23f69d6..381ce62 100644 --- a/src/framebuffer.h +++ b/src/framebuffer.h @@ -15,9 +15,10 @@ protected: bool check(); const bool allocated; - GLuint fbo; - std::vector textures; - std::vector attachments; + GLenum m_target; + GLuint m_frameBufferId; + std::vector m_textures; + std::vector m_attachments; public: /** @@ -30,7 +31,7 @@ public: /** * @brief this constructor is only used to get a handle on an existing Framebuffer created by another library */ - FrameBuffer(GLuint id) : allocated(false), fbo(id) {} + FrameBuffer(GLuint id) : allocated(false), m_target(GL_FRAMEBUFFER), m_frameBufferId(id) {} /** * @brief the destructor does not destroy the textures, however, deleteTextures will do that @@ -43,10 +44,13 @@ public: void deleteTextures(); + void setTarget(GLenum target = GL_FRAMEBUFFER) { m_target = target; } + /** - * @brief bindFBO binds the framebuffer on the specified target + * @brief bindFBO binds the framebuffer + * to unbind the framebuffer (bind the screen), you can use FrameBuffer::screen->bindFBO(); */ - void bindFBO(GLenum target = GL_FRAMEBUFFER) const; + void bindFBO() const; /** * @brief getTexture returns an attached texture, indexed from their adding order. diff --git a/src/light.cpp b/src/light.cpp index ed54da5..aa006b1 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -27,93 +27,117 @@ const glm::mat4 Light::biasMatrix( Light::Light() { - initPointLight(); + initAmbientLight(); } void Light::initAmbientLight(glm::vec3 lightColor) { - type = AMBIENT; - position = glm::vec3(0); - color = lightColor; - shadowCaster = false; - isDir = false; - viewMatrix = glm::mat4(); + 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 } 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)); + 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; } void Light::initPointLight(glm::vec3 pos, glm::vec3 lightColor, float att) { - type = POINT; - position = pos; - cutOffAngle = 360; - color = lightColor; - shadowCaster = false; - isDir = false; - viewMatrix = glm::mat4(); - attenuation = att; + 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; } -void Light::initSpotLight(glm::vec3 pos, glm::vec3 dir, float spotAngle, glm::vec3 lightColor) +void Light::initSpotLight(glm::vec3 pos, glm::vec3 dir, float spotAngle, glm::vec3 lightColor, float att) { - type = SPOT; - position = pos; - direction = dir; - cutOffAngle = spotAngle; - color = lightColor; - shadowCaster = false; - isDir = false; + m_type = SPOT; + m_position = pos; + m_direction = dir; + m_cutOffAngle = spotAngle; + m_color = lightColor; + m_attenuation = att; + m_shadowCaster = false; } -bool Light::isDirectionnal() +void Light::initShadowMap(int resolution, glm::vec3 dim) { - return isDir; -} + m_shadowMapResolution = resolution; + Texture* tex; -void Light::initShadowMap(int resWidth, int resHeight, glm::vec3 dim) -{ - shadowMapWidth = resWidth; - shadowMapHeight = resHeight; - viewMatrix = glm::lookAt(position, position-direction, glm::vec3(0, 1, 0)); - if(type == DIRECTIONNAL) - projectionMatrix = glm::ortho(-dim.x/2, dim.x/2, -dim.y/2, dim.y/2, -dim.z/2, dim.z/2); - else - ; // TODO : glm::projection + switch(m_type) + { + case DIRECTIONNAL: + // 3 orthogonal matrices (cascaded shadowmaps) + // 3 square textures + m_viewMatrix = glm::lookAt(m_position, m_position-m_direction, glm::vec3(0, 1, 0)); + m_projectionMatrix = glm::ortho(-dim.x/2, dim.x/2, -dim.y/2, dim.y/2, -dim.z/2, dim.z/2); + tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resolution, resolution, GL_FLOAT, GL_TEXTURE_2D); + break; + case POINT: + // see http://learnopengl.com/#!Advanced-Lighting/Shadows/Point-Shadows - shadowCaster = true; - shadowMap = new FrameBuffer(); - // Depth buffer - Texture* tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resWidth, resHeight, GL_FLOAT); - 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); - shadowMap->addTexture(tex, GL_DEPTH_ATTACHMENT); - shadowMap->initColorAttachments(); + // 6 projection matrices + // 1 cubemap texture + m_viewMatrix = glm::lookAt(m_position, m_position-glm::vec3(0, 0, 1), glm::vec3(0, 1, 0)); + m_projectionMatrix = glm::perspective(90.f, 1.f, 0.1f, 100.f); + tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resolution, resolution, GL_FLOAT, GL_TEXTURE_CUBE_MAP); + break; + case SPOT: + // 1 projection matrix + // 1 square texture + m_viewMatrix = glm::lookAt(m_position, m_position+m_direction, glm::vec3(0, 1, 0)); + m_projectionMatrix = glm::perspective(m_cutOffAngle, 1.f, 0.1f, 100.f); + tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resolution, resolution, GL_FLOAT, GL_TEXTURE_2D); + break; + case AMBIENT: + return; + } + // shader compilation + // TODO : do not compile shader for every light ShaderSource source; Resource::ResourceMap shaderMap; Resource::getResourcePack_shaders(shaderMap); source.setSource(shaderMap["shaders/shadow.vert.glsl"], ShaderSource::VERTEX); + if(m_type == POINT) + source.setSource(shaderMap["shaders/shadow.geom.glsl"], ShaderSource::GEOMETRY); source.setSource(shaderMap["shaders/shadow.frag.glsl"], ShaderSource::FRAGMENT); - shaders[0] = source.compile(Mesh::MESH_3D, getFlags()); - shaders[1] = source.compile(Mesh::MESH_3D & Mesh::MATERIAL_ALPHA_MASK, getFlags()); + m_shaders[0] = source.compile(Mesh::MESH_3D, getFlags()); + m_shaders[1] = source.compile(Mesh::MESH_3D & Mesh::MATERIAL_ALPHA_MASK, getFlags()); + + // Depth buffer + 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 Light::generateShadowMap(Scene* scene) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glViewport(0, 0, shadowMapWidth, shadowMapHeight); - shadowMap->bindFBO(); + glViewport(0, 0, m_shadowMapResolution, m_shadowMapResolution); + m_shadowMap->bindFBO(); glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); @@ -128,9 +152,9 @@ void Light::generateShadowMap(Scene* scene) // compute matrix attributes glm::mat4 lightMVP = getProjectionMatrix() * (getViewMatrix() * node->modelMatrix); int hasAlpha = (node->mesh->getFlags() & (1 << Mesh::MATERIAL_ALPHA_MASK)) > 0; - shaders[hasAlpha]->bind(); - shaders[hasAlpha]->bindMat4(shaders[hasAlpha]->getLocation("MVP"), lightMVP); - node->mesh->draw(shaders[hasAlpha], false, hasAlpha, false); + m_shaders[hasAlpha]->bind(); + m_shaders[hasAlpha]->bindMat4(m_shaders[hasAlpha]->getLocation("MVP"), lightMVP); + node->mesh->draw(m_shaders[hasAlpha], false, hasAlpha, false); } } //glCullFace(GL_BACK); @@ -138,19 +162,19 @@ void Light::generateShadowMap(Scene* scene) Texture* Light::getShadowMap() { - return shadowMap->getTexture(0); + return m_shadowMap->getTexture(0); } void Light::setPosition(glm::vec3 new_pos) { - position = new_pos; - viewMatrix = glm::lookAt(position, position+direction, glm::vec3(0, 1, 0)); + m_position = new_pos; + m_viewMatrix = glm::lookAt(m_position, m_position+m_direction, glm::vec3(0, 1, 0)); } unsigned int Light::getFlags() { unsigned int flags = 0; - switch(type) + switch(m_type) { case AMBIENT : flags = 1 << AMBIENT_FLAG; @@ -165,7 +189,7 @@ unsigned int Light::getFlags() flags = 1 << SPOT_FLAG; break; } - if(shadowCaster) + if(m_shadowCaster) flags |= 1 << SHADOWMAP_FLAG; return flags; } diff --git a/src/light.h b/src/light.h index 76a4451..507210b 100644 --- a/src/light.h +++ b/src/light.h @@ -36,27 +36,26 @@ public: 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)); + 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); - bool isDirectionnal(); - LightType getType() {return type;} - glm::vec3 getDir() {return direction;} - glm::vec3 getPos() {return position;} - glm::vec3 getColor() {return color;} - float getAttenuation() {return attenuation;} + LightType getType() {return m_type;} + glm::vec3 getDir() {return m_direction;} + glm::vec3 getPos() {return m_position;} + glm::vec3 getColor() {return m_color;} + float getAttenuation() {return m_attenuation;} - bool isShadowCaster() {return shadowCaster;} - void initShadowMap(int resWidth, int resHeight, glm::vec3 dim = glm::vec3(1)); + bool isShadowCaster() {return m_shadowCaster;} + void initShadowMap(int resolution, glm::vec3 dim = glm::vec3(1)); void generateShadowMap(Scene* scene); Texture* getShadowMap(); - void setAttenuation(float a) {attenuation = a;} + void setAttenuation(float a) {m_attenuation = a;} void setPosition(glm::vec3 new_pos); - void setColor(glm::vec3 new_color) {color = new_color;} + void setColor(glm::vec3 new_color) {m_color = new_color;} // camera inheritance - glm::mat4 getProjectionMatrix() {return projectionMatrix;} - glm::mat4 getViewMatrix() {return viewMatrix;} + glm::mat4 getProjectionMatrix() {return m_projectionMatrix;} + glm::mat4 getViewMatrix() {return m_viewMatrix;} // does nothing, just required for inheriting Camera void resize(int width, int height) {} @@ -66,24 +65,21 @@ public: unsigned int getFlags(); private: // standard attributes - LightType type; + LightType m_type; - glm::vec3 position; - glm::vec3 direction; - float cutOffAngle; - float attenuation; - glm::vec3 color; - - bool isDir; + glm::vec3 m_position; + glm::vec3 m_direction; + float m_cutOffAngle; + float m_attenuation; + glm::vec3 m_color; // shadowmap attributes - bool shadowCaster; - int shadowMapWidth; - int shadowMapHeight; - FrameBuffer* shadowMap; - Shader* shaders[2]; - glm::mat4 viewMatrix; - glm::mat4 projectionMatrix; + bool m_shadowCaster; + int m_shadowMapResolution; + FrameBuffer* m_shadowMap; + Shader* m_shaders[2]; + glm::mat4 m_viewMatrix; + glm::mat4 m_projectionMatrix; }; #endif // LIGHT_H diff --git a/src/texture.h b/src/texture.h index 5179375..66cb642 100644 --- a/src/texture.h +++ b/src/texture.h @@ -33,7 +33,7 @@ public: // creates a standard texture from an image Texture(Image* myImage, bool makeMipMaps = true); // creates a cubeMap from 6 images - Texture(Image* myCubemapImages[6], bool makeMipMaps = true); + Texture(Image* myCubemapImages[6], bool makeMipMaps = true); // creates a texture from another Texture(Texture* tex, bool halfDim = false); diff --git a/src/textureblur.cpp b/src/textureblur.cpp index f856bef..12d3be2 100644 --- a/src/textureblur.cpp +++ b/src/textureblur.cpp @@ -66,8 +66,10 @@ void TextureBlur::blur() { FrameBuffer* src = fbos + i; FrameBuffer* dst = fbos + (i + 1); - src->bindFBO(GL_READ_FRAMEBUFFER); - dst->bindFBO(GL_DRAW_FRAMEBUFFER); + src->setTarget(GL_READ_FRAMEBUFFER); + src->bindFBO(); + dst->setTarget(GL_DRAW_FRAMEBUFFER); + dst->bindFBO(); glBlitFramebuffer(0, 0, src->getTexture(0)->getWidth(), src->getTexture(0)->getHeight(),