implemented most of shadowmaps code in the shaders and in forwardmodule.cpp

This commit is contained in:
Anselme 2015-12-13 17:10:44 +01:00
parent a7d4391898
commit c455d31948
11 changed files with 261 additions and 116 deletions

View File

@ -25,7 +25,7 @@ GBuffer::GBuffer(int width, int height) : FrameBuffer()
tex->setFiltering(GL_NEAREST);
addTexture(tex, GL_DEPTH_ATTACHMENT);
initGL();
initColorAttachments();
}
GBuffer::~GBuffer()

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include "shader.h"
#include "light.h"
#include "glassert.h"
#include "texture.h"
#include <glm/ext.hpp>
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<Light*>* 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<Light*>* 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; i<flags.size(); ++i)
for(int i=0; i<geometryFlagList.size(); ++i)
{
// bind shader
Shader* shader = shaders[i*NB_LIGHT_FLAGS + type];
int j;
for(j=0; j<lightFlagList.size(); ++j)
if(lightFlagList[j] == Light::getFlags(light))
break;
Shader* shader = shaders[i*lightFlagList.size() + j];
shader->bind();
// 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<PhongEntity*>* 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));
// loop over material groups
for(int j=0; j<entity->getMesh()->indiceGroups.size(); ++j)
if(light != NULL && light->isShadowCaster())
{
Material* mat = entity->getMesh()->indiceGroups[j].material;
if(mat->getFlags() == flags[i])
{
// bind material attributes
mat->bindAttributes(shader);
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; j<entity->getMesh()->indiceGroups.size(); ++j)
{
Material* mat = entity->getMesh()->indiceGroups[j].material;
if(mat->getFlags() == geometryFlagList[i])
{
// bind material attributes
mat->bindAttributes(shader);
// 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<size; ++i)
// get material flags
const int nb_geometry_flags = 1 << NB_FLAGS;
bool geometryFlags[nb_geometry_flags];
for(int i=0; i<nb_geometry_flags; ++i)
geometryFlags[i] = false;
// get material flags
for(SceneIterator<PhongEntity*>* entityIt = scene->getGeometry();
entityIt->isValid(); entityIt->next())
{
@ -129,16 +147,39 @@ void ForwardModule::compileShaders(Scene* scene)
for(Mesh::Group &g : m->indiceGroups)
geometryFlags[g.material->getFlags()] = true;
}
// shader compilation
for(int i=0; i<size; ++i)
for(int i=0; i<nb_geometry_flags; ++i)
{
if(geometryFlags[i])
geometryFlagList.push_back(i);
}
// get light flags
const int nb_light_flags = 1 << Light::NB_LIGHT_FLAGS;
bool lightFlags[nb_light_flags];
for(int i=0; i<nb_light_flags; ++i)
lightFlags[i] = false;
// ambient light
lightFlags[Light::getFlags(NULL)] = true;
// scene lights
for(SceneIterator<Light*>* lightIt = scene->getLights();
lightIt->isValid(); lightIt->next())
{
Light* l = lightIt->getItem();
lightFlags[Light::getFlags(l)] = true;
}
for(int i=0; i<nb_light_flags; ++i)
{
if(lightFlags[i])
lightFlagList.push_back(i);
}
// shader compilation
for(int i : geometryFlagList)
{
std::vector<const char*> defines;
defines.push_back(lightStr[AMBIENT_LIGHT]);
// set defines
// set geometry defines
if(i & NORMAL_MAP_FLAG)
defines.push_back(flagStr[NORMAL_MAP]);
if(i & AMBIENT_TEXTURE_FLAG)
@ -150,15 +191,18 @@ void ForwardModule::compileShaders(Scene* scene)
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];
int boundary = defines.size();
for(int j : lightFlagList)
{
while(defines.size() > boundary)
defines.pop_back();
// set light defines
for(int k=0; k<Light::NB_LIGHT_FLAGS; ++k)
{
if(j & (1 << k))
defines.push_back(Light::flagStr[k]);
}
// compilation
shaders.push_back(shaderSources->compile(defines.size(), defines.data()));
}
}

View File

@ -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<Shader*> shaders;
std::vector<unsigned int> flags;
std::vector<unsigned int> geometryFlagList;
std::vector<unsigned int> 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

View File

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

View File

@ -20,7 +20,7 @@ public:
FrameBuffer();
~FrameBuffer();
void addTexture(Texture* tex, GLenum attachment);
void initGL();
void initColorAttachments();
void bindFBO() const;
Texture* getTexture(int texId);

View File

@ -9,6 +9,14 @@
#include "glassert.h"
#include <glm/ext.hpp>
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; j<entity->getMesh()->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\

66
light.h
View File

@ -2,20 +2,65 @@
#define LIGHT_H
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <string>
#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

View File

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

View File

@ -1,5 +1,6 @@
#include "shadersource.h"
#include <string>
#include <vector>
#include <sstream>
#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<bool> 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 if(allowed)
else
{
bool ok = true;
for(bool allowed : allowedStack)
{
if(!allowed)
{
ok = false; break;
}
}
if(ok)
compiled.append(line+'\n');
}
}
return compiled;
}