diff --git a/testbed/opengl-framework/src/FrameBufferObject.h b/testbed/opengl-framework/src/FrameBufferObject.h index a76951c7..6194510a 100644 --- a/testbed/opengl-framework/src/FrameBufferObject.h +++ b/testbed/opengl-framework/src/FrameBufferObject.h @@ -65,7 +65,7 @@ class FrameBufferObject { void attachTexture(uint position, uint textureID); // Bind the FBO - void bind(uint position) const; + void bind() const; // Unbind the FBO void unbind() const; @@ -78,18 +78,14 @@ class FrameBufferObject { }; // Bind the FBO -inline void FrameBufferObject::bind(uint position) const { +inline void FrameBufferObject::bind() const { assert(mFrameBufferID != 0); glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID); - glDrawBuffer(position); - glReadBuffer(position); } // Unbind the FBO inline void FrameBufferObject::unbind() const { assert(mFrameBufferID != 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, 0); } diff --git a/testbed/opengl-framework/src/Light.cpp b/testbed/opengl-framework/src/Light.cpp index cd1831eb..9bffc0c6 100644 --- a/testbed/opengl-framework/src/Light.cpp +++ b/testbed/opengl-framework/src/Light.cpp @@ -60,41 +60,3 @@ void Light::init() { glLightfv(mLightID, GL_DIFFUSE, diffuseColor); glLightfv(mLightID, GL_SPECULAR, specularColor); } - -// Create a shadow map associated with this light -bool Light::createShadowMap(uint width, uint height) { - - // Destroy the current shadow map - destroyShadowMap(); - - // Create the Framebuffer object to render the shadow map - bool isFBOCreated = mFBOShadowMap.create(width, height, false); - if (!isFBOCreated) { - std::cerr << "Error : Cannot create the Shadow Map !" << std::endl; - destroyShadowMap(); - return false; - } - - // Bind the Framebuffer object - mFBOShadowMap.bind(GL_NONE); - - // Create the shadow map depth texture - mShadowMap.create(width, height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE); - - // Attache the shadow map texture to the Framebuffer object - mFBOShadowMap.attachTexture(GL_DEPTH_ATTACHMENT_EXT, mShadowMap.getID()); - - // Unbind the Framebuffer object - mFBOShadowMap.unbind(); - - // TODO : Change the path of the shader here so that it does not depend on the build folder - bool isShaderCreated = mDepthShader.create("../../opengl-framework/src/shaders/depth.vert", - "../../opengl-framework/src/shaders/depth.vert"); - if (!isShaderCreated) { - std::cerr << "Error : Cannot create the Shadow Map !" << std::endl; - destroyShadowMap(); - return false; - } - - return true; -} diff --git a/testbed/opengl-framework/src/Light.h b/testbed/opengl-framework/src/Light.h index 8f8323d9..9ecc63b9 100644 --- a/testbed/opengl-framework/src/Light.h +++ b/testbed/opengl-framework/src/Light.h @@ -31,7 +31,6 @@ #include "maths/Vector3.h" #include "Object3D.h" #include "Texture2D.h" -#include "FrameBufferObject.h" #include "Shader.h" #include @@ -56,15 +55,6 @@ class Light : public Object3D { // True if the light is active bool mIsActive; - // Shadow map associated with this light - Texture2D mShadowMap; - - // Framebuffer object to render the shadow map - FrameBufferObject mFBOShadowMap; - - // Shader to render the depth of the scene into a texture - Shader mDepthShader; - public: // -------------------- Methods -------------------- // @@ -101,18 +91,6 @@ class Light : public Object3D { // Disable the light void disable(); - - // Create a shadow map associated with this light - bool createShadowMap(uint width, uint height); - - // Call this method before rendering the scene for the shadow map computation - void startRenderingShadowMap(); - - // Call this method after having rendered the scene for the shadow map computation - void stopRenderingShadowMap(); - - // Destroy the shadow map associated with this light - void destroyShadowMap(); }; // Return the diffuse color @@ -159,23 +137,6 @@ inline void Light::disable() { glDisable(GL_LIGHT0 + mLightID); } -// Destroy the shadow map associated with this light -inline void Light::destroyShadowMap() { - mShadowMap.destroy(); - mFBOShadowMap.destroy(); - mDepthShader.destroy(); -} - -// Call this method before rendering the scene for the shadow map computation -inline void Light::startRenderingShadowMap() { - assert(mShadowMap.getID()); -} - -// Call this method after having rendered the scene for the shadow map computation -inline void Light::stopRenderingShadowMap() { - assert(mShadowMap.getID()); -} - } #endif diff --git a/testbed/opengl-framework/src/Texture2D.h b/testbed/opengl-framework/src/Texture2D.h index 08087081..f765e1ac 100644 --- a/testbed/opengl-framework/src/Texture2D.h +++ b/testbed/opengl-framework/src/Texture2D.h @@ -103,7 +103,6 @@ class Texture2D { // Bind the texture inline void Texture2D::bind() const { assert(mID != 0); - glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0 + mLayer); glBindTexture(GL_TEXTURE_2D, mID); } @@ -113,7 +112,6 @@ inline void Texture2D::unbind() const { assert(mID != 0); glActiveTexture(GL_TEXTURE0 + mLayer); glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); } // Get the OpenGL texture ID diff --git a/testbed/scenes/cubes/CubesScene.cpp b/testbed/scenes/cubes/CubesScene.cpp index ce1b5bbf..1defa9ce 100644 --- a/testbed/scenes/cubes/CubesScene.cpp +++ b/testbed/scenes/cubes/CubesScene.cpp @@ -167,10 +167,7 @@ void CubesScene::update() { } // Render the scene in a single pass -void CubesScene::renderSinglePass(Shader& shader) { - - // Get the world-space to camera-space matrix - const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse(); +void CubesScene::renderSinglePass(Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) { // Bind the shader shader.bind(); diff --git a/testbed/scenes/cubes/CubesScene.h b/testbed/scenes/cubes/CubesScene.h index 695aa89a..02db7d4c 100644 --- a/testbed/scenes/cubes/CubesScene.h +++ b/testbed/scenes/cubes/CubesScene.h @@ -76,7 +76,8 @@ class CubesScene : public SceneDemo { virtual void update(); /// Render the scene in a single pass - virtual void renderSinglePass(openglframework::Shader& shader); + virtual void renderSinglePass(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); /// Reset the scene virtual void reset(); diff --git a/testbed/shaders/quad.frag b/testbed/shaders/quad.frag new file mode 100644 index 00000000..a6a842ba --- /dev/null +++ b/testbed/shaders/quad.frag @@ -0,0 +1,42 @@ +#version 330 + +/******************************************************************************** +* OpenGL-Framework * +* Copyright (c) 2015 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Uniform variables +uniform sampler2D textureSampler; // Texture + +// In variables +in vec2 texCoords; // Texture coordinates + +// Out variable +out vec4 color; // Output color + +void main() { + + // Get the texture color + float depthColor = texture(textureSampler, texCoords).r; + color = vec4(depthColor, depthColor, depthColor, 1); +} diff --git a/testbed/shaders/quad.vert b/testbed/shaders/quad.vert new file mode 100644 index 00000000..81c6ee9e --- /dev/null +++ b/testbed/shaders/quad.vert @@ -0,0 +1,41 @@ +#version 330 + +/******************************************************************************** +* OpenGL-Framework * +* Copyright (c) 2015 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// In variables +in vec4 vertexPosition; + +// Out variables +out vec2 texCoords; // Texture coordinates + +void main() { + + // Compute the texture coordinates + texCoords = (vertexPosition.xy + vec2(1, 1)) / 2.0; + + // Compute the clip-space vertex coordinates + gl_Position = vec4(vertexPosition.xyz, 1); +} diff --git a/testbed/src/Scene.cpp b/testbed/src/Scene.cpp index 5d832746..ea64fc13 100644 --- a/testbed/src/Scene.cpp +++ b/testbed/src/Scene.cpp @@ -30,7 +30,9 @@ using namespace openglframework; // Constructor -Scene::Scene(const std::string& name) : mName(name), mInterpolationFactor(0.0f) { +Scene::Scene(const std::string& name) + : mName(name), mInterpolationFactor(0.0f), mViewportX(0), mViewportY(0), + mViewportWidth(0), mViewportHeight(0) { } diff --git a/testbed/src/Scene.h b/testbed/src/Scene.h index 53c7c077..d4e05892 100644 --- a/testbed/src/Scene.h +++ b/testbed/src/Scene.h @@ -87,6 +87,9 @@ class Scene { /// Interpolation factor for the bodies in the current frame float mInterpolationFactor; + /// Viewport x,y, width and height values + int mViewportX, mViewportY, mViewportWidth, mViewportHeight; + // -------------------- Methods -------------------- // /// Set the scene position (where the camera needs to look at) @@ -152,6 +155,9 @@ class Scene { /// Set the window dimension void setWindowDimension(int width, int height); + /// Set the viewport to render the scene + void setViewport(int x, int y, int width, int height); + /// Return a reference to the camera const openglframework::Camera& getCamera() const; @@ -189,6 +195,14 @@ inline void Scene::setWindowDimension(int width, int height) { mWindowHeight = height; } +// Set the viewport to render the scene +inline void Scene::setViewport(int x, int y, int width, int height) { + mViewportX = x; + mViewportY = y; + mViewportWidth = width; + mViewportHeight = height; +} + // Get the engine settings inline EngineSettings Scene::getEngineSettings() const { return mEngineSettings; diff --git a/testbed/src/SceneDemo.cpp b/testbed/src/SceneDemo.cpp index 0b5fa0ef..e48f1090 100644 --- a/testbed/src/SceneDemo.cpp +++ b/testbed/src/SceneDemo.cpp @@ -32,10 +32,12 @@ using namespace openglframework; // Constructor SceneDemo::SceneDemo(const std::string& name, float sceneRadius) : Scene(name), mLight0(0), mDepthShader("shaders/depth.vert", "shaders/depth.frag"), - mPhongShader("shaders/phong.vert", "shaders/phong.frag") { + mPhongShader("shaders/phong.vert", "shaders/phong.frag"), + mQuadShader("shaders/quad.vert", "shaders/quad.frag"), + mVBOQuad(GL_ARRAY_BUFFER) { // Move the light0 - mLight0.translateWorld(Vector3(7, 15, 15)); + mLight0.translateWorld(Vector3(20, 20, 20)); // Camera at light0 postion for the shadow map mShadowMapLightCamera.translateWorld(mLight0.getOrigin()); @@ -52,6 +54,8 @@ SceneDemo::SceneDemo(const std::string& name, float sceneRadius) : Scene(name), // Create the Shadow map FBO and texture createShadowMapFBOAndTexture(); + + createQuadVBO(); } // Destructor @@ -65,28 +69,45 @@ SceneDemo::~SceneDemo() { void SceneDemo::render() { glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_CULL_FACE); - // Get the world-space to camera-space matrix - const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse(); - // ---------- Render the scene to generate the shadow map (first pass) ----------- // + // Get the world-space to camera-space matrix + const openglframework::Matrix4 worldToLightCameraMatrix = mShadowMapLightCamera.getTransformMatrix().getInverse(); + + mFBOShadowMap.bind(); + // Bind the shader mDepthShader.bind(); // Set the variables of the shader - mDepthShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix()); + mDepthShader.setMatrix4x4Uniform("projectionMatrix", mShadowMapBiasMatrix * mShadowMapLightCamera.getProjectionMatrix()); + + // Set the viewport to render into the shadow map texture + glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT); + + // Clear previous frame values + glClear( GL_DEPTH_BUFFER_BIT); + + // Disable color rendering, we only want to write to the Z-Buffer + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Render the objects of the scene - renderSinglePass(mDepthShader); + renderSinglePass(mDepthShader, worldToLightCameraMatrix); // Unbind the shader mDepthShader.unbind(); + mFBOShadowMap.unbind(); + + // ---------- Render the scene for final rendering (second pass) ----------- // + // Get the world-space to camera-space matrix + const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse(); + + mPhongShader.bind(); // Set the variables of the shader @@ -99,10 +120,22 @@ void SceneDemo::render() { mPhongShader.setVector3Uniform("light0SpecularColor", Vector3(specCol.r, specCol.g, specCol.b)); mPhongShader.setFloatUniform("shininess", 60.0f); + // Set the viewport to render the scene + glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight); + + //Enabling color write (previously disabled for light POV z-buffer rendering) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + // Clear previous frame values + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Render the objects of the scene - renderSinglePass(mPhongShader); + renderSinglePass(mPhongShader, worldToCameraMatrix); mPhongShader.unbind(); + + + // drawTextureQuad(); } // Create the Shadow map FBO and texture @@ -111,14 +144,77 @@ void SceneDemo::createShadowMapFBOAndTexture() { // Create the texture for the depth values mShadowMapTexture.create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, GL_NEAREST, GL_NEAREST, GL_CLAMP, GL_CLAMP, NULL); + mShadowMapTexture.setLayer(1); // Create the FBO for the shadow map mFBOShadowMap.create(0, 0, false); - mFBOShadowMap.bind(GL_NONE); + mFBOShadowMap.bind(); + + // Tell OpenGL that we won't bind a color texture with the currently binded FBO + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + mFBOShadowMap.attachTexture(GL_DEPTH_ATTACHMENT_EXT, mShadowMapTexture.getID()); + mFBOShadowMap.unbind(); } -// Render the shadow map -void SceneDemo::renderShadowMap() { +// TODO : Delete this +void SceneDemo::createQuadVBO() { + mVAOQuad.create(); + mVAOQuad.bind(); + + static const GLfloat quadVertexData[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + }; + + mVBOQuad.create(); + mVBOQuad.bind(); + mVBOQuad.copyDataIntoVBO(sizeof(quadVertexData), quadVertexData, GL_STATIC_DRAW); + mVBOQuad.unbind(); + + mVAOQuad.unbind(); +} + +// TODO : Delete this +void SceneDemo::drawTextureQuad() { + + glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + // Clear previous frame values + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + mVAOQuad.bind(); + mQuadShader.bind(); + mShadowMapTexture.bind(); + mQuadShader.setIntUniform("textureSampler", mShadowMapTexture.getID()); + mVBOQuad.bind(); + + GLint vertexPositionLoc = mQuadShader.getAttribLocation("vertexPosition"); + glEnableVertexAttribArray(vertexPositionLoc); + + glVertexAttribPointer( + vertexPositionLoc, // attribute 0. No particular reason for 0, but must match the layout in the shader. + 3, // size + GL_FLOAT, // type + GL_FALSE, // normalized? + 0, // stride + (void*)0 // array buffer offset + ); + + // Draw the triangles ! + glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles + + glDisableVertexAttribArray(vertexPositionLoc); + + mVBOQuad.unbind(); + mShadowMapTexture.unbind(); + mQuadShader.unbind(); + mVAOQuad.unbind(); } diff --git a/testbed/src/SceneDemo.h b/testbed/src/SceneDemo.h index 4bcc8d91..87b5f989 100644 --- a/testbed/src/SceneDemo.h +++ b/testbed/src/SceneDemo.h @@ -63,14 +63,25 @@ class SceneDemo : public Scene { /// Phong shader openglframework::Shader mPhongShader; + // TODO : Delete this + openglframework::Shader mQuadShader; + + // TODO : Delete this + openglframework::VertexArrayObject mVAOQuad; + + openglframework::VertexBufferObject mVBOQuad; + // -------------------- Methods -------------------- // // Create the Shadow map FBO and texture void createShadowMapFBOAndTexture(); - // Render the shadow map - void renderShadowMap(); + // TODO : Delete this + void createQuadVBO(); + + // TODO : Delete this + void drawTextureQuad(); public: @@ -86,7 +97,8 @@ class SceneDemo : public Scene { virtual void render(); /// Render the scene in a single pass - virtual void renderSinglePass(openglframework::Shader& shader)=0; + virtual void renderSinglePass(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix)=0; }; #endif diff --git a/testbed/src/TestbedApplication.cpp b/testbed/src/TestbedApplication.cpp index d32b927f..d81887f9 100644 --- a/testbed/src/TestbedApplication.cpp +++ b/testbed/src/TestbedApplication.cpp @@ -250,11 +250,11 @@ void TestbedApplication::render() { mWindowToFramebufferRatio.x = float(bufferWidth) / float(windowWidth); mWindowToFramebufferRatio.y = float(bufferHeight) / float(windowHeight); - // Resize the OpenGL viewport - glViewport(mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH, - 0, - bufferWidth - mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH, - bufferHeight - mWindowToFramebufferRatio.y * HEADER_HEIGHT); + // Set the viewport of the scene + mCurrentScene->setViewport(mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH, + 0, + bufferWidth - mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH, + bufferHeight - mWindowToFramebufferRatio.y * HEADER_HEIGHT); // Render the scene mCurrentScene->render();