enhanced Texture and FrameBuffer class to prepare incoming features on shadowmaps

This commit is contained in:
Anselme FRANÇOIS 2016-06-12 01:16:19 +02:00
parent cbefe4f86e
commit 1acf555854
8 changed files with 171 additions and 125 deletions

22
shaders/gbuffer.geom.glsl Normal file
View File

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

View File

@ -30,6 +30,6 @@ GBuffer::GBuffer(int width, int height) : FrameBuffer()
GBuffer::~GBuffer() GBuffer::~GBuffer()
{ {
for(Texture* t : textures) for(Texture* t : m_textures)
delete(t); delete(t);
} }

View File

@ -6,16 +6,17 @@
const FrameBuffer* FrameBuffer::screen = new FrameBuffer(0); const FrameBuffer* FrameBuffer::screen = new FrameBuffer(0);
FrameBuffer::FrameBuffer() : FrameBuffer::FrameBuffer() :
allocated(true) allocated(true),
m_target(GL_FRAMEBUFFER)
{ {
glGenFramebuffers(1, &fbo); glGenFramebuffers(1, &m_frameBufferId);
} }
FrameBuffer::~FrameBuffer() FrameBuffer::~FrameBuffer()
{ {
if(allocated) if(allocated)
glDeleteFramebuffers(1, &fbo); glDeleteFramebuffers(1, &m_frameBufferId);
for(Texture* t : textures) for(Texture* t : m_textures)
{ {
t->unbind(); t->unbind();
delete(t); delete(t);
@ -24,48 +25,45 @@ FrameBuffer::~FrameBuffer()
void FrameBuffer::addTexture(Texture* tex, GLenum attachment) void FrameBuffer::addTexture(Texture* tex, GLenum attachment)
{ {
if(fbo != 0) if(m_frameBufferId != 0)
{ {
textures.push_back(tex); m_textures.push_back(tex);
bindFBO(); bindFBO();
if(tex->isCubeMap()) if(tex->isCubeMap())
{ glFramebufferTexture(m_target, attachment, tex->getId(), 0);
// TODO
// http://cg.siomax.ru/index.php/computer-graphics/10-one-pass-rendering-to-cube-map
}
else else
{
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, tex->getTarget(), tex->getId(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, tex->getTarget(), tex->getId(), 0);
if(attachment != GL_DEPTH_ATTACHMENT) // TODO stencil attachment must be tested too if((attachment != GL_DEPTH_ATTACHMENT && attachment != GL_STENCIL_ATTACHMENT) && attachment != GL_DEPTH_STENCIL_ATTACHMENT)
attachments.push_back(attachment); m_attachments.push_back(attachment);
}
} }
} }
void FrameBuffer::initColorAttachments() void FrameBuffer::initColorAttachments()
{ {
if(fbo != 0 && attachments.size() != 0) if(m_frameBufferId != 0 && m_attachments.size() != 0)
{ {
bindFBO(); bindFBO();
glDrawBuffers(attachments.size(), attachments.data()); glDrawBuffers(m_attachments.size(), m_attachments.data());
} }
else else
{
glDrawBuffer(GL_NONE); glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
check(); check();
} }
void FrameBuffer::deleteTextures() void FrameBuffer::deleteTextures()
{ {
for(Texture* t : textures) for(Texture* t : m_textures)
delete(t); delete(t);
textures.clear(); m_textures.clear();
glDrawBuffer(GL_NONE); glDrawBuffer(GL_NONE);
} }
void FrameBuffer::bindFBO(GLenum target) const void FrameBuffer::bindFBO() const
{ {
glBindFramebuffer(target, fbo); glBindFramebuffer(m_target, m_frameBufferId);
} }
bool FrameBuffer::check() bool FrameBuffer::check()
@ -100,8 +98,8 @@ bool FrameBuffer::check()
Texture* FrameBuffer::getTexture(int texId) Texture* FrameBuffer::getTexture(int texId)
{ {
if(fbo != 0) if(m_frameBufferId != 0)
return textures[texId]; return m_textures[texId];
else else
return NULL; return NULL;
} }

View File

@ -15,9 +15,10 @@ protected:
bool check(); bool check();
const bool allocated; const bool allocated;
GLuint fbo; GLenum m_target;
std::vector<Texture*> textures; GLuint m_frameBufferId;
std::vector<GLuint> attachments; std::vector<Texture*> m_textures;
std::vector<GLuint> m_attachments;
public: public:
/** /**
@ -30,7 +31,7 @@ public:
/** /**
* @brief this constructor is only used to get a handle on an existing Framebuffer created by another library * @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 * @brief the destructor does not destroy the textures, however, deleteTextures will do that
@ -43,10 +44,13 @@ public:
void deleteTextures(); 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. * @brief getTexture returns an attached texture, indexed from their adding order.

View File

@ -27,93 +27,117 @@ const glm::mat4 Light::biasMatrix(
Light::Light() Light::Light()
{ {
initPointLight(); initAmbientLight();
} }
void Light::initAmbientLight(glm::vec3 lightColor) void Light::initAmbientLight(glm::vec3 lightColor)
{ {
type = AMBIENT; m_type = AMBIENT;
position = glm::vec3(0); m_position = glm::vec3(0); // not used
color = lightColor; m_direction = glm::vec3(0, 0, 1); // not used
shadowCaster = false; m_cutOffAngle = 0; // not used
isDir = false; m_color = lightColor;
viewMatrix = glm::mat4(); m_attenuation = 0; // not used
m_shadowCaster = false; // not used
} }
void Light::initDirectionnalLight(glm::vec3 dir, glm::vec3 lightColor) void Light::initDirectionnalLight(glm::vec3 dir, glm::vec3 lightColor)
{ {
type = DIRECTIONNAL; m_type = DIRECTIONNAL;
position = glm::vec3(0); m_position = glm::vec3(0); // not used
direction = dir; m_direction = dir;
color = lightColor; m_cutOffAngle = 0; // not used
shadowCaster = false; m_color = lightColor;
isDir = true; m_attenuation = 0; // not used
viewMatrix = glm::lookAt(position, position+direction, glm::vec3(0, 1, 0)); m_shadowCaster = false;
} }
void Light::initPointLight(glm::vec3 pos, glm::vec3 lightColor, float att) void Light::initPointLight(glm::vec3 pos, glm::vec3 lightColor, float att)
{ {
type = POINT; m_type = POINT;
position = pos; m_position = pos;
cutOffAngle = 360; m_direction = glm::vec3(0, 0, 1); // used to orient the shadowmap
color = lightColor; m_cutOffAngle = 0; // not used
shadowCaster = false; m_color = lightColor;
isDir = false; m_attenuation = att;
viewMatrix = glm::mat4(); m_shadowCaster = false;
attenuation = att;
} }
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; m_type = SPOT;
position = pos; m_position = pos;
direction = dir; m_direction = dir;
cutOffAngle = spotAngle; m_cutOffAngle = spotAngle;
color = lightColor; m_color = lightColor;
shadowCaster = false; m_attenuation = att;
isDir = false; 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) switch(m_type)
{ {
shadowMapWidth = resWidth; case DIRECTIONNAL:
shadowMapHeight = resHeight; // 3 orthogonal matrices (cascaded shadowmaps)
viewMatrix = glm::lookAt(position, position-direction, glm::vec3(0, 1, 0)); // 3 square textures
if(type == DIRECTIONNAL) m_viewMatrix = glm::lookAt(m_position, m_position-m_direction, glm::vec3(0, 1, 0));
projectionMatrix = glm::ortho(-dim.x/2, dim.x/2, -dim.y/2, dim.y/2, -dim.z/2, dim.z/2); m_projectionMatrix = glm::ortho(-dim.x/2, dim.x/2, -dim.y/2, dim.y/2, -dim.z/2, dim.z/2);
else tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resolution, resolution, GL_FLOAT, GL_TEXTURE_2D);
; // TODO : glm::projection break;
case POINT:
// see http://learnopengl.com/#!Advanced-Lighting/Shadows/Point-Shadows
shadowCaster = true; // 6 projection matrices
shadowMap = new FrameBuffer(); // 1 cubemap texture
// Depth buffer m_viewMatrix = glm::lookAt(m_position, m_position-glm::vec3(0, 0, 1), glm::vec3(0, 1, 0));
Texture* tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resWidth, resHeight, GL_FLOAT); m_projectionMatrix = glm::perspective(90.f, 1.f, 0.1f, 100.f);
tex->setFiltering(GL_LINEAR); tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, resolution, resolution, GL_FLOAT, GL_TEXTURE_CUBE_MAP);
tex->setWrap(GL_CLAMP_TO_EDGE); break;
tex->setParameter(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); case SPOT:
tex->setParameter(GL_TEXTURE_COMPARE_FUNC, GL_LESS); // 1 projection matrix
shadowMap->addTexture(tex, GL_DEPTH_ATTACHMENT); // 1 square texture
shadowMap->initColorAttachments(); 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; ShaderSource source;
Resource::ResourceMap shaderMap; Resource::ResourceMap shaderMap;
Resource::getResourcePack_shaders(shaderMap); Resource::getResourcePack_shaders(shaderMap);
source.setSource(shaderMap["shaders/shadow.vert.glsl"], ShaderSource::VERTEX); 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); source.setSource(shaderMap["shaders/shadow.frag.glsl"], ShaderSource::FRAGMENT);
shaders[0] = source.compile(Mesh::MESH_3D, getFlags()); m_shaders[0] = source.compile(Mesh::MESH_3D, getFlags());
shaders[1] = source.compile(Mesh::MESH_3D & Mesh::MATERIAL_ALPHA_MASK, 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) void Light::generateShadowMap(Scene* scene)
{ {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glViewport(0, 0, shadowMapWidth, shadowMapHeight); glViewport(0, 0, m_shadowMapResolution, m_shadowMapResolution);
shadowMap->bindFBO(); m_shadowMap->bindFBO();
glClearDepth(1.0); glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -128,9 +152,9 @@ void Light::generateShadowMap(Scene* scene)
// compute matrix attributes // compute matrix attributes
glm::mat4 lightMVP = getProjectionMatrix() * (getViewMatrix() * node->modelMatrix); glm::mat4 lightMVP = getProjectionMatrix() * (getViewMatrix() * node->modelMatrix);
int hasAlpha = (node->mesh->getFlags() & (1 << Mesh::MATERIAL_ALPHA_MASK)) > 0; int hasAlpha = (node->mesh->getFlags() & (1 << Mesh::MATERIAL_ALPHA_MASK)) > 0;
shaders[hasAlpha]->bind(); m_shaders[hasAlpha]->bind();
shaders[hasAlpha]->bindMat4(shaders[hasAlpha]->getLocation("MVP"), lightMVP); m_shaders[hasAlpha]->bindMat4(m_shaders[hasAlpha]->getLocation("MVP"), lightMVP);
node->mesh->draw(shaders[hasAlpha], false, hasAlpha, false); node->mesh->draw(m_shaders[hasAlpha], false, hasAlpha, false);
} }
} }
//glCullFace(GL_BACK); //glCullFace(GL_BACK);
@ -138,19 +162,19 @@ void Light::generateShadowMap(Scene* scene)
Texture* Light::getShadowMap() Texture* Light::getShadowMap()
{ {
return shadowMap->getTexture(0); return m_shadowMap->getTexture(0);
} }
void Light::setPosition(glm::vec3 new_pos) void Light::setPosition(glm::vec3 new_pos)
{ {
position = new_pos; m_position = new_pos;
viewMatrix = glm::lookAt(position, position+direction, glm::vec3(0, 1, 0)); m_viewMatrix = glm::lookAt(m_position, m_position+m_direction, glm::vec3(0, 1, 0));
} }
unsigned int Light::getFlags() unsigned int Light::getFlags()
{ {
unsigned int flags = 0; unsigned int flags = 0;
switch(type) switch(m_type)
{ {
case AMBIENT : case AMBIENT :
flags = 1 << AMBIENT_FLAG; flags = 1 << AMBIENT_FLAG;
@ -165,7 +189,7 @@ unsigned int Light::getFlags()
flags = 1 << SPOT_FLAG; flags = 1 << SPOT_FLAG;
break; break;
} }
if(shadowCaster) if(m_shadowCaster)
flags |= 1 << SHADOWMAP_FLAG; flags |= 1 << SHADOWMAP_FLAG;
return flags; return flags;
} }

View File

@ -36,27 +36,26 @@ public:
void initAmbientLight(glm::vec3 lightColor = glm::vec3(0.1f)); 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 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 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 m_type;}
LightType getType() {return type;} glm::vec3 getDir() {return m_direction;}
glm::vec3 getDir() {return direction;} glm::vec3 getPos() {return m_position;}
glm::vec3 getPos() {return position;} glm::vec3 getColor() {return m_color;}
glm::vec3 getColor() {return color;} float getAttenuation() {return m_attenuation;}
float getAttenuation() {return attenuation;}
bool isShadowCaster() {return shadowCaster;} bool isShadowCaster() {return m_shadowCaster;}
void initShadowMap(int resWidth, int resHeight, glm::vec3 dim = glm::vec3(1)); void initShadowMap(int resolution, glm::vec3 dim = glm::vec3(1));
void generateShadowMap(Scene* scene); void generateShadowMap(Scene* scene);
Texture* getShadowMap(); Texture* getShadowMap();
void setAttenuation(float a) {attenuation = a;} void setAttenuation(float a) {m_attenuation = a;}
void setPosition(glm::vec3 new_pos); 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 // camera inheritance
glm::mat4 getProjectionMatrix() {return projectionMatrix;} glm::mat4 getProjectionMatrix() {return m_projectionMatrix;}
glm::mat4 getViewMatrix() {return viewMatrix;} glm::mat4 getViewMatrix() {return m_viewMatrix;}
// does nothing, just required for inheriting Camera // does nothing, just required for inheriting Camera
void resize(int width, int height) {} void resize(int width, int height) {}
@ -66,24 +65,21 @@ public:
unsigned int getFlags(); unsigned int getFlags();
private: private:
// standard attributes // standard attributes
LightType type; LightType m_type;
glm::vec3 position; glm::vec3 m_position;
glm::vec3 direction; glm::vec3 m_direction;
float cutOffAngle; float m_cutOffAngle;
float attenuation; float m_attenuation;
glm::vec3 color; glm::vec3 m_color;
bool isDir;
// shadowmap attributes // shadowmap attributes
bool shadowCaster; bool m_shadowCaster;
int shadowMapWidth; int m_shadowMapResolution;
int shadowMapHeight; FrameBuffer* m_shadowMap;
FrameBuffer* shadowMap; Shader* m_shaders[2];
Shader* shaders[2]; glm::mat4 m_viewMatrix;
glm::mat4 viewMatrix; glm::mat4 m_projectionMatrix;
glm::mat4 projectionMatrix;
}; };
#endif // LIGHT_H #endif // LIGHT_H

View File

@ -33,7 +33,7 @@ public:
// creates a standard texture from an image // creates a standard texture from an image
Texture(Image* myImage, bool makeMipMaps = true); Texture(Image* myImage, bool makeMipMaps = true);
// creates a cubeMap from 6 images // 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 // creates a texture from another
Texture(Texture* tex, bool halfDim = false); Texture(Texture* tex, bool halfDim = false);

View File

@ -66,8 +66,10 @@ void TextureBlur::blur()
{ {
FrameBuffer* src = fbos + i; FrameBuffer* src = fbos + i;
FrameBuffer* dst = fbos + (i + 1); FrameBuffer* dst = fbos + (i + 1);
src->bindFBO(GL_READ_FRAMEBUFFER); src->setTarget(GL_READ_FRAMEBUFFER);
dst->bindFBO(GL_DRAW_FRAMEBUFFER); src->bindFBO();
dst->setTarget(GL_DRAW_FRAMEBUFFER);
dst->bindFBO();
glBlitFramebuffer(0, 0, glBlitFramebuffer(0, 0,
src->getTexture(0)->getWidth(), src->getTexture(0)->getWidth(),
src->getTexture(0)->getHeight(), src->getTexture(0)->getHeight(),