diff --git a/Shader/depth.fsh b/Shader/depth.fsh new file mode 100644 index 0000000..1e0039f --- /dev/null +++ b/Shader/depth.fsh @@ -0,0 +1,10 @@ +#version 150 + +out vec4 fragmentDepth; + +void main() { + fragmentDepth.r = gl_FragCoord.z; + fragmentDepth.g = gl_FragCoord.z; + fragmentDepth.b = gl_FragCoord.z; + fragmentDepth.a = 1.0; +} diff --git a/Shader/depth.vsh b/Shader/depth.vsh new file mode 100644 index 0000000..e3eba6a --- /dev/null +++ b/Shader/depth.vsh @@ -0,0 +1,12 @@ +#version 150 + +in vec3 aPosition; +in vec3 aNormal; +in vec3 aTexcoord; + +uniform mat4 viewProjectionMatrix; +uniform mat4 modelMatrix; + +void main() { + gl_Position = viewProjectionMatrix * modelMatrix * vec4(aPosition, 1.0); +} diff --git a/Shader/phong.fsh b/Shader/phong.fsh index 436bee1..d9fc0d5 100644 --- a/Shader/phong.fsh +++ b/Shader/phong.fsh @@ -3,10 +3,12 @@ in vec3 vNormal; in vec2 vTexCoord; in vec4 fragPosition; +in vec4 shadowCoord; out vec4 oColor; uniform sampler2D uTexture; +uniform sampler2D shadowMap; uniform vec3 ambientColor; uniform float ambientFactor; uniform float diffuseFactor; @@ -30,6 +32,8 @@ void main() vec3 diffuseColor = vec3(0.0, 0.0, 0.0); vec3 specularColor = vec3(0.0, 0.0, 0.0); + + // direction lighting if(length(directionalLightVector)>0.0f) { vec3 directionalVector = normalize(directionalLightVector); diffuseColor += clamp(dot(normalize(vNormal), directionalVector) @@ -38,6 +42,8 @@ void main() specularColor += clamp(pow((dot((cameraVector+directionalVector),normalize(vNormal))/(length(cameraVector+directionalVector)*length(normalize(vNormal)))),shininess), 0.0, 1.0) *specularFactor*directionalIntensity*directionalColor; } + + // point lights for(int i = 0; i 0.0 && shadowCoord.x < 1.0) { + if (shadowCoord.y > 0.0 && shadowCoord.y < 1.0) { + if (texture(shadowMap, shadowCoord.xy).z < shadowCoord.z-bias) { + visibility = 0.5; + } + } + } + + specularColor *= visibility; + diffuseColor *= visibility; + vec3 finalColor = specularColor + diffuseColor + ambientColor; float distanceCameraCenter = distance(cameraCenter, vec3(fragPosition)); float fogFactor = clamp((1.0 - (fogEnd-distanceCameraCenter)/30.0), 0.0, 1.0); diff --git a/Shader/phong.vsh b/Shader/phong.vsh index 4b71ce9..df35a04 100644 --- a/Shader/phong.vsh +++ b/Shader/phong.vsh @@ -1,8 +1,8 @@ #version 150 uniform mat4 modelMatrix; -uniform mat4 viewMatrix; -uniform mat4 projectionMatrix; +uniform mat4 lightingViewProjectionMatrix; +uniform mat4 shadowMVP; in vec3 aPosition; in vec3 aNormal; @@ -11,11 +11,13 @@ in vec2 aTexCoord; out vec3 vNormal; out vec2 vTexCoord; out vec4 fragPosition; +out vec4 shadowCoord; void main() { fragPosition = modelMatrix * vec4(aPosition, 1.0); vNormal = inverse(transpose(mat3(modelMatrix))) * aNormal; vTexCoord = aTexCoord; - gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(aPosition, 1.0); + shadowCoord = shadowMVP * modelMatrix * vec4(aPosition, 1.0); + gl_Position = lightingViewProjectionMatrix * modelMatrix * vec4(aPosition, 1.0); } diff --git a/application.cc b/application.cc index 8356f16..f6ee1ff 100644 --- a/application.cc +++ b/application.cc @@ -11,7 +11,7 @@ void Application::init() ignoredMouseUpdates = 0; cameraLock = true; // set Skybox size - level.setSkydomeSize((graphics.getFarPlane()/2.0f)-10.0f); + level.setSkydomeSize((graphics.getFarPlane())-31.0f); // define where shaders and textures can be found: ACGL::Base::Settings::the()->setResourcePath("../"); diff --git a/extern/acgl/include/ACGL/OpenGL/Objects/VertexArrayObject.hh b/extern/acgl/include/ACGL/OpenGL/Objects/VertexArrayObject.hh old mode 100755 new mode 100644 diff --git a/graphics.cc b/graphics.cc index aa9bc6a..951f09f 100644 --- a/graphics.cc +++ b/graphics.cc @@ -5,6 +5,8 @@ #include +using namespace ACGL::OpenGL; + Graphics::Graphics(glm::uvec2 windowSize, float nearPlane, float farPlane) { this->windowSize = windowSize; this->nearPlane = nearPlane; @@ -16,17 +18,37 @@ Graphics::Graphics() { void Graphics::init() { // construct VAO to give shader correct Attribute locations - ACGL::OpenGL::SharedArrayBuffer ab = std::make_shared(); + SharedArrayBuffer ab = SharedArrayBuffer(new ArrayBuffer()); ab->defineAttribute("aPosition", GL_FLOAT, 3); ab->defineAttribute("aTexCoord", GL_FLOAT, 2); ab->defineAttribute("aNormal", GL_FLOAT, 3); - ACGL::OpenGL::SharedVertexArrayObject vao = std::make_shared(); + SharedVertexArrayObject vao = SharedVertexArrayObject(new VertexArrayObject()); vao->attachAllAttributes(ab); // look up all shader files starting with 'phong' and build a ShaderProgram from it: - shader = ACGL::OpenGL::ShaderProgramCreator("phong").attributeLocations( + lightingShader = ShaderProgramCreator("phong").attributeLocations( vao->getAttributeLocations()).create(); - shader->use(); + + depthTexture_depth = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH24_STENCIL8)); + depthTexture_depth->setMinFilter(GL_NEAREST); + depthTexture_depth->setMagFilter(GL_NEAREST); + depthTexture_depth->setWrapS(GL_CLAMP_TO_EDGE); + depthTexture_depth->setWrapT(GL_CLAMP_TO_EDGE); + depthTexture_colour = SharedTexture2D( new Texture2D(windowSize)); + depthTexture_colour->setMinFilter(GL_LINEAR); + depthTexture_colour->setMagFilter(GL_LINEAR); + depthTexture_colour->setWrapS(GL_CLAMP_TO_EDGE); + depthTexture_colour->setWrapT(GL_CLAMP_TO_EDGE); + + framebuffer = SharedFrameBufferObject(new FrameBufferObject()); + framebuffer->attachColorTexture("fragmentDepth", depthTexture_colour); + framebuffer->setDepthTexture(depthTexture_depth); + framebuffer->validate(); + + depthShader = ShaderProgramCreator("depth") + .attributeLocations(vao->getAttributeLocations()) + .fragmentDataLocations(framebuffer->getAttachmentLocations()) + .create(); } GLFWwindow* Graphics::getWindow() { @@ -37,6 +59,121 @@ glm::uvec2 Graphics::getWindowSize() { return windowSize; } +void Graphics::render(Level* level) +{ + // render depth texture for sun + framebuffer->bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + depthShader->use(); + glm::vec3 sunVector = (level->getCameraCenter()->getPosition() + level->getDirectionalLight()->getPosition()); + glm::mat4 depthViewProjectionMatrix = glm::ortho(-20, 20, -20, 20, -20, 40) * + glm::lookAt(sunVector, level->getCameraCenter()->getPosition(), glm::vec3(0,1,0)); + depthShader->setUniform("viewProjectionMatrix", depthViewProjectionMatrix); + level->render(depthShader, false); + if (!framebuffer->isFrameBufferObjectComplete()) { + printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); + } + + // final render pass + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + lightingShader->use(); + + //set view and projection matrix + glm::mat4 lightingViewProjectionMatrix = buildFrustum(75.0f, 0.1f, farPlane, (float)windowSize.x/(float)windowSize.y) * buildViewMatrix(level); + lightingShader->setUniform("lightingViewProjectionMatrix", lightingViewProjectionMatrix); + + + // convert texture to homogenouse coordinates + glm::mat4 biasMatrix( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0 + ); + glm::mat4 depthBiasMVP = biasMatrix*depthViewProjectionMatrix; + + lightingShader->setUniform("shadowMVP", depthBiasMVP); + lightingShader->setTexture("shadowMap", depthTexture_colour, 2); + + //set lighting parameters + if (level->getLights().size() > 0) { + lightingShader->setUniform("lightCount", (int) level->getLights().size()); + + // TODO look into doing this less often + // Build light position array + glm::vec3 lightSources[level->getLights().size()]; + for(unsigned int i = 0; igetLights().size(); i++) { + lightSources[i] = level->getLights()[i].getPosition(); + } + glUniform3fv(lightingShader->getUniformLocation("lightSources"), + sizeof(lightSources), (GLfloat*) lightSources); + // Build light colour array + glm::vec3 lightColours[level->getLights().size()]; + for(unsigned int i = 0; igetLights().size(); i++) { + lightColours[i] = level->getLights()[i].getColour(); + } + glUniform3fv(lightingShader->getUniformLocation("lightColors"), + sizeof(lightColours), (GLfloat*) lightColours); + // Build light attenuation array + float lightIntensities[level->getLights().size()]; + for(unsigned int i = 0; igetLights().size(); i++) { + lightIntensities[i] = level->getLights()[i].getIntensity(); + } + glUniform1fv(lightingShader->getUniformLocation("lightIntensities"), + sizeof(lightIntensities), (GLfloat*) lightIntensities); + } + // set directional Light + if(level->getDirectionalLight()) { + lightingShader->setUniform("directionalLightVector", + level->getDirectionalLight()->getPosition()); + lightingShader->setUniform("directionalColor", + level->getDirectionalLight()->getColour()); + lightingShader->setUniform("directionalIntensity", + level->getDirectionalLight()->getIntensity()); + } + + // set fog Parameters + lightingShader->setUniform("fogEnd", (farPlane)-35.0f); + lightingShader->setUniform("fogColor", level->getFogColor()); + lightingShader->setUniform("cameraCenter", level->getCameraCenter()->getPosition()); + + // set Material Parameters + lightingShader->setUniform("ambientColor", level->getAmbientLight()); + lightingShader->setUniform("camera", level->getCameraPosition()); + + // render the level + level->render(lightingShader, true); +} + +void Graphics::resize(glm::uvec2 windowSize) { + this->windowSize = windowSize; + depthTexture_depth->resize(windowSize); + depthTexture_colour->resize(windowSize); +} + +glm::mat4 Graphics::buildFrustum( float phiInDegree, float _near, float _far, float aspectRatio) { + + float phiHalfInRadians = 0.5*phiInDegree * (M_PI/180.0); + float top = _near * tan( phiHalfInRadians ); + float bottom = -top; + float left = bottom * aspectRatio; + float right = -left; + + return glm::frustum(left, right, bottom, top, _near, _far); +} + +glm::mat4 Graphics::buildViewMatrix(Level* level) { + //construct lookAt (cameraPosition = cameraCenter + cameraVector + return glm::lookAt((level->getCameraCenter()->getPosition() + level->getCamera()->getVector()), + level->getCameraCenter()->getPosition(), glm::vec3(0.0f, 1.0f, 0.0f)); +} + +float Graphics::getFarPlane() { + return farPlane; +} + void Graphics::setGLFWHintsForOpenGLVersion( unsigned int _version ) { #ifdef __APPLE__ @@ -90,87 +227,3 @@ bool Graphics::createWindow() ACGL::init(); return true; } - -void Graphics::render(Level* level) -{ - // clear the framebuffer: - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //set view and projection matrix - shader->setUniform("projectionMatrix", buildFrustum(75.0f, 0.1f, 100.0f, (float)windowSize.x/(float)windowSize.y) ); - shader->setUniform("viewMatrix", buildViewMatrix(level)); - - //set lighting parameters - if (level->getLights().size() > 0) { - shader->setUniform("lightCount", (int) level->getLights().size()); - - // TODO look into doing this less often - // Build light position array - glm::vec3 lightSources[level->getLights().size()]; - for(unsigned int i = 0; igetLights().size(); i++) { - lightSources[i] = level->getLights()[i].getPosition(); - } - glUniform3fv(shader->getUniformLocation("lightSources"), - sizeof(lightSources), (GLfloat*) lightSources); - // Build light colour array - glm::vec3 lightColours[level->getLights().size()]; - for(unsigned int i = 0; igetLights().size(); i++) { - lightColours[i] = level->getLights()[i].getColour(); - } - glUniform3fv(shader->getUniformLocation("lightColors"), - sizeof(lightColours), (GLfloat*) lightColours); - // Build light attenuation array - float lightIntensities[level->getLights().size()]; - for(unsigned int i = 0; igetLights().size(); i++) { - lightIntensities[i] = level->getLights()[i].getIntensity(); - } - glUniform1fv(shader->getUniformLocation("lightIntensities"), - sizeof(lightIntensities), (GLfloat*) lightIntensities); - } - // set directional Light - if(level->getDirectionalLight()) { - shader->setUniform("directionalLightVector", - level->getDirectionalLight()->getPosition()); - shader->setUniform("directionalColor", - level->getDirectionalLight()->getColour()); - shader->setUniform("directionalIntensity", - level->getDirectionalLight()->getIntensity()); - } - - // set fog Parameters - shader->setUniform("fogEnd", (farPlane/2.0f)-10.0f); - shader->setUniform("fogColor", level->getFogColor()); - shader->setUniform("cameraCenter", level->getCameraCenter()->getPosition()); - - // set Material Parameters - shader->setUniform("ambientColor", level->getAmbientLight()); - shader->setUniform("camera", level->getCameraPosition()); - - // render the level - level->render(shader); -} - -void Graphics::setWindowSize(glm::uvec2 windowSize) { - this->windowSize = windowSize; -} - -glm::mat4 Graphics::buildFrustum( float phiInDegree, float _near, float _far, float aspectRatio) { - - float phiHalfInRadians = 0.5*phiInDegree * (M_PI/180.0); - float top = _near * tan( phiHalfInRadians ); - float bottom = -top; - float left = bottom * aspectRatio; - float right = -left; - - return glm::frustum(left, right, bottom, top, _near, _far); -} - -glm::mat4 Graphics::buildViewMatrix(Level* level) { - //construct lookAt (cameraPosition = cameraCenter + cameraVector - return glm::lookAt((level->getCameraCenter()->getPosition() + level->getCamera()->getVector()), - level->getCameraCenter()->getPosition(), glm::vec3(0.0f, 1.0f, 0.0f)); -} - -float Graphics::getFarPlane() { - return farPlane; -} diff --git a/graphics.hh b/graphics.hh index 0e0d26a..9cb1c2c 100644 --- a/graphics.hh +++ b/graphics.hh @@ -4,6 +4,8 @@ #include #include +#include + #include "level.hh" class Graphics { @@ -18,15 +20,19 @@ class Graphics { glm::uvec2 getWindowSize(); bool createWindow(); GLFWwindow* getWindow(); - void setWindowSize(glm::uvec2 windowSize); + void resize(glm::uvec2 windowSize); float getFarPlane(); + ACGL::OpenGL::SharedFrameBufferObject framebuffer; private: void setGLFWHintsForOpenGLVersion( unsigned int _version ); glm::uvec2 windowSize; float nearPlane; float farPlane; GLFWwindow* window; - ACGL::OpenGL::SharedShaderProgram shader; + ACGL::OpenGL::SharedShaderProgram lightingShader; + ACGL::OpenGL::SharedShaderProgram depthShader; + ACGL::OpenGL::SharedTexture2D depthTexture_depth; + ACGL::OpenGL::SharedTexture2D depthTexture_colour; }; #endif diff --git a/level.cc b/level.cc index dc2f808..036ea6c 100644 --- a/level.cc +++ b/level.cc @@ -96,9 +96,12 @@ void Level::load() { physics.addTerrain(terrain.getHeightmapWidth(), terrain.getHeightmapHeight(), terrain.getHeightmap()); } -void Level::render(ACGL::OpenGL::SharedShaderProgram shader) { +void Level::render(ACGL::OpenGL::SharedShaderProgram shader, bool lightingPass) { for(unsigned int i = 0; irender(shader); + // do not project shadow of skydome + if(lightingPass || objects.at(i) != skydome) { + objects.at(i)->render(shader, lightingPass); + } } } diff --git a/level.hh b/level.hh index 89d1bfb..83c971f 100644 --- a/level.hh +++ b/level.hh @@ -17,7 +17,7 @@ class Level { ~Level(); void load(); void update(float runTime, glm::vec2 mouseDelta,bool wPressed, bool aPressed,bool sPressed, bool dPressed); - void render(ACGL::OpenGL::SharedShaderProgram shader); + void render(ACGL::OpenGL::SharedShaderProgram shader, bool lightingPass); glm::vec3 getAmbientLight(); Light* getDirectionalLight(); std::vector getLights(); diff --git a/main.cc b/main.cc index 8ac7a9b..b21edfa 100644 --- a/main.cc +++ b/main.cc @@ -3,10 +3,10 @@ #include #include -void resizeCallback(GLFWwindow* window, int newWidth, int newHeight) +static void resizeCallback(GLFWwindow* window, int newWidth, int newHeight) { // store the new window size and adjust the viewport: - app.getGraphics()->setWindowSize(glm::uvec2( newWidth, newHeight)); + app.getGraphics()->resize(glm::uvec2( newWidth, newHeight)); glViewport( 0, 0, newWidth, newHeight); } diff --git a/object.cc b/object.cc index 298d242..6e4fe82 100644 --- a/object.cc +++ b/object.cc @@ -12,13 +12,15 @@ Object::Object() { Object::~Object() { } -void Object::render(ACGL::OpenGL::SharedShaderProgram shader) { +void Object::render(ACGL::OpenGL::SharedShaderProgram shader, bool lightingPass) { + if (lightingPass) { // set lightning parameters for this object - shader->setUniform("ambientFactor", material.getAmbientFactor()); - shader->setUniform("diffuseFactor", material.getDiffuseFactor()); - shader->setUniform("specularFactor", material.getSpecularFactor()); - shader->setUniform("shininess", material.getShininess()); - shader->setTexture("uTexture", material.getReference(), 0); + shader->setUniform("ambientFactor", material.getAmbientFactor()); + shader->setUniform("diffuseFactor", material.getDiffuseFactor()); + shader->setUniform("specularFactor", material.getSpecularFactor()); + shader->setUniform("shininess", material.getShininess()); + shader->setTexture("uTexture", material.getReference(), 0); + } // set model matrix glm::mat4 modelMatrix = glm::translate(getPosition()) * getRotation() * glm::scale(glm::vec3(model.getScale())); shader->setUniform( "modelMatrix", modelMatrix); diff --git a/object.hh b/object.hh index d5a4c2f..526b90c 100644 --- a/object.hh +++ b/object.hh @@ -15,7 +15,7 @@ class Object : public Entity { glm::vec3 position, glm::vec3 rotation); Object(); ~Object(); - void render(ACGL::OpenGL::SharedShaderProgram shader); + void render(ACGL::OpenGL::SharedShaderProgram shader, bool lightingPass); private: Model model; Material material;