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()
{
for(Texture* t : textures)
for(Texture* t : m_textures)
delete(t);
}

View File

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

View File

@ -15,9 +15,10 @@ protected:
bool check();
const bool allocated;
GLuint fbo;
std::vector<Texture*> textures;
std::vector<GLuint> attachments;
GLenum m_target;
GLuint m_frameBufferId;
std::vector<Texture*> m_textures;
std::vector<GLuint> 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.

View File

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

View File

@ -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

View File

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

View File

@ -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(),