Shadow mapping

This commit is contained in:
2014-11-18 19:00:51 +01:00
parent 5f388a1723
commit 701ccce857
9 changed files with 258 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
CXX=g++
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -std=c++11
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -Wno-sign-compare -std=c++11
LDOPTS=-flto
LIBS=-lglbinding -lSDL2 -lSDL2_image -lobj
CXXSRCS=main.cc objectParser.cc

View File

@@ -10,22 +10,26 @@ class Object {
public:
Object(VBOManager& vboManager, std::vector<objVertexAttribs> const& vas, std::vector<uint16_t> const& indices,
Program& prog)
: _vboManager(vboManager), _prog(prog), _indices(indices) {
: _vboManager(vboManager), _prog(prog), _indices(indices), _vaID(0) {
construct(vas);
}
Object(VBOManager& vboManager, std::string const& filename, Program& prog)
: _vboManager(vboManager), _prog(prog) {
: _vboManager(vboManager), _prog(prog), _vaID(0) {
auto tmp = readObject(filename);
_indices = std::get<1>(tmp);
construct(std::get<0>(tmp));
}
~Object() {
glDeleteVertexArrays(1, &_vaID);
}
void draw(glm::mat4 const& modelview) const {
void draw(glm::mat4 const& modelview, Program *override = nullptr) const {
glBindVertexArray(_vaID);
if (override)
override->use();
else
_prog.use();
glUniformMatrix4fv(_prog.getUniformLocation("model_matrix"), 1, GL_FALSE,
glm::value_ptr(modelview));

106
main.cc
View File

@@ -63,8 +63,8 @@ int main(int argc, char *argv[])
window = SDL_CreateWindow("SDL2 Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
1680,
1050,
/*SDL_WINDOW_FULLSCREEN_DESKTOP |*/ SDL_WINDOW_OPENGL);
if (!window) {
@@ -132,9 +132,33 @@ int main(int argc, char *argv[])
Texture2D redTex("textures/red.png");
Texture2D whiteTex("textures/white.png");
const unsigned lights = 2;
const unsigned shadowMapSize = 512;
glm::mat4 shadowProj = glm::perspectiveFov(90.0f, static_cast<float>(shadowMapSize),
static_cast<float>(shadowMapSize), 1.0f, 128.0f);
std::vector<TextureCubeMap> shadowMaps;
for(unsigned i = 0;i < lights;++i) {
shadowMaps.emplace_back(shadowMapSize);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, static_cast<GLint>(GL_LESS));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, static_cast<GLint>(GL_COMPARE_REF_TO_TEXTURE));
}
const glm::vec3 lightPos[lights] = {glm::vec3(2.0, -2.0, 10.0),
glm::vec3(2.0, 2.0, 10.0)};
// const glm::vec3 lightColor[lights] = {glm::vec3(1.0, 0.9, 0.8),
// glm::vec3(0.0, 1.0, 0.0)};
// const float lightIntensity[lights] = {75.0f, 25.0f};
Framebuffer shadowFB;
VertexShader vs{fileToString("shaders/textured.vs")};
FragmentShader fs{fileToString("shaders/textured.fs")};
Program prog(vs, fs);
Program prog{vs, fs};
VertexShader shadowVs{fileToString("shaders/shadow.vs")};
FragmentShader shadowFs{fileToString("shaders/shadow.fs")};
Program shadowProg{shadowVs, shadowFs};
prog.use();
glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE,
@@ -143,6 +167,13 @@ int main(int argc, char *argv[])
glm::value_ptr(view));
glUniform1i(prog.getUniformLocation("texBase"), 0);
const GLint shadowMapTUs[] = {1, 2};
glUniform1iv(prog.getUniformLocation("texShadowMaps"), 2, shadowMapTUs);
shadowProg.use();
glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE,
glm::value_ptr(shadowProj));
Object box(vboManager, "objects/woodbox.obj", prog);
Object pyramid(vboManager, "objects/pyramid.obj", prog);
Object plane(vboManager, "objects/plane.obj", prog);
@@ -165,14 +196,83 @@ int main(int argc, char *argv[])
}
}
// Draw shadow maps
GLint origVP[4];
glGetIntegerv(GL_VIEWPORT, origVP);
glViewport(0, 0, shadowMapSize, shadowMapSize);
shadowProg.use();
shadowFB.bind();
glPolygonOffset(1.1f, 4.0f);
glEnable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_POLYGON_OFFSET_LINE);
glEnable(GL_POLYGON_OFFSET_POINT);
for (unsigned light = 0;light < lights;++light) {
for (unsigned i = 0;i < 6;++i) {
GLenum const face[6] = {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
const glm::vec3 dir[6] = {glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(-1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(0.0f, 0.0f, -1.0f)};
const glm::vec3 up[6] = {glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(-1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f)};
shadowMaps[light].bind();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
face[i], shadowMaps[light].getID(), 0);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glm::mat4 view = glm::lookAt(lightPos[light],
lightPos[light]+dir[i],
up[i]);
glUniformMatrix4fv(prog.getUniformLocation("view_matrix"), 1, GL_FALSE,
glm::value_ptr(view));
glm::mat4 model = glm::translate(glm::vec3(0.5f, 0.5f, -0.5f)) *
glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) *
glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f));
box.draw(model, &shadowProg);
plane.draw(glm::translate(glm::vec3(2.0f, -2.5f, 0.0f))*
glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f)), &shadowProg);
pyramid.draw(glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f)), &shadowProg);
}
}
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, UnusedMask());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(origVP[0], origVP[1], origVP[2], origVP[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glDisable(GL_POLYGON_OFFSET_POINT);
glActiveTexture(GL_TEXTURE2);
shadowMaps[1].bind();
glActiveTexture(GL_TEXTURE1);
shadowMaps[0].bind();
glActiveTexture(GL_TEXTURE0);
glm::mat4 model = glm::translate(glm::vec3(0.5f, 0.5f, -0.5f)) *
glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) *
glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f));
cubeTex.bind();
// Shadow maps must be rendered before real drawing can begin
glClientWaitSync(fence, SyncObjectMask(), 0xffffffffu);
glDeleteSync(fence);
box.draw(model);
whiteTex.bind();
plane.draw(glm::translate(glm::vec3(2.0f, -2.5f, 0.0f))*

View File

@@ -384,7 +384,7 @@ public:
obj_parser.parse(filename);
}
std::vector<objVertexAttribs> buildVA()
std::vector<objVertexAttribs> buildVA() const
{
std::vector<objVertexAttribs> ret;
for (auto const& ent : _vertex_tc_norm) {

5
shaders/shadow.fs Normal file
View File

@@ -0,0 +1,5 @@
#version 330 core
void main(void) {
// Only standard depth calc.
}

12
shaders/shadow.vs Normal file
View File

@@ -0,0 +1,12 @@
#version 330 core
#extension GL_ARB_shading_language_420pack : enable
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
layout(location = 0) in vec3 vertex;
void main(void) {
gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertex, 1.0);
}

View File

@@ -1,16 +1,52 @@
#version 330 core
const uint lights = 2u;
uniform sampler2D texBase;
uniform samplerCubeShadow texShadowMaps[lights];
float VectorToDepth (vec3 Vec)
{
vec3 AbsVec = abs(Vec);
float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));
// Replace f and n with the far and near plane values you used when
// you drew your cube map.
const float f = 128.0;
const float n = 1.0;
float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp;
return (NormZComp + 1.0) * 0.5;
}
in vec2 fragTC;
//in vec3 fragNorm;
//in vec3 light0Vect;
in vec3 light;
in vec3 lightColors[lights];
in vec3 lightVecs[lights];
out vec4 color;
const float bias = 0.00;
void main(void) {
vec4 texColor = texture(texBase, fragTC);
color = texColor*vec4(light, 1.0)+texColor*0.05;
vec4 col = vec4(0.0, 0.0, 0.0, 0.0);
{
float depth = VectorToDepth(lightVecs[0])-bias;
vec3 nlv = normalize(lightVecs[0]);
float depth_compare = texture(texShadowMaps[0], vec4(nlv, depth));
// color = vec4(depth_compare, 0.0, 0.0, 1.0);
col += texColor*vec4(lightColors[0], 1.0)*depth_compare;
}
{
float depth = VectorToDepth(lightVecs[1])-bias;
vec3 nlv = normalize(lightVecs[1]);
float depth_compare = texture(texShadowMaps[1], vec4(nlv, depth));
// color = vec4(depth_compare, 0.0, 0.0, 1.0);
col += texColor*vec4(lightColors[1], 1.0)*depth_compare;
}
color = col+texColor*0.05;
}

View File

@@ -19,7 +19,8 @@ layout(location = 1) in vec2 vertexTC;
layout(location = 2) in vec3 vertexNorm;
out vec2 fragTC;
out vec3 light;
out vec3 lightColors[lights];
out vec3 lightVecs[lights];
void main(void) {
vec4 vertex_Pos = model_matrix * vec4(vertex, 1.0);
@@ -28,12 +29,13 @@ void main(void) {
fragTC = vertexTC;
vec3 vertexNorm_trans = (model_matrix*vec4(vertexNorm, 0.0)).xyz;
light = vec3(0.0, 0.0, 0.0);
for (uint i = 0u;i < lights;++i) {
vec3 lightVec = lightPos[i]-vertex_Pos.xyz;
lightVecs[i] = -lightVec;
vec3 lightNorm = normalize(lightVec);
float lightDist = length(lightVec);
light += lightColor[i]*clamp(dot(vertexNorm_trans, lightNorm), 0.0, 1.0)*
lightColors[i] = lightColor[i]*clamp(dot(vertexNorm_trans, lightNorm), 0.0, 1.0)*
clamp(lightIntensity[i]/(lightDist*lightDist), 0.0, 1.0);
}
}

View File

@@ -22,6 +22,88 @@ static unsigned ilog2(unsigned in)
return ret;
}
class Framebuffer {
public:
Framebuffer() {
glGenFramebuffers(1, &_fbID);
}
~Framebuffer() {
glDeleteFramebuffers(1, &_fbID);
}
void bind() const {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbID);
}
GLuint getID() const {
return _fbID;
}
void attachTexture(GLenum textarget, GLuint texID) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
textarget, texID, 0);
}
private:
GLuint _fbID;
};
class TextureCubeMap {
public:
TextureCubeMap(unsigned size) {
glGenTextures(1, &_texID);
glBindTexture(GL_TEXTURE_CUBE_MAP, _texID);
if(SDL_GL_ExtensionSupported("GL_ARB_texture_storage"))
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_DEPTH_COMPONENT24,
size, size);
else {
std::printf("Warning: extension GL_ARB_texture_storage not supported!\n");
for (unsigned i = 0;i < 6;++i) {
GLenum const face[6] = {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
glTexImage2D(face[i], 0, static_cast<GLint>(GL_DEPTH_COMPONENT16), size, size, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(GL_LINEAR));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(GL_LINEAR));
}
~TextureCubeMap() {
glDeleteTextures(1, &_texID);
}
TextureCubeMap(TextureCubeMap const& copy) = delete;
TextureCubeMap& operator=(TextureCubeMap const& copy) = delete;
TextureCubeMap(TextureCubeMap && move) : _texID(move._texID) {
move._texID = 0;
}
TextureCubeMap& operator=(TextureCubeMap && move) {
glDeleteTextures(1, &_texID);
_texID = move._texID;
move._texID = 0;
return *this;
}
void bind() const {
glBindTexture(GL_TEXTURE_CUBE_MAP, _texID);
}
GLuint getID() const {
return _texID;
}
private:
GLuint _texID;
};
class Texture2D {
public:
Texture2D(unsigned width, unsigned height) {