From fdfad19476c6bfb34cab5b6a68bfc00f95b46a3d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 16 Dec 2019 11:27:53 +0100 Subject: [PATCH] Coding style fixes --- modules/globebrowsing/shaders/rings_fs.glsl | 2 +- .../globebrowsing/shaders/rings_geom_fs.glsl | 2 +- .../globebrowsing/shaders/rings_geom_vs.glsl | 4 +- modules/globebrowsing/shaders/rings_vs.glsl | 2 +- .../globebrowsing/shaders/smviewer_vs.glsl | 6 +- modules/globebrowsing/src/renderableglobe.cpp | 8 +- modules/globebrowsing/src/renderableglobe.h | 9 +- modules/globebrowsing/src/ringscomponent.cpp | 724 ++++++----- modules/globebrowsing/src/ringscomponent.h | 48 +- modules/globebrowsing/src/shadowcomponent.cpp | 1056 ++++++++--------- modules/globebrowsing/src/shadowcomponent.h | 251 ++-- 11 files changed, 1034 insertions(+), 1078 deletions(-) diff --git a/modules/globebrowsing/shaders/rings_fs.glsl b/modules/globebrowsing/shaders/rings_fs.glsl index c31eef3ff4..fb198a952a 100644 --- a/modules/globebrowsing/shaders/rings_fs.glsl +++ b/modules/globebrowsing/shaders/rings_fs.glsl @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2018 * + * Copyright (c) 2014-2019 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * diff --git a/modules/globebrowsing/shaders/rings_geom_fs.glsl b/modules/globebrowsing/shaders/rings_geom_fs.glsl index 88e43984a9..211d17d596 100644 --- a/modules/globebrowsing/shaders/rings_geom_fs.glsl +++ b/modules/globebrowsing/shaders/rings_geom_fs.glsl @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2018 * + * Copyright (c) 2014-2019 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * diff --git a/modules/globebrowsing/shaders/rings_geom_vs.glsl b/modules/globebrowsing/shaders/rings_geom_vs.glsl index 6eb0ca2390..f803cd15bc 100644 --- a/modules/globebrowsing/shaders/rings_geom_vs.glsl +++ b/modules/globebrowsing/shaders/rings_geom_vs.glsl @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2018 * + * Copyright (c) 2014-2019 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -44,4 +44,4 @@ void main() { vs_screenSpaceDepth = positionClipSpaceZNorm.w; gl_Position = positionClipSpaceZNorm; -} \ No newline at end of file +} diff --git a/modules/globebrowsing/shaders/rings_vs.glsl b/modules/globebrowsing/shaders/rings_vs.glsl index 5fb7d0fbeb..dfe33ed905 100644 --- a/modules/globebrowsing/shaders/rings_vs.glsl +++ b/modules/globebrowsing/shaders/rings_vs.glsl @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2018 * + * Copyright (c) 2014-2019 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * diff --git a/modules/globebrowsing/shaders/smviewer_vs.glsl b/modules/globebrowsing/shaders/smviewer_vs.glsl index a69397368e..958527c339 100644 --- a/modules/globebrowsing/shaders/smviewer_vs.glsl +++ b/modules/globebrowsing/shaders/smviewer_vs.glsl @@ -46,6 +46,6 @@ const vec2 texData[6] = vec2[] ( ); void main() { - texCoord = texData[ gl_VertexID ]; - gl_Position = vec4(posData[ gl_VertexID ], 1.0); -} \ No newline at end of file + texCoord = texData[gl_VertexID]; + gl_Position = vec4(posData[gl_VertexID], 1.0); +} diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 56477c915e..89cc1035a1 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -956,7 +956,9 @@ const glm::dmat4& RenderableGlobe::modelTransform() const { ////////////////////////////////////////////////////////////////////////////////////////// void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, - const ShadowComponent::ShadowMapData& shadowData, const bool renderGeomOnly) { + const ShadowComponent::ShadowMapData& shadowData, + bool renderGeomOnly) +{ if (_shadersNeedRecompilation) { recompileShaders(); } @@ -1256,7 +1258,9 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, } void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& data, - const ShadowComponent::ShadowMapData& shadowData, const bool renderGeomOnly) { + const ShadowComponent::ShadowMapData& shadowData, + bool renderGeomOnly) +{ //PerfMeasure("globally"); const TileIndex& tileIndex = chunk.tileIndex; ghoul::opengl::ProgramObject& program = *_globalRenderer.program; diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index d21445e1f9..8670263749 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -189,8 +189,7 @@ private: float getHeight(const glm::dvec3& position) const; void renderChunks(const RenderData& data, RendererTasks& rendererTask, - const ShadowComponent::ShadowMapData& shadowData = {}, - const bool renderGeomOnly = false + const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false ); /** @@ -202,8 +201,7 @@ private: * tile will lead to jagging. We only render global chunks for lower chunk levels. */ void renderChunkGlobally(const Chunk& chunk, const RenderData& data, - const ShadowComponent::ShadowMapData& shadowData = {}, - const bool renderGeomOnly = false + const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false ); /** @@ -218,8 +216,7 @@ private: * chunks for higher chunk levels. */ void renderChunkLocally(const Chunk& chunk, const RenderData& data, - const ShadowComponent::ShadowMapData& shadowData = {}, - const bool renderGeomOnly = false + const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false ); void debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp, diff --git a/modules/globebrowsing/src/ringscomponent.cpp b/modules/globebrowsing/src/ringscomponent.cpp index c9f20cdb41..3195237b20 100644 --- a/modules/globebrowsing/src/ringscomponent.cpp +++ b/modules/globebrowsing/src/ringscomponent.cpp @@ -1,56 +1,49 @@ /***************************************************************************************** -* * -* OpenSpace * -* * -* Copyright (c) 2014-2018 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ #include + #include #include - #include #include -#include - #include -#include #include - +#include #include #include - +#include #include #include -#include - -#include -#include -#include -#include -#include -#include - #include #include - +#include +#include +#include +#include +#include +#include #include #include #include @@ -120,371 +113,370 @@ namespace { namespace openspace { - documentation::Documentation RingsComponent::Documentation() { - using namespace documentation; - return { - "Rings Component", - "globebrowsing_rings_component", +documentation::Documentation RingsComponent::Documentation() { + using namespace documentation; + return { + "Rings Component", + "globebrowsing_rings_component", + { { - { - TextureInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureInfo.description - }, - { - SizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SizeInfo.description - }, - { - OffsetInfo.identifier, - new DoubleVector2Verifier, - Optional::Yes, - OffsetInfo.description - }, - { - NightFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - NightFactorInfo.description - }, - { - TransparencyInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TransparencyInfo.description - }, - { - ZFightingPercentageInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ZFightingPercentageInfo.description - }, - { - NumberShadowSamplesInfo.identifier, - new IntVerifier, - Optional::Yes, - NumberShadowSamplesInfo.description - } + TextureInfo.identifier, + new StringVerifier, + Optional::Yes, + TextureInfo.description + }, + { + SizeInfo.identifier, + new DoubleVerifier, + Optional::Yes, + SizeInfo.description + }, + { + OffsetInfo.identifier, + new DoubleVector2Verifier, + Optional::Yes, + OffsetInfo.description + }, + { + NightFactorInfo.identifier, + new DoubleVerifier, + Optional::Yes, + NightFactorInfo.description + }, + { + TransparencyInfo.identifier, + new DoubleVerifier, + Optional::Yes, + TransparencyInfo.description + }, + { + ZFightingPercentageInfo.identifier, + new DoubleVerifier, + Optional::Yes, + ZFightingPercentageInfo.description + }, + { + NumberShadowSamplesInfo.identifier, + new IntVerifier, + Optional::Yes, + NumberShadowSamplesInfo.description } - }; - } + } + }; +} - RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary) - : properties::PropertyOwner({ "Rings" }) - , _texturePath(TextureInfo) - , _size(SizeInfo, 1.f, 0.f, 1e25f) - , _offset(OffsetInfo, glm::vec2(0.f, 1.f), glm::vec2(0.f), glm::vec2(1.f)) - , _nightFactor(NightFactorInfo, 0.33f, 0.f, 1.f) - , _transparency(TransparencyInfo, 0.15f, 0.f, 1.f) - , _enabled({ "Enabled", "Enabled", "Enable/Disable Rings" }, true) - , _zFightingPercentage(ZFightingPercentageInfo, 0.995f, 0.000001f, 1.f) - , _nShadowSamples(NumberShadowSamplesInfo, 2, 1, 20) - , _ringsDictionary(dictionary) - { - using ghoul::filesystem::File; +RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Rings" }) + , _texturePath(TextureInfo) + , _size(SizeInfo, 1.f, 0.f, 1e25f) + , _offset(OffsetInfo, glm::vec2(0.f, 1.f), glm::vec2(0.f), glm::vec2(1.f)) + , _nightFactor(NightFactorInfo, 0.33f, 0.f, 1.f) + , _transparency(TransparencyInfo, 0.15f, 0.f, 1.f) + , _enabled({ "Enabled", "Enabled", "Enable/Disable Rings" }, true) + , _zFightingPercentage(ZFightingPercentageInfo, 0.995f, 0.000001f, 1.f) + , _nShadowSamples(NumberShadowSamplesInfo, 2, 1, 20) + , _ringsDictionary(dictionary) +{ + using ghoul::filesystem::File; - if (dictionary.hasKey("Rings")) { - dictionary.getValue("Rings", _ringsDictionary); - } + if (dictionary.hasKey("Rings")) { + // @TODO (abock, 2019-12-16) It would be better to not store the dictionary long + // term and rather extract the values directly here. This would require a bit of + // a rewrite in the RenderableGlobe class to not create the RingsComponent in the + // class-initializer list though + dictionary.getValue("Rings", _ringsDictionary); + } - documentation::testSpecificationAndThrow( - Documentation(), - _ringsDictionary, - "RingsComponent" + documentation::testSpecificationAndThrow( + Documentation(), + _ringsDictionary, + "RingsComponent" + ); +} + +void RingsComponent::initialize() { + using ghoul::filesystem::File; + + addProperty(_enabled); + + _size = static_cast(_ringsDictionary.value(SizeInfo.identifier)); + //setBoundingSphere(_size); + _size.onChange([&]() { _planeIsDirty = true; }); + addProperty(_size); + + _texturePath = absPath( + _ringsDictionary.value(TextureInfo.identifier) + ); + _textureFile = std::make_unique(_texturePath); + + if (_ringsDictionary.hasKeyAndValue(OffsetInfo.identifier)) { + _offset = _ringsDictionary.value(OffsetInfo.identifier); + } + addProperty(_offset); + + _texturePath.onChange([&]() { loadTexture(); }); + addProperty(_texturePath); + + _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); + + if (_ringsDictionary.hasKeyAndValue(NightFactorInfo.identifier)) { + _nightFactor = static_cast( + _ringsDictionary.value(NightFactorInfo.identifier) + ); + } + addProperty(_nightFactor); + + if (_ringsDictionary.hasKeyAndValue(TransparencyInfo.identifier)) { + _transparency = static_cast( + _ringsDictionary.value(TransparencyInfo.identifier) ); } - void RingsComponent::initialize() - { - using ghoul::filesystem::File; - - addProperty(_enabled); - - _size = static_cast(_ringsDictionary.value(SizeInfo.identifier)); - //setBoundingSphere(_size); - _size.onChange([&]() { _planeIsDirty = true; }); - addProperty(_size); - - _texturePath = absPath(_ringsDictionary.value(TextureInfo.identifier)); - _textureFile = std::make_unique(_texturePath); - - if (_ringsDictionary.hasKeyAndValue(OffsetInfo.identifier)) { - _offset = _ringsDictionary.value(OffsetInfo.identifier); - } - addProperty(_offset); - - _texturePath.onChange([&]() { loadTexture(); }); - addProperty(_texturePath); - - _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); - - if (_ringsDictionary.hasKeyAndValue(NightFactorInfo.identifier)) { - _nightFactor = static_cast( - _ringsDictionary.value(NightFactorInfo.identifier) - ); - } - addProperty(_nightFactor); - - if (_ringsDictionary.hasKeyAndValue(TransparencyInfo.identifier)) { - _transparency = static_cast( - _ringsDictionary.value(TransparencyInfo.identifier) - ); - } - - // Shadow Mapping Quality Controls - if (_ringsDictionary.hasKey(ZFightingPercentageInfo.identifier)) { - _zFightingPercentage = _ringsDictionary.value( - ZFightingPercentageInfo.identifier - ); - } - addProperty(_zFightingPercentage); - - if (_ringsDictionary.hasKey(NumberShadowSamplesInfo.identifier)) { - _nShadowSamples = _ringsDictionary.value( - NumberShadowSamplesInfo.identifier - ); - } - addProperty(_nShadowSamples); - - addProperty(_transparency); + // Shadow Mapping Quality Controls + if (_ringsDictionary.hasKey(ZFightingPercentageInfo.identifier)) { + _zFightingPercentage = _ringsDictionary.value( + ZFightingPercentageInfo.identifier + ); } + addProperty(_zFightingPercentage); - bool RingsComponent::isReady() const { - return (_shader || _geometryOnlyShader) && _texture; + if (_ringsDictionary.hasKey(NumberShadowSamplesInfo.identifier)) { + _nShadowSamples = _ringsDictionary.value(NumberShadowSamplesInfo.identifier); } + addProperty(_nShadowSamples); - void RingsComponent::initializeGL() { - _shader = global::renderEngine.buildRenderProgram( - "RingsProgram", - absPath("${MODULE_GLOBEBROWSING}/shaders/rings_vs.glsl"), - absPath("${MODULE_GLOBEBROWSING}/shaders/rings_fs.glsl") + addProperty(_transparency); +} + +bool RingsComponent::isReady() const { + return (_shader || _geometryOnlyShader) && _texture; +} + +void RingsComponent::initializeGL() { + _shader = global::renderEngine.buildRenderProgram( + "RingsProgram", + absPath("${MODULE_GLOBEBROWSING}/shaders/rings_vs.glsl"), + absPath("${MODULE_GLOBEBROWSING}/shaders/rings_fs.glsl") + ); + + _geometryOnlyShader = global::renderEngine.buildRenderProgram( + "RingsGeomOnlyProgram", + absPath("${MODULE_GLOBEBROWSING}/shaders/rings_geom_vs.glsl"), + absPath("${MODULE_GLOBEBROWSING}/shaders/rings_geom_fs.glsl") + ); + + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); + ghoul::opengl::updateUniformLocations( + *_geometryOnlyShader, + _geomUniformCache, + GeomUniformNames + ); + + glGenVertexArrays(1, &_quad); + glGenBuffers(1, &_vertexPositionBuffer); + + createPlane(); + loadTexture(); +} + +void RingsComponent::deinitializeGL() { + glDeleteVertexArrays(1, &_quad); + _quad = 0; + + glDeleteBuffers(1, &_vertexPositionBuffer); + _vertexPositionBuffer = 0; + + _textureFile = nullptr; + _texture = nullptr; + + global::renderEngine.removeRenderProgram(_shader.get()); + _shader = nullptr; + + global::renderEngine.removeRenderProgram(_geometryOnlyShader.get()); + _geometryOnlyShader = nullptr; +} + +void RingsComponent::draw(const RenderData& data, + const RingsComponent::RenderPass renderPass, + const ShadowComponent::ShadowMapData& shadowData) +{ + if (renderPass == GeometryAndShading) { + _shader->activate(); + } + else if (renderPass == GeometryOnly) { + _geometryOnlyShader->activate(); + } + + const glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + const glm::dmat4 modelViewProjectionTransform = + glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() + * modelTransform; + + ghoul::opengl::TextureUnit ringTextureUnit; + if (renderPass == GeometryAndShading) { + _shader->setUniform( + _uniformCache.modelViewProjectionMatrix, + modelViewProjectionTransform + ); + _shader->setUniform(_uniformCache.textureOffset, _offset); + _shader->setUniform(_uniformCache.transparency, _transparency); + _shader->setUniform(_uniformCache.nightFactor, _nightFactor); + _shader->setUniform(_uniformCache.sunPosition, _sunPosition); + _shader->setUniform(_uniformCache.nShadowSamples, _nShadowSamples); + _shader->setUniform(_uniformCache.zFightingPercentage, _zFightingPercentage); + + ringTextureUnit.activate(); + _texture->bind(); + _shader->setUniform(_uniformCache.ringTexture, ringTextureUnit); + + // Adding the model transformation to the final shadow matrix so we have a + // complete transformation from the model coordinates to the clip space of + // the light position. + _shader->setUniform( + _uniformCache.shadowMatrix, + shadowData.shadowMatrix * modelTransform ); - _geometryOnlyShader = global::renderEngine.buildRenderProgram( - "RingsGeomOnlyProgram", - absPath("${MODULE_GLOBEBROWSING}/shaders/rings_geom_vs.glsl"), - absPath("${MODULE_GLOBEBROWSING}/shaders/rings_geom_fs.glsl") - ); + ghoul::opengl::TextureUnit shadowMapUnit; + shadowMapUnit.activate(); + glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture); + + _shader->setUniform(_uniformCache.shadowMapTexture, shadowMapUnit); + } + else if (renderPass == GeometryOnly) { + _geometryOnlyShader->setUniform( + _geomUniformCache.modelViewProjectionMatrix, + modelViewProjectionTransform + ); + _geometryOnlyShader->setUniform(_geomUniformCache.textureOffset, _offset); + + ringTextureUnit.activate(); + _texture->bind(); + _shader->setUniform(_geomUniformCache.ringTexture, ringTextureUnit); + } + + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glBindVertexArray(_quad); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glEnable(GL_CULL_FACE); + + if (renderPass == GeometryAndShading) { + _shader->deactivate(); + } + else if (renderPass == GeometryOnly) { + _geometryOnlyShader->deactivate(); + } +} + +void RingsComponent::update(const UpdateData& data) { + if (_shader->isDirty()) { + _shader->rebuildFromFile(); ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); + } + + if (_geometryOnlyShader->isDirty()) { + _geometryOnlyShader->rebuildFromFile(); ghoul::opengl::updateUniformLocations( *_geometryOnlyShader, _geomUniformCache, GeomUniformNames ); + } - glGenVertexArrays(1, &_quad); - glGenBuffers(1, &_vertexPositionBuffer); - + if (_planeIsDirty) { createPlane(); + _planeIsDirty = false; + } + + if (_textureIsDirty) { loadTexture(); + _textureIsDirty = false; } - void RingsComponent::deinitializeGL() { - glDeleteVertexArrays(1, &_quad); - _quad = 0; + _sunPosition = glm::normalize( + global::renderEngine.scene()->sceneGraphNode("Sun")->worldPosition() - + data.modelTransform.translation + ); +} - glDeleteBuffers(1, &_vertexPositionBuffer); - _vertexPositionBuffer = 0; - - _textureFile = nullptr; - _texture = nullptr; - - global::renderEngine.removeRenderProgram(_shader.get()); - _shader = nullptr; - - global::renderEngine.removeRenderProgram(_geometryOnlyShader.get()); - _geometryOnlyShader = nullptr; - } - - void RingsComponent::draw( - const RenderData& data, - const RingsComponent::RenderPass renderPass, - const ShadowComponent::ShadowMapData& shadowData - ) { - - if (renderPass == GeometryAndShading) { - _shader->activate(); - } - else if (renderPass == GeometryOnly) { - _geometryOnlyShader->activate(); - } - - const glm::dmat4 modelTransform = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * - glm::dmat4(data.modelTransform.rotation) * - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); - - const glm::dmat4 modelViewProjectionTransform = - glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() - * modelTransform; - - ghoul::opengl::TextureUnit ringTextureUnit; - if (renderPass == GeometryAndShading) { - _shader->setUniform( - _uniformCache.modelViewProjectionMatrix, - modelViewProjectionTransform - ); - _shader->setUniform(_uniformCache.textureOffset, _offset); - _shader->setUniform(_uniformCache.transparency, _transparency); - _shader->setUniform(_uniformCache.nightFactor, _nightFactor); - _shader->setUniform(_uniformCache.sunPosition, _sunPosition); - _shader->setUniform(_uniformCache.nShadowSamples, _nShadowSamples); - _shader->setUniform(_uniformCache.zFightingPercentage, _zFightingPercentage); - - ringTextureUnit.activate(); - _texture->bind(); - _shader->setUniform(_uniformCache.ringTexture, ringTextureUnit); - - // Adding the model transformation to the final shadow matrix so we have a - // complete transformation from the model coordinates to the clip space of - // the light position. - _shader->setUniform( - _uniformCache.shadowMatrix, - shadowData.shadowMatrix * modelTransform - ); - - ghoul::opengl::TextureUnit shadowMapUnit; - shadowMapUnit.activate(); - glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture); - - _shader->setUniform(_uniformCache.shadowMapTexture, shadowMapUnit); - - } - else if (renderPass == GeometryOnly) { - _geometryOnlyShader->setUniform( - _geomUniformCache.modelViewProjectionMatrix, - modelViewProjectionTransform - ); - _geometryOnlyShader->setUniform( - _geomUniformCache.textureOffset, - _offset - ); - - ringTextureUnit.activate(); - _texture->bind(); - _shader->setUniform(_geomUniformCache.ringTexture, ringTextureUnit); - } - - glEnable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - glBindVertexArray(_quad); - glDrawArrays(GL_TRIANGLES, 0, 6); - - glEnable(GL_CULL_FACE); - - if (renderPass == GeometryAndShading) { - _shader->deactivate(); - } - else if (renderPass == GeometryOnly) { - _geometryOnlyShader->deactivate(); - } - } - - void RingsComponent::update(const UpdateData& data) { - if (_shader->isDirty()) { - _shader->rebuildFromFile(); - ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); - } - - if (_geometryOnlyShader->isDirty()) { - _geometryOnlyShader->rebuildFromFile(); - ghoul::opengl::updateUniformLocations( - *_geometryOnlyShader, - _geomUniformCache, - GeomUniformNames - ); - } - - if (_planeIsDirty) { - createPlane(); - _planeIsDirty = false; - } - - if (_textureIsDirty) { - loadTexture(); - _textureIsDirty = false; - } - - _sunPosition = glm::normalize( - global::renderEngine.scene()->sceneGraphNode("Sun")->worldPosition() - - data.modelTransform.translation +void RingsComponent::loadTexture() { + if (!_texturePath.value().empty()) { + using namespace ghoul::io; + using namespace ghoul::opengl; + std::unique_ptr texture = TextureReader::ref().loadTexture( + absPath(_texturePath) ); - } - void RingsComponent::loadTexture() { - if (!_texturePath.value().empty()) { - using namespace ghoul::io; - using namespace ghoul::opengl; - std::unique_ptr texture = TextureReader::ref().loadTexture( - absPath(_texturePath) + if (texture) { + LDEBUGC( + "RingsComponent", + fmt::format("Loaded texture from '{}'", absPath(_texturePath)) ); + _texture = std::move(texture); - if (texture) { - LDEBUGC( - "RingsComponent", - fmt::format("Loaded texture from '{}'", absPath(_texturePath)) - ); - _texture = std::move(texture); + _texture->uploadTexture(); + _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - _texture->uploadTexture(); - _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - - _textureFile = std::make_unique(_texturePath); - _textureFile->setCallback( - [&](const ghoul::filesystem::File&) { _textureIsDirty = true; } - ); - } + _textureFile = std::make_unique(_texturePath); + _textureFile->setCallback( + [&](const ghoul::filesystem::File&) { _textureIsDirty = true; } + ); } } +} - void RingsComponent::createPlane() { - const GLfloat size = _size; +void RingsComponent::createPlane() { + const GLfloat size = _size; - struct VertexData { - GLfloat x; - GLfloat y; - GLfloat s; - GLfloat t; - }; + struct VertexData { + GLfloat x; + GLfloat y; + GLfloat s; + GLfloat t; + }; - VertexData data[] = { - { -size, -size, 0.f, 0.f }, - { size, size, 1.f, 1.f }, - { -size, size, 0.f, 1.f }, - { -size, -size, 0.f, 0.f }, - { size, -size, 1.f, 0.f }, - { size, size, 1.f, 1.f }, - }; + VertexData data[] = { + { -size, -size, 0.f, 0.f }, + { size, size, 1.f, 1.f }, + { -size, size, 0.f, 1.f }, + { -size, -size, 0.f, 0.f }, + { size, -size, 1.f, 0.f }, + { size, size, 1.f, 1.f }, + }; - glBindVertexArray(_quad); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(VertexData), - nullptr - ); - glEnableVertexAttribArray(1); - glVertexAttribPointer( - 1, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(VertexData), - reinterpret_cast(offsetof(VertexData, s)) // NOLINT - ); - } + glBindVertexArray(_quad); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(VertexData), + nullptr + ); + glEnableVertexAttribArray(1); + glVertexAttribPointer( + 1, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(VertexData), + reinterpret_cast(offsetof(VertexData, s)) // NOLINT + ); +} + +bool RingsComponent::isEnabled() const { + return _enabled; +} - bool RingsComponent::isEnabled() const { - return _enabled; - } } // namespace openspace diff --git a/modules/globebrowsing/src/ringscomponent.h b/modules/globebrowsing/src/ringscomponent.h index 4804af9ae3..f2e277b3a4 100644 --- a/modules/globebrowsing/src/ringscomponent.h +++ b/modules/globebrowsing/src/ringscomponent.h @@ -1,26 +1,26 @@ /***************************************************************************************** -* * -* OpenSpace * -* * -* Copyright (c) 2014-2018 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___RINGSCOMPONENT___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___RINGSCOMPONENT___H__ @@ -28,14 +28,12 @@ #include #include - +#include #include #include #include #include #include -#include - #include #include #include diff --git a/modules/globebrowsing/src/shadowcomponent.cpp b/modules/globebrowsing/src/shadowcomponent.cpp index da2d166bd6..2d16428728 100644 --- a/modules/globebrowsing/src/shadowcomponent.cpp +++ b/modules/globebrowsing/src/shadowcomponent.cpp @@ -1,64 +1,54 @@ /***************************************************************************************** -* * -* OpenSpace * -* * -* Copyright (c) 2014-2018 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ #include + #include #include - #include #include -#include - #include -#include #include - +#include +#include #include #include -#include - #include #include - #include - +#include #include #include #include - -#include +#include #include #include -#include #include #include - #include #include - #include - #include #include #include @@ -85,8 +75,7 @@ namespace { "The depth map size in pixels. You must entry the width and height values." }; - void checkFrameBufferState(const std::string& codePosition) - { + void checkFrameBufferState(const std::string& codePosition) { if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { LERROR("Framework not built. " + codePosition); GLenum fbErr = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -152,530 +141,510 @@ namespace { namespace openspace { - documentation::Documentation ShadowComponent::Documentation() { - using namespace documentation; - return { - "ShadowsRing Component", - "globebrowsing_shadows_component", +documentation::Documentation ShadowComponent::Documentation() { + using namespace documentation; + return { + "ShadowsRing Component", + "globebrowsing_shadows_component", + { { - { - DistanceFractionInfo.identifier, - new DoubleVerifier, - Optional::Yes, - DistanceFractionInfo.description - }, - { - DepthMapSizeInfo.identifier, - new Vector2ListVerifier, - Optional::Yes, - DepthMapSizeInfo.description - } + DistanceFractionInfo.identifier, + new DoubleVerifier, + Optional::Yes, + DistanceFractionInfo.description + }, + { + DepthMapSizeInfo.identifier, + new Vector2ListVerifier, + Optional::Yes, + DepthMapSizeInfo.description } - }; + } + }; +} + +ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Shadows Component" }) + , _saveDepthTexture(SaveDepthTextureInfo) + , _distanceFraction(DistanceFractionInfo, 20, 1, 10000) + , _enabled({ "Enabled", "Enabled", "Enable/Disable Shadows" }, true) + , _shadowMapDictionary(dictionary) +{ + using ghoul::filesystem::File; + + if (dictionary.hasKey("Shadows")) { + // @TODO (abock, 2019-12-16) It would be better to not store the dictionary long + // term and rather extract the values directly here. This would require a bit of + // a rewrite in the RenderableGlobe class to not create the ShadowComponent in the + // class-initializer list though + dictionary.getValue("Shadows", _shadowMapDictionary); } - ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) - : properties::PropertyOwner({ "Shadows Component" }) - , _saveDepthTexture(SaveDepthTextureInfo) - , _distanceFraction(DistanceFractionInfo, 20, 1, 10000) - , _enabled({ "Enabled", "Enabled", "Enable/Disable Shadows" }, true) - , _shadowMapDictionary(dictionary) - , _shadowDepthTextureHeight(4096) - , _shadowDepthTextureWidth(4096) - , _shadowDepthTexture(-1) - , _positionInLightSpaceTexture(-1) - , _shadowFBO(-1) - , _firstPassSubroutine(-1) - , _secondPassSubroutine(1) - , _defaultFBO(-1) - , _sunPosition(0.0) - , _shadowMatrix(1.0) - , _executeDepthTextureSave(false) - { - using ghoul::filesystem::File; + documentation::testSpecificationAndThrow( + Documentation(), + _shadowMapDictionary, + "ShadowComponent" + ); - if (dictionary.hasKey("Shadows")) { - dictionary.getValue("Shadows", _shadowMapDictionary); - } - - documentation::testSpecificationAndThrow( - Documentation(), - _shadowMapDictionary, - "ShadowComponent" + if (_shadowMapDictionary.hasKey(DistanceFractionInfo.identifier)) { + _distanceFraction = static_cast( + _shadowMapDictionary.value(DistanceFractionInfo.identifier) ); - - if (_shadowMapDictionary.hasKey(DistanceFractionInfo.identifier)) { - _distanceFraction = static_cast( - _shadowMapDictionary.value(DistanceFractionInfo.identifier) - ); - } - _saveDepthTexture.onChange([&]() { - _executeDepthTextureSave = true; - }); - - - if (_shadowMapDictionary.hasKey(DepthMapSizeInfo.identifier)) { - glm::vec2 depthMapSize = - _shadowMapDictionary.value(DepthMapSizeInfo.identifier); - _shadowDepthTextureWidth = depthMapSize.x; - _shadowDepthTextureHeight = depthMapSize.y; - _dynamicDepthTextureRes = false; - } - else { - glm::ivec2 renderingResolution = global::renderEngine.renderingResolution(); - _shadowDepthTextureWidth = renderingResolution.x * 2; - _shadowDepthTextureHeight = renderingResolution.y * 2; - _dynamicDepthTextureRes = true; - } - - _saveDepthTexture.onChange([&]() { - _executeDepthTextureSave = true; - }); - - _viewDepthMap = false; - - addProperty(_enabled); - addProperty(_saveDepthTexture); - addProperty(_distanceFraction); } + _saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; }); - void ShadowComponent::initialize() - { - using ghoul::filesystem::File; + + if (_shadowMapDictionary.hasKey(DepthMapSizeInfo.identifier)) { + glm::vec2 depthMapSize = + _shadowMapDictionary.value(DepthMapSizeInfo.identifier); + _shadowDepthTextureWidth = depthMapSize.x; + _shadowDepthTextureHeight = depthMapSize.y; + _dynamicDepthTextureRes = false; } - - bool ShadowComponent::isReady() const { - return true; - } - - void ShadowComponent::initializeGL() { - createDepthTexture(); - createShadowFBO(); - } - - void ShadowComponent::deinitializeGL() { - glDeleteTextures(1, &_shadowDepthTexture); - glDeleteTextures(1, &_positionInLightSpaceTexture); - glDeleteFramebuffers(1, &_shadowFBO); - checkGLError("ShadowComponent::deinitializeGL() -- Deleted Textures and Framebuffer"); - } - - RenderData ShadowComponent::begin(const RenderData& data) { - // =========================================== - // Builds light's ModelViewProjectionMatrix: - // =========================================== - - glm::dvec3 diffVector = glm::dvec3(_sunPosition) - data.modelTransform.translation; - double originalLightDistance = glm::length(diffVector); - glm::dvec3 lightDirection = glm::normalize(diffVector); - - // Percentage of the original light source distance (to avoid artifacts) - /*double multiplier = originalLightDistance * - (static_cast(_distanceFraction)/1.0E5);*/ - - double multiplier = originalLightDistance * - (static_cast(_distanceFraction) / 1E17); - - // New light source position - /*glm::dvec3 lightPosition = data.modelTransform.translation + - (lightDirection * multiplier);*/ - glm::dvec3 lightPosition = data.modelTransform.translation + - (diffVector * multiplier); - - //// Light Position - //glm::dvec3 lightPosition = glm::dvec3(_sunPosition); - - //=============== Manually Created Camera Matrix =================== - //================================================================== - // camera Z - glm::dvec3 cameraZ = lightDirection; - - // camera X - glm::dvec3 upVector = glm::dvec3(0.0, 1.0, 0.0); - glm::dvec3 cameraX = glm::normalize(glm::cross(upVector, cameraZ)); - - // camera Y - glm::dvec3 cameraY = glm::cross(cameraZ, cameraX); - - // init 4x4 matrix - glm::dmat4 cameraRotationMatrix(1.0); - - double* matrix = glm::value_ptr(cameraRotationMatrix); - matrix[0] = cameraX.x; - matrix[4] = cameraX.y; - matrix[8] = cameraX.z; - matrix[1] = cameraY.x; - matrix[5] = cameraY.y; - matrix[9] = cameraY.z; - matrix[2] = cameraZ.x; - matrix[6] = cameraZ.y; - matrix[10] = cameraZ.z; - - // set translation part - // We aren't setting the position here because it is set in - // the camera->setPosition() - //matrix[12] = -glm::dot(cameraX, lightPosition); - //matrix[13] = -glm::dot(cameraY, lightPosition); - //matrix[14] = -glm::dot(cameraZ, lightPosition); - - - _lightCamera = std::move(std::unique_ptr(new Camera(data.camera))); - _lightCamera->setPositionVec3(lightPosition); - _lightCamera->setRotation(glm::dquat(glm::inverse(cameraRotationMatrix))); - //======================================================================= - //======================================================================= - - - //============= Light Matrix by Camera Matrices Composition ============= - //======================================================================= - glm::dmat4 lightProjectionMatrix = glm::dmat4(_lightCamera->projectionMatrix()); - - // The model transformation missing in the final shadow matrix is add when rendering each - // object (using its transformations provided by the RenderData structure) - _shadowData.shadowMatrix = - _toTextureCoordsMatrix * - lightProjectionMatrix * - _lightCamera->combinedViewMatrix(); - - - // Saves current state - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - glGetIntegerv(GL_VIEWPORT, _mViewport); - _faceCulling = glIsEnabled(GL_CULL_FACE); - glGetIntegerv(GL_CULL_FACE_MODE, &_faceToCull); - _polygonOffSet = glIsEnabled(GL_POLYGON_OFFSET_FILL); - glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &_polygonOffSetFactor); - glGetFloatv(GL_POLYGON_OFFSET_UNITS, &_polygonOffSetUnits); - glGetFloatv(GL_COLOR_CLEAR_VALUE, _colorClearValue); - glGetFloatv(GL_DEPTH_CLEAR_VALUE, &_depthClearValue); - _depthIsEnabled = glIsEnabled(GL_DEPTH_TEST); - glGetIntegerv(GL_DEPTH_FUNC, &_depthFunction); - _blendIsEnabled = glIsEnabled(GL_BLEND); - - - glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO); - GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE }; - glDrawBuffers(3, drawBuffers); - glViewport(0, 0, _shadowDepthTextureWidth, _shadowDepthTextureHeight); - glClearDepth(1.0f); - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - - /*glEnable(GL_CULL_FACE); - checkGLError("begin() -- enabled cull face"); - glCullFace(GL_FRONT); - checkGLError("begin() -- set cullface to front");*/ - /*glEnable(GL_POLYGON_OFFSET_FILL); - checkGLError("begin() -- enabled polygon offset fill"); - glPolygonOffset(2.5f, 10.0f); - checkGLError("begin() -- set values for polygon offset");*/ - - RenderData lightRenderData{ - *_lightCamera, - data.time, - data.doPerformanceMeasurement, - data.renderBinMask, - data.modelTransform - }; - - return lightRenderData; - } - - void ShadowComponent::end() { - if (_executeDepthTextureSave) { - saveDepthBuffer(); - _executeDepthTextureSave = false; - } - - // Restores system state - glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); - GLenum drawBuffers[] = { - GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 - }; - glDrawBuffers(3, drawBuffers); - glViewport( - _mViewport[0], - _mViewport[1], - _mViewport[2], - _mViewport[3] - ); - - if (_faceCulling) { - glEnable(GL_CULL_FACE); - glCullFace(_faceToCull); - } - else { - glDisable(GL_CULL_FACE); - } - - if (_depthIsEnabled) { - glEnable(GL_DEPTH_TEST); - } - else { - glDisable(GL_DEPTH_TEST); - } - - glDepthFunc(_depthFunction); - - if (_polygonOffSet) { - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(_polygonOffSetFactor, _polygonOffSetUnits); - } - else { - glDisable(GL_POLYGON_OFFSET_FILL); - } - - glClearColor( - _colorClearValue[0], - _colorClearValue[1], - _colorClearValue[2], - _colorClearValue[3] - ); - glClearDepth(_depthClearValue); - - if (_blendIsEnabled) { - glEnable(GL_BLEND); - } - - if (_viewDepthMap) { - if (!_renderDMProgram) { - _renderDMProgram = global::renderEngine.buildRenderProgram( - "ShadowMappingDebuggingProgram", - absPath("${MODULE_GLOBEBROWSING}/shaders/smviewer_vs.glsl"), - absPath("${MODULE_GLOBEBROWSING}/shaders/smviewer_fs.glsl") - ); - } - - if (!_quadVAO) { - glGenVertexArrays(1, &_quadVAO); - } - - _renderDMProgram->activate(); - - ghoul::opengl::TextureUnit shadowMapUnit; - shadowMapUnit.activate(); - glBindTexture(GL_TEXTURE_2D, _shadowDepthTexture); - - _renderDMProgram->setUniform("shadowMapTexture", shadowMapUnit); - - glBindVertexArray(_quadVAO); - glDrawArrays(GL_TRIANGLES, 0, 6); - - _renderDMProgram->deactivate(); - } - } - - void ShadowComponent::update(const UpdateData& /*data*/) { - _sunPosition = global::renderEngine.scene()->sceneGraphNode("Sun")->worldPosition(); - + else { glm::ivec2 renderingResolution = global::renderEngine.renderingResolution(); - if (_dynamicDepthTextureRes && ((_shadowDepthTextureWidth != renderingResolution.x) || - (_shadowDepthTextureHeight != renderingResolution.y))) { - _shadowDepthTextureWidth = renderingResolution.x * 2; - _shadowDepthTextureHeight = renderingResolution.y * 2; - updateDepthTexture(); + _shadowDepthTextureWidth = renderingResolution.x * 2; + _shadowDepthTextureHeight = renderingResolution.y * 2; + _dynamicDepthTextureRes = true; + } + + _saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; }); + + _viewDepthMap = false; + + addProperty(_enabled); + addProperty(_saveDepthTexture); + addProperty(_distanceFraction); +} + +void ShadowComponent::initialize() {} + +bool ShadowComponent::isReady() const { + return true; +} + +void ShadowComponent::initializeGL() { + createDepthTexture(); + createShadowFBO(); +} + +void ShadowComponent::deinitializeGL() { + glDeleteTextures(1, &_shadowDepthTexture); + glDeleteTextures(1, &_positionInLightSpaceTexture); + glDeleteFramebuffers(1, &_shadowFBO); + checkGLError("ShadowComponent::deinitializeGL() -- Deleted Textures and Framebuffer"); +} + +RenderData ShadowComponent::begin(const RenderData& data) { + // =========================================== + // Builds light's ModelViewProjectionMatrix: + // =========================================== + + glm::dvec3 diffVector = glm::dvec3(_sunPosition) - data.modelTransform.translation; + double originalLightDistance = glm::length(diffVector); + glm::dvec3 lightDirection = glm::normalize(diffVector); + + // Percentage of the original light source distance (to avoid artifacts) + /*double multiplier = originalLightDistance * + (static_cast(_distanceFraction)/1.0E5);*/ + + double multiplier = originalLightDistance * + (static_cast(_distanceFraction) / 1E17); + + // New light source position + /*glm::dvec3 lightPosition = data.modelTransform.translation + + (lightDirection * multiplier);*/ + glm::dvec3 lightPosition = data.modelTransform.translation + + (diffVector * multiplier); + + //// Light Position + //glm::dvec3 lightPosition = glm::dvec3(_sunPosition); + + //=============== Manually Created Camera Matrix =================== + //================================================================== + // camera Z + glm::dvec3 cameraZ = lightDirection; + + // camera X + glm::dvec3 upVector = glm::dvec3(0.0, 1.0, 0.0); + glm::dvec3 cameraX = glm::normalize(glm::cross(upVector, cameraZ)); + + // camera Y + glm::dvec3 cameraY = glm::cross(cameraZ, cameraX); + + // init 4x4 matrix + glm::dmat4 cameraRotationMatrix(1.0); + + double* matrix = glm::value_ptr(cameraRotationMatrix); + matrix[0] = cameraX.x; + matrix[4] = cameraX.y; + matrix[8] = cameraX.z; + matrix[1] = cameraY.x; + matrix[5] = cameraY.y; + matrix[9] = cameraY.z; + matrix[2] = cameraZ.x; + matrix[6] = cameraZ.y; + matrix[10] = cameraZ.z; + + // set translation part + // We aren't setting the position here because it is set in + // the camera->setPosition() + //matrix[12] = -glm::dot(cameraX, lightPosition); + //matrix[13] = -glm::dot(cameraY, lightPosition); + //matrix[14] = -glm::dot(cameraZ, lightPosition); + + + _lightCamera = std::move(std::unique_ptr(new Camera(data.camera))); + _lightCamera->setPositionVec3(lightPosition); + _lightCamera->setRotation(glm::dquat(glm::inverse(cameraRotationMatrix))); + //======================================================================= + //======================================================================= + + + //============= Light Matrix by Camera Matrices Composition ============= + //======================================================================= + glm::dmat4 lightProjectionMatrix = glm::dmat4(_lightCamera->projectionMatrix()); + + // The model transformation missing in the final shadow matrix is add when rendering each + // object (using its transformations provided by the RenderData structure) + _shadowData.shadowMatrix = + _toTextureCoordsMatrix * lightProjectionMatrix * + _lightCamera->combinedViewMatrix(); + + + // Saves current state + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + glGetIntegerv(GL_VIEWPORT, _mViewport); + _faceCulling = glIsEnabled(GL_CULL_FACE); + glGetIntegerv(GL_CULL_FACE_MODE, &_faceToCull); + _polygonOffSet = glIsEnabled(GL_POLYGON_OFFSET_FILL); + glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &_polygonOffSetFactor); + glGetFloatv(GL_POLYGON_OFFSET_UNITS, &_polygonOffSetUnits); + glGetFloatv(GL_COLOR_CLEAR_VALUE, _colorClearValue); + glGetFloatv(GL_DEPTH_CLEAR_VALUE, &_depthClearValue); + _depthIsEnabled = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &_depthFunction); + _blendIsEnabled = glIsEnabled(GL_BLEND); + + + glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO); + GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE }; + glDrawBuffers(3, drawBuffers); + glViewport(0, 0, _shadowDepthTextureWidth, _shadowDepthTextureHeight); + glClearDepth(1.0f); + glDepthFunc(GL_LEQUAL); + glEnable(GL_DEPTH_TEST); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + /*glEnable(GL_CULL_FACE); + checkGLError("begin() -- enabled cull face"); + glCullFace(GL_FRONT); + checkGLError("begin() -- set cullface to front");*/ + /*glEnable(GL_POLYGON_OFFSET_FILL); + checkGLError("begin() -- enabled polygon offset fill"); + glPolygonOffset(2.5f, 10.0f); + checkGLError("begin() -- set values for polygon offset");*/ + + RenderData lightRenderData{ + *_lightCamera, + data.time, + data.doPerformanceMeasurement, + data.renderBinMask, + data.modelTransform + }; + + return lightRenderData; +} + +void ShadowComponent::end() { + if (_executeDepthTextureSave) { + saveDepthBuffer(); + _executeDepthTextureSave = false; + } + + // Restores system state + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); + GLenum drawBuffers[] = { + GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 + }; + glDrawBuffers(3, drawBuffers); + glViewport(_mViewport[0], _mViewport[1], _mViewport[2], _mViewport[3]); + + if (_faceCulling) { + glEnable(GL_CULL_FACE); + glCullFace(_faceToCull); + } + else { + glDisable(GL_CULL_FACE); + } + + if (_depthIsEnabled) { + glEnable(GL_DEPTH_TEST); + } + else { + glDisable(GL_DEPTH_TEST); + } + + glDepthFunc(_depthFunction); + + if (_polygonOffSet) { + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(_polygonOffSetFactor, _polygonOffSetUnits); + } + else { + glDisable(GL_POLYGON_OFFSET_FILL); + } + + glClearColor( + _colorClearValue[0], + _colorClearValue[1], + _colorClearValue[2], + _colorClearValue[3] + ); + glClearDepth(_depthClearValue); + + if (_blendIsEnabled) { + glEnable(GL_BLEND); + } + + if (_viewDepthMap) { + if (!_renderDMProgram) { + _renderDMProgram = global::renderEngine.buildRenderProgram( + "ShadowMappingDebuggingProgram", + absPath("${MODULE_GLOBEBROWSING}/shaders/smviewer_vs.glsl"), + absPath("${MODULE_GLOBEBROWSING}/shaders/smviewer_fs.glsl") + ); } - } - void ShadowComponent::createDepthTexture() { - glGenTextures(1, &_shadowDepthTexture); - updateDepthTexture(); - - checkGLError("createDepthTexture() -- Depth texture created"); - - _shadowData.shadowDepthTexture = _shadowDepthTexture; - //_shadowData.positionInLightSpaceTexture = _positionInLightSpaceTexture; - } + if (!_quadVAO) { + glGenVertexArrays(1, &_quadVAO); + } - void ShadowComponent::createShadowFBO() { - // Saves current FBO first - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - - glGenFramebuffers(1, &_shadowFBO); - glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO); - glFramebufferTexture( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - _shadowDepthTexture, - 0 - ); + _renderDMProgram->activate(); - /*glFramebufferTexture( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - _positionInLightSpaceTexture, - 0 - );*/ - - checkGLError("createShadowFBO() -- Created Shadow Framebuffer"); - //GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE }; - GLenum drawBuffers[] = { GL_NONE, GL_NONE, GL_NONE }; - glDrawBuffers(3, drawBuffers); - - checkFrameBufferState("createShadowFBO()"); - - // Restores system state - glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); - } - - void ShadowComponent::updateDepthTexture() { + ghoul::opengl::TextureUnit shadowMapUnit; + shadowMapUnit.activate(); glBindTexture(GL_TEXTURE_2D, _shadowDepthTexture); - /* - glTexStorage2D( - GL_TEXTURE_2D, - 1, - GL_DEPTH_COMPONENT32F, - _shadowDepthTextureWidth, - _shadowDepthTextureHeight - ); - */ - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_DEPTH_COMPONENT32F, - _shadowDepthTextureWidth, - _shadowDepthTextureHeight, - 0, - GL_DEPTH_COMPONENT, - GL_FLOAT, - 0 - ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, ShadowBorder); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + _renderDMProgram->setUniform("shadowMapTexture", shadowMapUnit); - /*glGenTextures(1, &_positionInLightSpaceTexture); - glBindTexture(GL_TEXTURE_2D, _positionInLightSpaceTexture); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGB32F, - _shadowDepthTextureWidth, - _shadowDepthTextureHeight, - 0, - GL_RGBA, - GL_FLOAT, - nullptr - ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/ - - glBindTexture(GL_TEXTURE_2D, 0); + glBindVertexArray(_quadVAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + + _renderDMProgram->deactivate(); } +} - void ShadowComponent::saveDepthBuffer() { - int size = _shadowDepthTextureWidth * _shadowDepthTextureHeight; - GLubyte * buffer = new GLubyte[size]; +void ShadowComponent::update(const UpdateData& /*data*/) { + _sunPosition = global::renderEngine.scene()->sceneGraphNode("Sun")->worldPosition(); + + glm::ivec2 renderingResolution = global::renderEngine.renderingResolution(); + if (_dynamicDepthTextureRes && ((_shadowDepthTextureWidth != renderingResolution.x) || + (_shadowDepthTextureHeight != renderingResolution.y))) { + _shadowDepthTextureWidth = renderingResolution.x * 2; + _shadowDepthTextureHeight = renderingResolution.y * 2; + updateDepthTexture(); + } +} - glReadPixels( - 0, - 0, - _shadowDepthTextureWidth, - _shadowDepthTextureHeight, - GL_DEPTH_COMPONENT, - GL_UNSIGNED_BYTE, - buffer - ); +void ShadowComponent::createDepthTexture() { + glGenTextures(1, &_shadowDepthTexture); + updateDepthTexture(); + + checkGLError("createDepthTexture() -- Depth texture created"); + + _shadowData.shadowDepthTexture = _shadowDepthTexture; + //_shadowData.positionInLightSpaceTexture = _positionInLightSpaceTexture; +} - checkGLError("readDepthBuffer To buffer"); - std::fstream ppmFile; +void ShadowComponent::createShadowFBO() { + // Saves current FBO first + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + + glGenFramebuffers(1, &_shadowFBO); + glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + _shadowDepthTexture, + 0 + ); - ppmFile.open("depthBufferShadowMapping.ppm", std::fstream::out); - if (ppmFile.is_open()) { + /*glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + _positionInLightSpaceTexture, + 0 + );*/ + + checkGLError("createShadowFBO() -- Created Shadow Framebuffer"); + //GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE }; + GLenum drawBuffers[] = { GL_NONE, GL_NONE, GL_NONE }; + glDrawBuffers(3, drawBuffers); - ppmFile << "P3" << std::endl; - ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight - << std::endl; - ppmFile << "255" << std::endl; + checkFrameBufferState("createShadowFBO()"); - std::cout << "\n\nSaving depth texture to file depthBufferShadowMapping.ppm\n\n"; - int k = 0; - for (int i = 0; i < _shadowDepthTextureWidth; i++) { - for (int j = 0; j < _shadowDepthTextureHeight; j++, k++) { - unsigned int val = static_cast(buffer[k]); - ppmFile << val << " " << val << " " << val << " "; - } - ppmFile << std::endl; + // Restores system state + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); +} + +void ShadowComponent::updateDepthTexture() { + glBindTexture(GL_TEXTURE_2D, _shadowDepthTexture); + /* + glTexStorage2D( + GL_TEXTURE_2D, + 1, + GL_DEPTH_COMPONENT32F, + _shadowDepthTextureWidth, + _shadowDepthTextureHeight + ); + */ + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT32F, + _shadowDepthTextureWidth, + _shadowDepthTextureHeight, + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + 0 + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, ShadowBorder); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + + /*glGenTextures(1, &_positionInLightSpaceTexture); + glBindTexture(GL_TEXTURE_2D, _positionInLightSpaceTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB32F, + _shadowDepthTextureWidth, + _shadowDepthTextureHeight, + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/ + + glBindTexture(GL_TEXTURE_2D, 0); +} + +void ShadowComponent::saveDepthBuffer() { + int size = _shadowDepthTextureWidth * _shadowDepthTextureHeight; + GLubyte* buffer = new GLubyte[size]; + + glReadPixels( + 0, + 0, + _shadowDepthTextureWidth, + _shadowDepthTextureHeight, + GL_DEPTH_COMPONENT, + GL_UNSIGNED_BYTE, + buffer + ); + + checkGLError("readDepthBuffer To buffer"); + std::fstream ppmFile; + + ppmFile.open("depthBufferShadowMapping.ppm", std::fstream::out); + if (ppmFile.is_open()) { + + ppmFile << "P3" << std::endl; + ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight + << std::endl; + ppmFile << "255" << std::endl; + + std::cout << "\n\nSaving depth texture to file depthBufferShadowMapping.ppm\n\n"; + int k = 0; + for (int i = 0; i < _shadowDepthTextureWidth; i++) { + for (int j = 0; j < _shadowDepthTextureHeight; j++, k++) { + unsigned int val = static_cast(buffer[k]); + ppmFile << val << " " << val << " " << val << " "; } - - ppmFile.close(); - - std::cout << "Texture saved to file depthBufferShadowMapping.ppm\n\n"; + ppmFile << std::endl; } - delete[] buffer; + ppmFile.close(); - GLfloat * bBuffer = new GLfloat[size * 4]; - - glReadBuffer(GL_COLOR_ATTACHMENT3); - glReadPixels( - 0, - 0, - _shadowDepthTextureWidth, - _shadowDepthTextureHeight, - GL_RGBA, - GL_FLOAT, - bBuffer - ); - - checkGLError("readPositionBuffer To buffer"); - ppmFile.clear(); - - ppmFile.open("positionBufferShadowMapping.ppm", std::fstream::out); - if (ppmFile.is_open()) { - - ppmFile << "P3" << std::endl; - ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight - << std::endl; - ppmFile << "255" << std::endl; - - std::cout << "\n\nSaving texture position to positionBufferShadowMapping.ppm\n\n"; - - float biggestValue = 0.f; - - int k = 0; - for (int i = 0; i < _shadowDepthTextureWidth; i++) { - for (int j = 0; j < _shadowDepthTextureHeight; j++) { - biggestValue = bBuffer[k] > biggestValue ? - bBuffer[k] : biggestValue; - k += 4; - } - } - - biggestValue /= 255.f; - - k = 0; - for (int i = 0; i < _shadowDepthTextureWidth; i++) { - for (int j = 0; j < _shadowDepthTextureHeight; j++) { - ppmFile << static_cast(bBuffer[k] / biggestValue) << " " - << static_cast(bBuffer[k + 1] / biggestValue) << " " - << static_cast(bBuffer[k + 2] / biggestValue) << " "; - k += 4; - } - ppmFile << std::endl; - } - - ppmFile.close(); - - std::cout << "Texture saved to file positionBufferShadowMapping.ppm\n\n"; - } - - delete[] bBuffer; + std::cout << "Texture saved to file depthBufferShadowMapping.ppm\n\n"; } - void ShadowComponent::checkGLError(const std::string & where) const { - const GLenum error = glGetError(); - switch (error) { + delete[] buffer; + + GLfloat* bBuffer = new GLfloat[size * 4]; + + glReadBuffer(GL_COLOR_ATTACHMENT3); + glReadPixels( + 0, + 0, + _shadowDepthTextureWidth, + _shadowDepthTextureHeight, + GL_RGBA, + GL_FLOAT, + bBuffer + ); + + checkGLError("readPositionBuffer To buffer"); + ppmFile.clear(); + + ppmFile.open("positionBufferShadowMapping.ppm", std::fstream::out); + if (ppmFile.is_open()) { + + ppmFile << "P3" << std::endl; + ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight + << std::endl; + ppmFile << "255" << std::endl; + + std::cout << "\n\nSaving texture position to positionBufferShadowMapping.ppm\n\n"; + + float biggestValue = 0.f; + + int k = 0; + for (int i = 0; i < _shadowDepthTextureWidth; i++) { + for (int j = 0; j < _shadowDepthTextureHeight; j++) { + biggestValue = bBuffer[k] > biggestValue ? + bBuffer[k] : biggestValue; + k += 4; + } + } + + biggestValue /= 255.f; + + k = 0; + for (int i = 0; i < _shadowDepthTextureWidth; i++) { + for (int j = 0; j < _shadowDepthTextureHeight; j++) { + ppmFile << static_cast(bBuffer[k] / biggestValue) << " " + << static_cast(bBuffer[k + 1] / biggestValue) << " " + << static_cast(bBuffer[k + 2] / biggestValue) << " "; + k += 4; + } + ppmFile << std::endl; + } + + ppmFile.close(); + + std::cout << "Texture saved to file positionBufferShadowMapping.ppm\n\n"; + } + + delete[] bBuffer; +} + +void ShadowComponent::checkGLError(const std::string & where) const { + const GLenum error = glGetError(); + switch (error) { case GL_NO_ERROR: break; case GL_INVALID_ENUM: @@ -717,18 +686,19 @@ namespace openspace { "OpenGL Invalid State", fmt::format("Unknown error code: {0:x}", static_cast(error)) ); - } } +} - bool ShadowComponent::isEnabled() const { - return _enabled; - } +bool ShadowComponent::isEnabled() const { + return _enabled; +} - ShadowComponent::ShadowMapData ShadowComponent::shadowMapData() const { - return _shadowData; - } +ShadowComponent::ShadowMapData ShadowComponent::shadowMapData() const { + return _shadowData; +} + +void ShadowComponent::setViewDepthMap(bool enable) { + _viewDepthMap = enable; +} - void ShadowComponent::setViewDepthMap(bool enable) { - _viewDepthMap = enable; - } } // namespace openspace diff --git a/modules/globebrowsing/src/shadowcomponent.h b/modules/globebrowsing/src/shadowcomponent.h index 602a480f00..d1505a3e31 100644 --- a/modules/globebrowsing/src/shadowcomponent.h +++ b/modules/globebrowsing/src/shadowcomponent.h @@ -1,46 +1,43 @@ /***************************************************************************************** -* * -* OpenSpace * -* * -* Copyright (c) 2014-2018 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___SHADOWCOMPONENT___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___SHADOWCOMPONENT___H__ #include +#include +#include #include #include #include #include #include -#include -#include - #include - #include #include #include - #include #include @@ -58,111 +55,109 @@ namespace openspace { struct RenderData; struct UpdateData; - namespace documentation { struct Documentation; } +namespace documentation { struct Documentation; } - static const GLfloat ShadowBorder[] = { 1.f, 1.f, 1.f, 1.f }; +static const GLfloat ShadowBorder[] = { 1.f, 1.f, 1.f, 1.f }; - class ShadowComponent : public properties::PropertyOwner { - public: - struct ShadowMapData { - glm::dmat4 shadowMatrix; - GLuint shadowDepthTexture; - }; - public: - ShadowComponent(const ghoul::Dictionary& dictionary); - - void initialize(); - void initializeGL(); - void deinitializeGL(); - //bool deinitialize(); - - bool isReady() const; - - RenderData begin(const RenderData& data); - void end(); - void update(const UpdateData& data); - - static documentation::Documentation Documentation(); - - bool isEnabled() const; - - ShadowComponent::ShadowMapData shadowMapData() const; - - void setViewDepthMap(bool enable); - - private: - void createDepthTexture(); - void createShadowFBO(); - void updateDepthTexture(); - - // Debug - void saveDepthBuffer(); - void checkGLError(const std::string & where) const; - - private: - - ShadowMapData _shadowData; - - // Texture coords in [0, 1], while clip coords in [-1, 1] - const glm::dmat4 _toTextureCoordsMatrix = glm::dmat4( - glm::dvec4(0.5, 0.0, 0.0, 0.0), - glm::dvec4(0.0, 0.5, 0.0, 0.0), - glm::dvec4(0.0, 0.0, 1.0, 0.0), - glm::dvec4(0.5, 0.5, 0.0, 1.0) - ); - - // DEBUG - properties::TriggerProperty _saveDepthTexture; - properties::IntProperty _distanceFraction; - properties::BoolProperty _enabled; - - ghoul::Dictionary _shadowMapDictionary; - - int _shadowDepthTextureHeight; - int _shadowDepthTextureWidth; - bool _dynamicDepthTextureRes = true; - - GLuint _shadowDepthTexture; - GLuint _positionInLightSpaceTexture; - GLuint _shadowFBO; - GLuint _firstPassSubroutine; - GLuint _secondPassSubroutine; - GLint _defaultFBO; - GLint _mViewport[4]; - - GLboolean _faceCulling; - GLboolean _polygonOffSet; - GLboolean _depthIsEnabled; - GLboolean _blendIsEnabled = false; - - GLenum _faceToCull; - GLenum _depthFunction; - - GLfloat _polygonOffSetFactor; - GLfloat _polygonOffSetUnits; - GLfloat _colorClearValue[4]; - GLfloat _depthClearValue; - - glm::vec3 _sunPosition; - - glm::dmat4 _shadowMatrix; - - glm::dvec3 _cameraPos; - glm::dvec3 _cameraFocus; - glm::dquat _cameraRotation; - - std::stringstream _serializedCamera; - - std::unique_ptr _lightCamera; - - // DEBUG - bool _executeDepthTextureSave = false; - bool _viewDepthMap = false; - std::unique_ptr _renderDMProgram; - GLuint _quadVAO = 0u; - +class ShadowComponent : public properties::PropertyOwner { +public: + struct ShadowMapData { + glm::dmat4 shadowMatrix; + GLuint shadowDepthTexture; }; + ShadowComponent(const ghoul::Dictionary& dictionary); + + void initialize(); + void initializeGL(); + void deinitializeGL(); + //bool deinitialize(); + + bool isReady() const; + + RenderData begin(const RenderData& data); + void end(); + void update(const UpdateData& data); + + static documentation::Documentation Documentation(); + + bool isEnabled() const; + + ShadowComponent::ShadowMapData shadowMapData() const; + + void setViewDepthMap(bool enable); + +private: + void createDepthTexture(); + void createShadowFBO(); + void updateDepthTexture(); + + // Debug + void saveDepthBuffer(); + void checkGLError(const std::string & where) const; + + ShadowMapData _shadowData; + + // Texture coords in [0, 1], while clip coords in [-1, 1] + const glm::dmat4 _toTextureCoordsMatrix = glm::dmat4( + glm::dvec4(0.5, 0.0, 0.0, 0.0), + glm::dvec4(0.0, 0.5, 0.0, 0.0), + glm::dvec4(0.0, 0.0, 1.0, 0.0), + glm::dvec4(0.5, 0.5, 0.0, 1.0) + ); + + // DEBUG + properties::TriggerProperty _saveDepthTexture; + properties::IntProperty _distanceFraction; + properties::BoolProperty _enabled; + + ghoul::Dictionary _shadowMapDictionary; + + int _shadowDepthTextureHeight = 4096; + int _shadowDepthTextureWidth = 4096; + bool _dynamicDepthTextureRes = true; + + // All of these initializations should probably be 0 since they are GLuints? + GLuint _shadowDepthTexture = -1; + GLuint _positionInLightSpaceTexture = -1; + GLuint _shadowFBO = -1; + GLuint _firstPassSubroutine = -1; + GLuint _secondPassSubroutine = 1; + GLint _defaultFBO = -1; + GLint _mViewport[4]; + + GLboolean _faceCulling; + GLboolean _polygonOffSet; + GLboolean _depthIsEnabled; + GLboolean _blendIsEnabled = false; + + GLenum _faceToCull; + GLenum _depthFunction; + + GLfloat _polygonOffSetFactor; + GLfloat _polygonOffSetUnits; + GLfloat _colorClearValue[4]; + GLfloat _depthClearValue; + + glm::vec3 _sunPosition; + + glm::dmat4 _shadowMatrix = glm::dmat4(1.0); + + glm::dvec3 _cameraPos = glm::dvec3(0.0); + glm::dvec3 _cameraFocus; + glm::dquat _cameraRotation; + + std::stringstream _serializedCamera; + + std::unique_ptr _lightCamera; + + // DEBUG + bool _executeDepthTextureSave = false; + bool _viewDepthMap = false; + std::unique_ptr _renderDMProgram; + GLuint _quadVAO = 0u; +}; + } // namespace openspace #endif // __OPENSPACE_MODULE_GLOBEBROWSING___SHADOWCOMPONENT___H__