mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-28 16:09:46 -06:00
Merge pull request #1027 from OpenSpace/feature/RingShadows
Feature/ring shadows
This commit is contained in:
@@ -34,7 +34,16 @@ local Saturn = {
|
||||
Enabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Rings = {
|
||||
Texture = textures .. "/saturn_rings.png",
|
||||
Size = 140445000,
|
||||
Offset = { 74500 / 140445.100671159, 1.0 }, -- min / max extend
|
||||
},
|
||||
Shadows = {
|
||||
Enabled = true,
|
||||
DistanceFraction = 40.0
|
||||
}
|
||||
},
|
||||
Tag = { "planet_solarSystem", "planet_giants" },
|
||||
GUI = {
|
||||
@@ -42,21 +51,6 @@ local Saturn = {
|
||||
}
|
||||
}
|
||||
|
||||
local SaturnRings = {
|
||||
Identifier = "SaturnRings",
|
||||
Parent = Saturn.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableRings",
|
||||
Texture = textures .. "/saturn_rings.png",
|
||||
Size = 140445000,
|
||||
Offset = { 74500 / 140445.100671159, 1.0 } -- min / max extend
|
||||
},
|
||||
GUI = {
|
||||
Name = "Saturn Rings",
|
||||
Path = "/Solar System/Planets/Saturn"
|
||||
}
|
||||
}
|
||||
|
||||
local SaturnLabel = {
|
||||
Identifier = "SaturnLabel",
|
||||
Parent = Saturn.Identifier,
|
||||
@@ -78,5 +72,4 @@ local SaturnLabel = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { Saturn, SaturnRings, SaturnLabel })
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { Saturn, SaturnLabel })
|
||||
|
||||
@@ -51,6 +51,8 @@ set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rawtile.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rawtiledatareader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/renderableglobe.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ringscomponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/shadowcomponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/skirtedgrid.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tileindex.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tileloadjob.h
|
||||
@@ -80,6 +82,8 @@ set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rawtile.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rawtiledatareader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/renderableglobe.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ringscomponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/shadowcomponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/skirtedgrid.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tileindex.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tileloadjob.cpp
|
||||
@@ -94,6 +98,10 @@ set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/globalrenderer_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/localrenderer_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/renderer_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_geom_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_geom_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/texturetilemapping.hglsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/tile.hglsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/tileheight.hglsl
|
||||
|
||||
@@ -48,6 +48,14 @@ out vec3 positionCameraSpace;
|
||||
uniform dmat4 modelTransform;
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING_ENABLED
|
||||
// ShadowMatrix is the matrix defined by:
|
||||
// textureCoordsMatrix * projectionMatrix * combinedViewMatrix * modelMatrix
|
||||
// where textureCoordsMatrix is just a scale and bias computation: [-1,1] to [0,1]
|
||||
uniform dmat4 shadowMatrix;
|
||||
out vec4 shadowCoords;
|
||||
#endif
|
||||
|
||||
uniform mat4 modelViewProjectionTransform;
|
||||
uniform mat4 modelViewTransform;
|
||||
uniform vec3 radiiSquared;
|
||||
@@ -130,4 +138,8 @@ void main() {
|
||||
#if USE_ECLIPSE_SHADOWS
|
||||
positionWorldSpace = vec3(modelTransform * dvec4(pair.position, 1.0));
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING_ENABLED
|
||||
shadowCoords = vec4(shadowMatrix * dvec4(pair.position, 1.0));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -48,6 +48,14 @@ out vec3 positionWorldSpace;
|
||||
uniform dmat4 inverseViewTransform;
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING_ENABLED
|
||||
// ShadowMatrix is the matrix defined by:
|
||||
// textureCoordsMatrix * projectionMatrix * combinedViewMatrix * modelMatrix
|
||||
// where textureCoordsMatrix is just a scale and bias computation: [-1,1] to [0,1]
|
||||
uniform dmat4 shadowMatrix;
|
||||
out vec4 shadowCoords;
|
||||
#endif
|
||||
|
||||
uniform mat4 projectionTransform;
|
||||
// Input points in camera space
|
||||
uniform vec3 p00;
|
||||
@@ -113,4 +121,8 @@ void main() {
|
||||
#if USE_ECLIPSE_SHADOWS
|
||||
positionWorldSpace = vec3(inverseViewTransform * dvec4(p, 1.0));
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING_ENABLED
|
||||
shadowCoords = vec4(shadowMatrix * dvec4(p, 1.0));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -59,6 +59,13 @@ uniform vec3 lightDirectionCameraSpace;
|
||||
uniform float orenNayarRoughness;
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING_ENABLED
|
||||
in vec4 shadowCoords;
|
||||
uniform sampler2DShadow shadowMapTexture;
|
||||
uniform int nShadowSamples;
|
||||
uniform float zFightingPercentage;
|
||||
#endif
|
||||
|
||||
#if USE_ECLIPSE_SHADOWS
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -258,5 +265,30 @@ Fragment getFragment() {
|
||||
}
|
||||
#endif // SHOW_CHUNK_EDGES
|
||||
|
||||
#if SHADOW_MAPPING_ENABLED
|
||||
float shadow = 1.0;
|
||||
if (shadowCoords.w > 1) {
|
||||
vec4 normalizedShadowCoords = shadowCoords;
|
||||
normalizedShadowCoords.z = normalizeFloat(zFightingPercentage * normalizedShadowCoords.w);
|
||||
normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w;
|
||||
normalizedShadowCoords.w = 1.0;
|
||||
|
||||
float sum = 0;
|
||||
for (int i = 0; i < nShadowSamples; ++i) {
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, -nShadowSamples + i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, 0));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, nShadowSamples - i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , -nShadowSamples + i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , nShadowSamples - i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, -nShadowSamples + i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, 0));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, nShadowSamples - i));
|
||||
}
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(0, 0));
|
||||
shadow = sum / (8.0 * nShadowSamples + 1.f);
|
||||
}
|
||||
frag.color.xyz *= shadow < 0.99 ? clamp(shadow + 0.3, 0.0, 1.0) : shadow;
|
||||
#endif
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
126
modules/globebrowsing/shaders/rings_fs.glsl
Normal file
126
modules/globebrowsing/shaders/rings_fs.glsl
Normal file
@@ -0,0 +1,126 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 "PowerScaling/powerScaling_fs.hglsl"
|
||||
#include "fragment.glsl"
|
||||
|
||||
in vec2 vs_st;
|
||||
in float vs_screenSpaceDepth;
|
||||
in vec4 shadowCoords;
|
||||
|
||||
uniform sampler2DShadow shadowMapTexture;
|
||||
uniform sampler1D ringTexture;
|
||||
uniform vec2 textureOffset;
|
||||
uniform float transparency;
|
||||
|
||||
uniform vec3 sunPosition;
|
||||
uniform float _nightFactor;
|
||||
uniform int nShadowSamples;
|
||||
uniform float zFightingPercentage;
|
||||
|
||||
// temp
|
||||
in vec4 fragPosInLightSpace;
|
||||
|
||||
Fragment getFragment() {
|
||||
// Moving the origin to the center
|
||||
vec2 st = (vs_st - vec2(0.5)) * 2.0;
|
||||
|
||||
// The length of the texture coordinates vector is our distance from the center
|
||||
float radius = length(st);
|
||||
|
||||
// We only want to consider ring-like objects so we need to discard everything else
|
||||
if (radius > 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Remapping the texture coordinates
|
||||
// Radius \in [0,1], texCoord \in [textureOffset.x, textureOffset.y]
|
||||
// textureOffset.x -> 0
|
||||
// textureOffset.y -> 1
|
||||
float texCoord = (radius - textureOffset.x) / (textureOffset.y - textureOffset.x);
|
||||
if (texCoord < 0.f || texCoord > 1.f) {
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 diffuse = texture(ringTexture, texCoord);
|
||||
float colorValue = length(diffuse.rgb);
|
||||
// times 3 as length of vec3(1.0, 1.0, 1.0) will return 3 and we want
|
||||
// to normalize the transparency value to [0,1]
|
||||
if (colorValue < 3.0 * transparency) {
|
||||
diffuse.a = pow(colorValue / (3.0 * transparency), 1);
|
||||
//diffuse.a = (colorValue / 3.0) * transparency;
|
||||
if (diffuse.a < 0.65)
|
||||
discard;
|
||||
}
|
||||
|
||||
// shadow == 1.0 means it is not in shadow
|
||||
float shadow = 1.0;
|
||||
if ( shadowCoords.z >= 0 ) {
|
||||
vec4 normalizedShadowCoords = shadowCoords;
|
||||
normalizedShadowCoords.z = normalizeFloat(zFightingPercentage * normalizedShadowCoords.w);
|
||||
normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w;
|
||||
normalizedShadowCoords.w = 1.0;
|
||||
|
||||
float sum = 0;
|
||||
for (int i = 0; i < nShadowSamples; ++i) {
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, -nShadowSamples + i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, 0));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, nShadowSamples - i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , -nShadowSamples + i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , nShadowSamples - i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, -nShadowSamples + i));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, 0));
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, nShadowSamples - i));
|
||||
}
|
||||
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(0, 0));
|
||||
shadow = sum / (8.0 * nShadowSamples + 1.f);
|
||||
}
|
||||
|
||||
// The normal for the one plane depends on whether we are dealing
|
||||
// with a front facing or back facing fragment
|
||||
vec3 normal;
|
||||
// The plane is oriented on the xz plane
|
||||
// WARNING: This might not be the case for Uranus
|
||||
if (gl_FrontFacing) {
|
||||
normal = vec3(-1.0, 0.0, 0.0);
|
||||
}
|
||||
else {
|
||||
normal = vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
// Reduce the color of the fragment by the user factor
|
||||
// if we are facing away from the Sun
|
||||
if (dot(sunPosition, normal) < 0) {
|
||||
diffuse.xyz *= _nightFactor;
|
||||
}
|
||||
|
||||
Fragment frag;
|
||||
|
||||
frag.color = (0.65 * diffuse * shadow) + diffuse * 0.35;
|
||||
frag.depth = vs_screenSpaceDepth;
|
||||
frag.gPosition = vec4(1e30, 1e30, 1e30, 1.0);
|
||||
frag.gNormal = vec4(normal, 1.0);
|
||||
|
||||
return frag;
|
||||
}
|
||||
74
modules/globebrowsing/shaders/rings_geom_fs.glsl
Normal file
74
modules/globebrowsing/shaders/rings_geom_fs.glsl
Normal file
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 "PowerScaling/powerScaling_fs.hglsl"
|
||||
#include "fragment.glsl"
|
||||
|
||||
in vec2 vs_st;
|
||||
in float vs_screenSpaceDepth;
|
||||
|
||||
uniform sampler1D ringTexture;
|
||||
uniform vec2 textureOffset;
|
||||
|
||||
Fragment getFragment() {
|
||||
// Moving the origin to the center
|
||||
vec2 st = (vs_st - vec2(0.5)) * 2.0;
|
||||
|
||||
// The length of the texture coordinates vector is our distance from the center
|
||||
float radius = length(st);
|
||||
|
||||
// We only want to consider ring-like objects so we need to discard everything else
|
||||
if (radius > 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Remapping the texture coordinates
|
||||
// Radius \in [0,1], texCoord \in [textureOffset.x, textureOffset.y]
|
||||
// textureOffset.x -> 0
|
||||
// textureOffset.y -> 1
|
||||
float texCoord = (radius - textureOffset.x) / (textureOffset.y - textureOffset.x);
|
||||
if (texCoord < 0.f || texCoord > 1.f) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float diffuse = length(texture(ringTexture, texCoord).rgb);
|
||||
|
||||
// The normal for the one plane depends on whether we are dealing
|
||||
// with a front facing or back facing fragment
|
||||
//vec3 normal;
|
||||
// The plane is oriented on the xz plane
|
||||
// WARNING: This might not be the case for Uranus
|
||||
// if (gl_FrontFacing) {
|
||||
// normal = vec3(-1.0, 0.0, 0.0);
|
||||
// }
|
||||
// else {
|
||||
// normal = vec3(1.0, 0.0, 0.0);
|
||||
// }
|
||||
|
||||
Fragment frag;
|
||||
frag.color = vec4(vec3(vs_screenSpaceDepth), 1.0);
|
||||
frag.depth = (diffuse < 0.5) ? 1E30 : vs_screenSpaceDepth;
|
||||
|
||||
return frag;
|
||||
}
|
||||
47
modules/globebrowsing/shaders/rings_geom_vs.glsl
Normal file
47
modules/globebrowsing/shaders/rings_geom_vs.glsl
Normal file
@@ -0,0 +1,47 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "PowerScaling/powerScalingMath.hglsl"
|
||||
|
||||
layout(location = 0) in vec2 in_position;
|
||||
layout(location = 1) in vec2 in_st;
|
||||
|
||||
out vec2 vs_st;
|
||||
out float vs_screenSpaceDepth;
|
||||
|
||||
uniform dmat4 modelViewProjectionMatrix;
|
||||
|
||||
void main() {
|
||||
vs_st = in_st;
|
||||
|
||||
dvec4 positionClipSpace = modelViewProjectionMatrix *
|
||||
dvec4(in_position, 0.0, 1.0);
|
||||
vec4 positionClipSpaceZNorm = z_normalization(vec4(positionClipSpace));
|
||||
|
||||
vs_screenSpaceDepth = positionClipSpaceZNorm.w;
|
||||
|
||||
gl_Position = positionClipSpaceZNorm;
|
||||
}
|
||||
53
modules/globebrowsing/shaders/rings_vs.glsl
Normal file
53
modules/globebrowsing/shaders/rings_vs.glsl
Normal file
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "PowerScaling/powerScaling_vs.hglsl"
|
||||
|
||||
layout(location = 0) in vec2 in_position;
|
||||
layout(location = 1) in vec2 in_st;
|
||||
|
||||
out vec2 vs_st;
|
||||
out float vs_screenSpaceDepth;
|
||||
out vec4 vs_positionViewSpace;
|
||||
out vec4 shadowCoords;
|
||||
|
||||
uniform dmat4 modelViewProjectionMatrix;
|
||||
|
||||
// ShadowMatrix is the matrix defined by:
|
||||
// textureCoordsMatrix * projectionMatrix * combinedViewMatrix * modelMatrix
|
||||
// where textureCoordsMatrix is just a scale and bias computation: [-1,1] to [0,1]
|
||||
uniform dmat4 shadowMatrix;
|
||||
|
||||
void main() {
|
||||
vs_st = in_st;
|
||||
|
||||
dvec4 positionClipSpace = modelViewProjectionMatrix * dvec4(in_position, 0.0, 1.0);
|
||||
vec4 positionClipSpaceZNorm = z_normalization(vec4(positionClipSpace));
|
||||
|
||||
shadowCoords = vec4(shadowMatrix * dvec4(in_position, 0.0, 1.0));
|
||||
vs_screenSpaceDepth = positionClipSpaceZNorm.w;
|
||||
gl_Position = positionClipSpaceZNorm;
|
||||
}
|
||||
40
modules/globebrowsing/shaders/smviewer_fs.glsl
Normal file
40
modules/globebrowsing/shaders/smviewer_fs.glsl
Normal file
@@ -0,0 +1,40 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 "PowerScaling/powerScaling_fs.hglsl"
|
||||
#include "fragment.glsl"
|
||||
|
||||
precision highp float;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform highp sampler2D shadowMapTexture;
|
||||
|
||||
Fragment getFragment() {
|
||||
Fragment frag;
|
||||
frag.color = vec4(vec3(1.f) - texture(shadowMapTexture, texCoord).rrr, 1.f);
|
||||
frag.depth = 0.f;
|
||||
|
||||
return frag;
|
||||
}
|
||||
51
modules/globebrowsing/shaders/smviewer_vs.glsl
Normal file
51
modules/globebrowsing/shaders/smviewer_vs.glsl
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
out vec2 texCoord;
|
||||
|
||||
const vec3 posData[6] = vec3[] (
|
||||
vec3(1.0, -0.5, 0.0),
|
||||
vec3(0.5, -0.5, 0.0),
|
||||
vec3(0.5, -1.0, 0.0),
|
||||
vec3(1.0, -1.0, 0.0),
|
||||
vec3(1.0, -0.5, 0.0),
|
||||
vec3(0.5, -1.0, 0.0)
|
||||
);
|
||||
|
||||
const vec2 texData[6] = vec2[] (
|
||||
vec2(1.0, 1.0),
|
||||
vec2(0.0, 1.0),
|
||||
vec2(0.0, 0.0),
|
||||
vec2(1.0, 0.0),
|
||||
vec2(1.0, 1.0),
|
||||
vec2(0.0, 0.0)
|
||||
|
||||
);
|
||||
|
||||
void main() {
|
||||
texCoord = texData[gl_VertexID];
|
||||
gl_Position = vec4(posData[gl_VertexID], 1.0);
|
||||
}
|
||||
@@ -64,6 +64,7 @@
|
||||
#define SHOW_CHUNK_EDGES #{showChunkEdges}
|
||||
#define SHOW_HEIGHT_RESOLUTION #{showHeightResolution}
|
||||
#define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities}
|
||||
#define SHADOW_MAPPING_ENABLED #{enableShadowMapping}
|
||||
|
||||
const vec3 DefaultLevelWeights = vec3(1.0, 0.0, 0.0);
|
||||
|
||||
|
||||
@@ -184,6 +184,26 @@ namespace {
|
||||
"Enables the rendering of eclipse shadows using hard shadows"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ShadowMappingInfo = {
|
||||
"ShadowMapping",
|
||||
"Shadow Mapping",
|
||||
"Enables shadow mapping algorithm. Used by renderable rings too."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ZFightingPercentageInfo = {
|
||||
"ZFightingPercentage",
|
||||
"Z-Fighting Percentage",
|
||||
"The percentage of the correct distance to the surface being shadowed. "
|
||||
"Possible values: [0.0, 1.0]"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo NumberShadowSamplesInfo = {
|
||||
"NumberShadowSamples",
|
||||
"Number of Shadow Samples",
|
||||
"The number of samples used during shadow mapping calculation "
|
||||
"(Percentage Closer Filtering)."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo TargetLodScaleFactorInfo = {
|
||||
"TargetLodScaleFactor",
|
||||
"Target Level of Detail Scale Factor",
|
||||
@@ -495,16 +515,22 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
BoolProperty(AccurateNormalsInfo, false),
|
||||
BoolProperty(EclipseInfo, false),
|
||||
BoolProperty(EclipseHardShadowsInfo, false),
|
||||
BoolProperty(ShadowMappingInfo, false),
|
||||
FloatProperty(ZFightingPercentageInfo, 0.995f, 0.000001f, 1.f),
|
||||
IntProperty(NumberShadowSamplesInfo, 5, 1, 20),
|
||||
FloatProperty(TargetLodScaleFactorInfo, 15.f, 1.f, 50.f),
|
||||
FloatProperty(CurrentLodScaleFactorInfo, 15.f, 1.f, 50.f),
|
||||
FloatProperty(CameraMinHeightInfo, 100.f, 0.f, 1000.f),
|
||||
FloatProperty(OrenNayarRoughnessInfo, 0.f, 0.f, 1.f),
|
||||
IntProperty(NActiveLayersInfo, 0, 0, OpenGLCap.maxTextureUnits() / 3)
|
||||
})
|
||||
, _shadowMappingPropertyOwner({ "Shadow Mapping" })
|
||||
, _debugPropertyOwner({ "Debug" })
|
||||
, _grid(DefaultSkirtedGridSegments, DefaultSkirtedGridSegments)
|
||||
, _leftRoot(Chunk(LeftHemisphereIndex))
|
||||
, _rightRoot(Chunk(RightHemisphereIndex))
|
||||
, _ringsComponent(dictionary)
|
||||
, _shadowComponent(dictionary)
|
||||
{
|
||||
_generalProperties.currentLodScaleFactor.setReadOnly(true);
|
||||
|
||||
@@ -535,6 +561,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
addProperty(_generalProperties.useAccurateNormals);
|
||||
addProperty(_generalProperties.eclipseShadowsEnabled);
|
||||
addProperty(_generalProperties.eclipseHardShadows);
|
||||
|
||||
_shadowMappingPropertyOwner.addProperty(_generalProperties.shadowMapping);
|
||||
_shadowMappingPropertyOwner.addProperty(_generalProperties.zFightingPercentage);
|
||||
_shadowMappingPropertyOwner.addProperty(_generalProperties.nShadowSamples);
|
||||
addPropertySubOwner(_shadowMappingPropertyOwner);
|
||||
|
||||
_generalProperties.targetLodScaleFactor.onChange([this]() {
|
||||
float sf = _generalProperties.targetLodScaleFactor;
|
||||
_generalProperties.currentLodScaleFactor = sf;
|
||||
@@ -656,6 +688,24 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
_labelsDictionary = dictionary.value<ghoul::Dictionary>(KeyLabels);
|
||||
}
|
||||
|
||||
// Components
|
||||
if (dictionary.hasKey("Rings")) {
|
||||
_ringsComponent.initialize();
|
||||
addPropertySubOwner(_ringsComponent);
|
||||
_hasRings = true;
|
||||
|
||||
ghoul::Dictionary ringsDic;
|
||||
dictionary.getValue("Rings", ringsDic);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey("Shadows")) {
|
||||
_shadowComponent.initialize();
|
||||
addPropertySubOwner(_shadowComponent);
|
||||
_hasShadows = true;
|
||||
_generalProperties.shadowMapping = true;
|
||||
}
|
||||
_generalProperties.shadowMapping.onChange(notifyShaderRecompilation);
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION
|
||||
_module = global::moduleEngine.module<GlobeBrowsingModule>();
|
||||
#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION
|
||||
@@ -670,6 +720,15 @@ void RenderableGlobe::initializeGL() {
|
||||
_layerManager.update();
|
||||
|
||||
_grid.initializeGL();
|
||||
|
||||
if (_hasRings) {
|
||||
_ringsComponent.initializeGL();
|
||||
}
|
||||
|
||||
if (_hasShadows) {
|
||||
_shadowComponent.initializeGL();
|
||||
}
|
||||
|
||||
// Recompile the shaders directly so that it is not done the first time the render
|
||||
// function is called.
|
||||
recompileShaders();
|
||||
@@ -691,6 +750,14 @@ void RenderableGlobe::deinitializeGL() {
|
||||
}
|
||||
|
||||
_grid.deinitializeGL();
|
||||
|
||||
if (_hasRings) {
|
||||
_ringsComponent.deinitializeGL();
|
||||
}
|
||||
|
||||
if (_hasShadows) {
|
||||
_shadowComponent.deinitializeGL();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableGlobe::isReady() const {
|
||||
@@ -713,8 +780,44 @@ void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask
|
||||
|
||||
if (distanceToCamera < distance) {
|
||||
try {
|
||||
renderChunks(data, rendererTask);
|
||||
_globeLabelsComponent.draw(data);
|
||||
// Before Shadows
|
||||
//renderChunks(data, rendererTask);
|
||||
//_globeLabelsComponent.draw(data);
|
||||
|
||||
if (_hasShadows && _shadowComponent.isEnabled()) {
|
||||
// Set matrices and other GL states
|
||||
RenderData lightRenderData(_shadowComponent.begin(data));
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
// Render from light source point of view
|
||||
renderChunks(lightRenderData, rendererTask, {}, true);
|
||||
if (_hasRings && _ringsComponent.isEnabled()) {
|
||||
_ringsComponent.draw(lightRenderData, RingsComponent::GeometryOnly);
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
_shadowComponent.setViewDepthMap(false);
|
||||
|
||||
_shadowComponent.end();
|
||||
|
||||
// Render again from original point of view
|
||||
renderChunks(data, rendererTask, _shadowComponent.shadowMapData());
|
||||
if (_hasRings && _ringsComponent.isEnabled()) {
|
||||
_ringsComponent.draw(
|
||||
data,
|
||||
RingsComponent::GeometryAndShading,
|
||||
_shadowComponent.shadowMapData()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
renderChunks(data, rendererTask);
|
||||
if (_hasRings && _ringsComponent.isEnabled()) {
|
||||
_ringsComponent.draw(data, RingsComponent::GeometryAndShading);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const ghoul::opengl::TextureUnit::TextureUnitError&) {
|
||||
std::string layer = _lastChangedLayer ? _lastChangedLayer->guiName() : "";
|
||||
@@ -807,6 +910,15 @@ void RenderableGlobe::update(const UpdateData& data) {
|
||||
_layerManager.reset();
|
||||
_debugProperties.resetTileProviders = false;
|
||||
}
|
||||
|
||||
if (_hasRings) {
|
||||
_ringsComponent.update(data);
|
||||
}
|
||||
|
||||
if (_hasShadows) {
|
||||
_shadowComponent.update(data);
|
||||
}
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION
|
||||
_nUploadedTiles = _layerManager.update();
|
||||
#else
|
||||
@@ -852,7 +964,10 @@ const glm::dmat4& RenderableGlobe::modelTransform() const {
|
||||
// Rendering code
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) {
|
||||
void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
|
||||
const ShadowComponent::ShadowMapData& shadowData,
|
||||
bool renderGeomOnly)
|
||||
{
|
||||
if (_shadersNeedRecompilation) {
|
||||
recompileShaders();
|
||||
}
|
||||
@@ -1086,7 +1201,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) {
|
||||
// Render all chunks that want to be rendered globally
|
||||
_globalRenderer.program->activate();
|
||||
for (int i = 0; i < std::min(globalCount, ChunkBufferSize); ++i) {
|
||||
renderChunkGlobally(*global[i], data);
|
||||
renderChunkGlobally(*global[i], data, shadowData, renderGeomOnly);
|
||||
}
|
||||
_globalRenderer.program->deactivate();
|
||||
|
||||
@@ -1094,7 +1209,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) {
|
||||
// Render all chunks that need to be rendered locally
|
||||
_localRenderer.program->activate();
|
||||
for (int i = 0; i < std::min(localCount, ChunkBufferSize); ++i) {
|
||||
renderChunkLocally(*local[i], data);
|
||||
renderChunkLocally(*local[i], data, shadowData, renderGeomOnly);
|
||||
}
|
||||
_localRenderer.program->deactivate();
|
||||
|
||||
@@ -1151,7 +1266,10 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& data) {
|
||||
void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& data,
|
||||
const ShadowComponent::ShadowMapData& shadowData,
|
||||
bool renderGeomOnly)
|
||||
{
|
||||
//PerfMeasure("globally");
|
||||
const TileIndex& tileIndex = chunk.tileIndex;
|
||||
ghoul::opengl::ProgramObject& program = *_globalRenderer.program;
|
||||
@@ -1198,17 +1316,43 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData&
|
||||
calculateEclipseShadows(program, data, ShadowCompType::GLOBAL_SHADOW);
|
||||
}
|
||||
|
||||
// Shadow Mapping
|
||||
ghoul::opengl::TextureUnit shadowMapUnit;
|
||||
if (_generalProperties.shadowMapping && shadowData.shadowDepthTexture != 0) {
|
||||
// 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.
|
||||
program.setUniform(
|
||||
"shadowMatrix",
|
||||
shadowData.shadowMatrix * modelTransform()
|
||||
);
|
||||
|
||||
shadowMapUnit.activate();
|
||||
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
|
||||
|
||||
program.setUniform("shadowMapTexture", shadowMapUnit);
|
||||
program.setUniform("nShadowSamples", _generalProperties.nShadowSamples);
|
||||
program.setUniform("zFightingPercentage", _generalProperties.zFightingPercentage);
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
if (!renderGeomOnly) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
}
|
||||
|
||||
_grid.drawUsingActiveProgram();
|
||||
|
||||
for (GPULayerGroup& l : _globalRenderer.gpuLayerGroups) {
|
||||
l.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& data) {
|
||||
void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& data,
|
||||
const ShadowComponent::ShadowMapData& shadowData,
|
||||
bool renderGeomOnly)
|
||||
{
|
||||
//PerfMeasure("locally");
|
||||
const TileIndex& tileIndex = chunk.tileIndex;
|
||||
ghoul::opengl::ProgramObject& program = *_localRenderer.program;
|
||||
@@ -1300,10 +1444,31 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d
|
||||
calculateEclipseShadows(program, data, ShadowCompType::LOCAL_SHADOW);
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
// Shadow Mapping
|
||||
ghoul::opengl::TextureUnit shadowMapUnit;
|
||||
if (_generalProperties.shadowMapping && shadowData.shadowDepthTexture != 0) {
|
||||
// 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.
|
||||
program.setUniform(
|
||||
"shadowMatrix",
|
||||
shadowData.shadowMatrix * modelTransform()
|
||||
);
|
||||
|
||||
shadowMapUnit.activate();
|
||||
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
|
||||
|
||||
program.setUniform("shadowMapTexture", shadowMapUnit);
|
||||
program.setUniform("nShadowSamples", _generalProperties.nShadowSamples);
|
||||
program.setUniform("zFightingPercentage", _generalProperties.zFightingPercentage);
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
if (!renderGeomOnly) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
}
|
||||
|
||||
_grid.drawUsingActiveProgram();
|
||||
|
||||
for (GPULayerGroup& l : _localRenderer.gpuLayerGroups) {
|
||||
@@ -1465,6 +1630,10 @@ void RenderableGlobe::recompileShaders() {
|
||||
"useEclipseHardShadows",
|
||||
std::to_string(_generalProperties.eclipseHardShadows)
|
||||
);
|
||||
pairs.emplace_back(
|
||||
"enableShadowMapping",
|
||||
std::to_string(_generalProperties.shadowMapping)
|
||||
);
|
||||
pairs.emplace_back("showChunkEdges", std::to_string(_debugProperties.showChunkEdges));
|
||||
pairs.emplace_back("showHeightResolution",
|
||||
std::to_string(_debugProperties.showHeightResolution)
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <modules/globebrowsing/src/globelabelscomponent.h>
|
||||
#include <modules/globebrowsing/src/gpulayergroup.h>
|
||||
#include <modules/globebrowsing/src/layermanager.h>
|
||||
#include <modules/globebrowsing/src/ringscomponent.h>
|
||||
#include <modules/globebrowsing/src/shadowcomponent.h>
|
||||
#include <modules/globebrowsing/src/skirtedgrid.h>
|
||||
#include <modules/globebrowsing/src/tileindex.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
@@ -127,24 +129,29 @@ private:
|
||||
properties::BoolProperty showHeightIntensities;
|
||||
properties::BoolProperty levelByProjectedAreaElseDistance;
|
||||
properties::BoolProperty resetTileProviders;
|
||||
properties::IntProperty modelSpaceRenderingCutoffLevel;
|
||||
properties::IntProperty dynamicLodIterationCount;
|
||||
properties::IntProperty modelSpaceRenderingCutoffLevel;
|
||||
properties::IntProperty dynamicLodIterationCount;
|
||||
} _debugProperties;
|
||||
|
||||
struct {
|
||||
properties::BoolProperty performShading;
|
||||
properties::BoolProperty useAccurateNormals;
|
||||
properties::BoolProperty eclipseShadowsEnabled;
|
||||
properties::BoolProperty eclipseHardShadows;
|
||||
properties::BoolProperty performShading;
|
||||
properties::BoolProperty useAccurateNormals;
|
||||
properties::BoolProperty eclipseShadowsEnabled;
|
||||
properties::BoolProperty eclipseHardShadows;
|
||||
properties::BoolProperty shadowMapping;
|
||||
properties::FloatProperty zFightingPercentage;
|
||||
properties::IntProperty nShadowSamples;
|
||||
properties::FloatProperty targetLodScaleFactor;
|
||||
properties::FloatProperty currentLodScaleFactor;
|
||||
properties::FloatProperty cameraMinHeight;
|
||||
properties::FloatProperty orenNayarRoughness;
|
||||
properties::IntProperty nActiveLayers;
|
||||
properties::IntProperty nActiveLayers;
|
||||
} _generalProperties;
|
||||
|
||||
properties::PropertyOwner _debugPropertyOwner;
|
||||
|
||||
properties::PropertyOwner _shadowMappingPropertyOwner;
|
||||
|
||||
/**
|
||||
* Test if a specific chunk can safely be culled without affecting the rendered
|
||||
* image.
|
||||
@@ -181,7 +188,9 @@ private:
|
||||
*/
|
||||
float getHeight(const glm::dvec3& position) const;
|
||||
|
||||
void renderChunks(const RenderData& data, RendererTasks& rendererTask);
|
||||
void renderChunks(const RenderData& data, RendererTasks& rendererTask,
|
||||
const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Chunks can be rendered either globally or locally. Global rendering is performed
|
||||
@@ -191,7 +200,9 @@ private:
|
||||
* point precision by doing this which means that the camera too close to a global
|
||||
* tile will lead to jagging. We only render global chunks for lower chunk levels.
|
||||
*/
|
||||
void renderChunkGlobally(const Chunk& chunk, const RenderData& data);
|
||||
void renderChunkGlobally(const Chunk& chunk, const RenderData& data,
|
||||
const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Local rendering of chunks are done using linear interpolation in camera space.
|
||||
@@ -204,7 +215,9 @@ private:
|
||||
* levels) the better the approximation becomes. This is why we only render local
|
||||
* chunks for higher chunk levels.
|
||||
*/
|
||||
void renderChunkLocally(const Chunk& chunk, const RenderData& data);
|
||||
void renderChunkLocally(const Chunk& chunk, const RenderData& data,
|
||||
const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false
|
||||
);
|
||||
|
||||
void debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp,
|
||||
bool renderBounds, bool renderAABB) const;
|
||||
@@ -275,6 +288,12 @@ private:
|
||||
size_t _iterationsOfUnavailableData = 0;
|
||||
Layer* _lastChangedLayer = nullptr;
|
||||
|
||||
// Components
|
||||
RingsComponent _ringsComponent;
|
||||
ShadowComponent _shadowComponent;
|
||||
bool _hasRings = false;
|
||||
bool _hasShadows = false;
|
||||
|
||||
// Labels
|
||||
GlobeLabelsComponent _globeLabelsComponent;
|
||||
ghoul::Dictionary _labelsDictionary;
|
||||
|
||||
481
modules/globebrowsing/src/ringscomponent.cpp
Normal file
481
modules/globebrowsing/src/ringscomponent.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <modules/globebrowsing/src/ringscomponent.h>
|
||||
|
||||
#include <modules/globebrowsing/globebrowsingmodule.h>
|
||||
#include <modules/globebrowsing/src/renderableglobe.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/filesystem/cachemanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/font/fontmanager.h>
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <locale>
|
||||
|
||||
namespace {
|
||||
constexpr const std::array<const char*, 10> UniformNames = {
|
||||
"modelViewProjectionMatrix", "textureOffset", "transparency", "_nightFactor",
|
||||
"sunPosition", "ringTexture", "shadowMatrix", "shadowMapTexture",
|
||||
"nShadowSamples", "zFightingPercentage"
|
||||
};
|
||||
|
||||
constexpr const std::array<const char*, 3> GeomUniformNames = {
|
||||
"modelViewProjectionMatrix", "textureOffset", "ringTexture"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo TextureInfo = {
|
||||
"Texture",
|
||||
"Texture",
|
||||
"This value is the path to a texture on disk that contains a one-dimensional "
|
||||
"texture which is used for these rings."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SizeInfo = {
|
||||
"Size",
|
||||
"Size",
|
||||
"This value specifies the radius of the rings in meter."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo OffsetInfo = {
|
||||
"Offset",
|
||||
"Offset",
|
||||
"This value is used to limit the width of the rings.Each of the two values is a "
|
||||
"value between 0 and 1, where 0 is the center of the ring and 1 is the maximum "
|
||||
"extent at the radius. If this value is, for example {0.5, 1.0}, the ring is "
|
||||
"only shown between radius/2 and radius. It defaults to {0.0, 1.0}."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo NightFactorInfo = {
|
||||
"NightFactor",
|
||||
"Night Factor",
|
||||
"This value is a multiplicative factor that is applied to the side of the rings "
|
||||
"that is facing away from the Sun. If this value is equal to '1', no darkening "
|
||||
"of the night side occurs."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo TransparencyInfo = {
|
||||
"Transparency",
|
||||
"Transparency",
|
||||
"This value determines the transparency of part of the rings depending on the "
|
||||
"color values. For this value v, the transparency is equal to length(color) / v."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ZFightingPercentageInfo = {
|
||||
"ZFightingPercentage",
|
||||
"Z-Fighting Percentage",
|
||||
"The percentage of the correct distance to the surface being shadowed. "
|
||||
"Possible values: [0.0, 1.0]"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo NumberShadowSamplesInfo = {
|
||||
"NumberShadowSamples",
|
||||
"Number of Shadow Samples",
|
||||
"The number of samples used during shadow mapping calculation "
|
||||
"(Percentage Closer Filtering)."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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")) {
|
||||
// @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"
|
||||
);
|
||||
}
|
||||
|
||||
void RingsComponent::initialize() {
|
||||
using ghoul::filesystem::File;
|
||||
|
||||
addProperty(_enabled);
|
||||
|
||||
_size = static_cast<float>(_ringsDictionary.value<double>(SizeInfo.identifier));
|
||||
//setBoundingSphere(_size);
|
||||
_size.onChange([&]() { _planeIsDirty = true; });
|
||||
addProperty(_size);
|
||||
|
||||
_texturePath = absPath(
|
||||
_ringsDictionary.value<std::string>(TextureInfo.identifier)
|
||||
);
|
||||
_textureFile = std::make_unique<File>(_texturePath);
|
||||
|
||||
if (_ringsDictionary.hasKeyAndValue<glm::vec2>(OffsetInfo.identifier)) {
|
||||
_offset = _ringsDictionary.value<glm::vec2>(OffsetInfo.identifier);
|
||||
}
|
||||
addProperty(_offset);
|
||||
|
||||
_texturePath.onChange([&]() { loadTexture(); });
|
||||
addProperty(_texturePath);
|
||||
|
||||
_textureFile->setCallback([&](const File&) { _textureIsDirty = true; });
|
||||
|
||||
if (_ringsDictionary.hasKeyAndValue<double>(NightFactorInfo.identifier)) {
|
||||
_nightFactor = static_cast<float>(
|
||||
_ringsDictionary.value<double>(NightFactorInfo.identifier)
|
||||
);
|
||||
}
|
||||
addProperty(_nightFactor);
|
||||
|
||||
if (_ringsDictionary.hasKeyAndValue<double>(TransparencyInfo.identifier)) {
|
||||
_transparency = static_cast<float>(
|
||||
_ringsDictionary.value<double>(TransparencyInfo.identifier)
|
||||
);
|
||||
}
|
||||
|
||||
// Shadow Mapping Quality Controls
|
||||
if (_ringsDictionary.hasKey(ZFightingPercentageInfo.identifier)) {
|
||||
_zFightingPercentage = _ringsDictionary.value<float>(
|
||||
ZFightingPercentageInfo.identifier
|
||||
);
|
||||
}
|
||||
addProperty(_zFightingPercentage);
|
||||
|
||||
if (_ringsDictionary.hasKey(NumberShadowSamplesInfo.identifier)) {
|
||||
_nShadowSamples = _ringsDictionary.value<int>(NumberShadowSamplesInfo.identifier);
|
||||
}
|
||||
addProperty(_nShadowSamples);
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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> texture = TextureReader::ref().loadTexture(
|
||||
absPath(_texturePath)
|
||||
);
|
||||
|
||||
if (texture) {
|
||||
LDEBUGC(
|
||||
"RingsComponent",
|
||||
fmt::format("Loaded texture from '{}'", absPath(_texturePath))
|
||||
);
|
||||
_texture = std::move(texture);
|
||||
|
||||
_texture->uploadTexture();
|
||||
_texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
|
||||
|
||||
_textureFile = std::make_unique<ghoul::filesystem::File>(_texturePath);
|
||||
_textureFile->setCallback(
|
||||
[&](const ghoul::filesystem::File&) { _textureIsDirty = true; }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RingsComponent::createPlane() {
|
||||
const GLfloat size = _size;
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
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<void*>(offsetof(VertexData, s)) // NOLINT
|
||||
);
|
||||
}
|
||||
|
||||
bool RingsComponent::isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
112
modules/globebrowsing/src/ringscomponent.h
Normal file
112
modules/globebrowsing/src/ringscomponent.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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__
|
||||
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
|
||||
#include <modules/globebrowsing/src/shadowcomponent.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/vector/vec2property.h>
|
||||
#include <openspace/properties/vector/vec4property.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/uniformcache.h>
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
namespace ghoul::filesystem { class File; }
|
||||
namespace ghoul::opengl { class ProgramObject; }
|
||||
|
||||
namespace openspace {
|
||||
struct RenderData;
|
||||
struct UpdateData;
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class RingsComponent : public properties::PropertyOwner {
|
||||
public:
|
||||
enum RenderPass {
|
||||
GeometryOnly,
|
||||
GeometryAndShading
|
||||
};
|
||||
|
||||
RingsComponent(const ghoul::Dictionary& dictionary);
|
||||
|
||||
void initialize();
|
||||
void initializeGL();
|
||||
void deinitializeGL();
|
||||
|
||||
bool isReady() const;
|
||||
|
||||
void draw(
|
||||
const RenderData& data,
|
||||
const RingsComponent::RenderPass renderPass,
|
||||
const ShadowComponent::ShadowMapData& shadowData = {}
|
||||
);
|
||||
void update(const UpdateData& data);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
bool isEnabled() const;
|
||||
|
||||
private:
|
||||
void loadTexture();
|
||||
void createPlane();
|
||||
|
||||
properties::StringProperty _texturePath;
|
||||
properties::FloatProperty _size;
|
||||
properties::Vec2Property _offset;
|
||||
properties::FloatProperty _nightFactor;
|
||||
properties::FloatProperty _transparency;
|
||||
properties::BoolProperty _enabled;
|
||||
properties::FloatProperty _zFightingPercentage;
|
||||
properties::IntProperty _nShadowSamples;
|
||||
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _shader;
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _geometryOnlyShader;
|
||||
UniformCache(modelViewProjectionMatrix, textureOffset, transparency, nightFactor,
|
||||
sunPosition, ringTexture, shadowMatrix, shadowMapTexture, nShadowSamples,
|
||||
zFightingPercentage
|
||||
) _uniformCache;
|
||||
UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture)
|
||||
_geomUniformCache;
|
||||
std::unique_ptr<ghoul::opengl::Texture> _texture;
|
||||
std::unique_ptr<ghoul::filesystem::File> _textureFile;
|
||||
|
||||
ghoul::Dictionary _ringsDictionary;
|
||||
bool _textureIsDirty = false;
|
||||
GLuint _quad = 0;
|
||||
GLuint _vertexPositionBuffer = 0;
|
||||
bool _planeIsDirty = false;
|
||||
|
||||
glm::vec3 _sunPosition;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___RINGSCOMPONENT___H__
|
||||
652
modules/globebrowsing/src/shadowcomponent.cpp
Normal file
652
modules/globebrowsing/src/shadowcomponent.cpp
Normal file
@@ -0,0 +1,652 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <modules/globebrowsing/src/shadowcomponent.h>
|
||||
|
||||
#include <modules/globebrowsing/globebrowsingmodule.h>
|
||||
#include <modules/globebrowsing/src/renderableglobe.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/keyframenavigator.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/filesystem/cachemanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/textureunit.h>
|
||||
#include <ghoul/font/fontmanager.h>
|
||||
#include <ghoul/font/fontrenderer.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <locale>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "ShadowComponent";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SaveDepthTextureInfo = {
|
||||
"SaveDepthTextureInfo",
|
||||
"Save Depth Texture",
|
||||
"Debug"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DistanceFractionInfo = {
|
||||
"DistanceFraction",
|
||||
"Distance Fraction",
|
||||
"Distance fraction of original distance from light source to the globe to be "
|
||||
"considered as the new light source distance."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DepthMapSizeInfo = {
|
||||
"DepthMapSize",
|
||||
"Depth Map Size",
|
||||
"The depth map size in pixels. You must entry the width and height values."
|
||||
};
|
||||
|
||||
constexpr const GLfloat ShadowBorder[] = { 1.f, 1.f, 1.f, 1.f };
|
||||
|
||||
void checkFrameBufferState(const std::string& codePosition) {
|
||||
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
LERROR("Framework not built. " + codePosition);
|
||||
GLenum fbErr = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
switch (fbErr) {
|
||||
case GL_FRAMEBUFFER_UNDEFINED:
|
||||
LERROR("Indefined framebuffer.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
LERROR("Incomplete, missing attachement.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
LERROR("Framebuffer doesn't have at least one image attached to it.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
LERROR(
|
||||
"Returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is "
|
||||
"GL_NONE for any color attachment point(s) named by GL_DRAW_BUFFERi."
|
||||
);
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
LERROR(
|
||||
"Returned if GL_READ_BUFFER is not GL_NONE and the value of "
|
||||
"GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color "
|
||||
"attachment point named by GL_READ_BUFFER.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
LERROR(
|
||||
"Returned if the combination of internal formats of the attached "
|
||||
"images violates an implementation - dependent set of restrictions."
|
||||
);
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
LERROR(
|
||||
"Returned if the value of GL_RENDERBUFFE_r_samples is not the same "
|
||||
"for all attached renderbuffers; if the value of GL_TEXTURE_SAMPLES "
|
||||
"is the not same for all attached textures; or , if the attached "
|
||||
"images are a mix of renderbuffers and textures, the value of "
|
||||
"GL_RENDERBUFFE_r_samples does not match the value of "
|
||||
"GL_TEXTURE_SAMPLES."
|
||||
);
|
||||
LERROR(
|
||||
"Returned if the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not "
|
||||
"the same for all attached textures; or , if the attached images are "
|
||||
"a mix of renderbuffers and textures, the value of "
|
||||
"GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached "
|
||||
"textures."
|
||||
);
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
LERROR(
|
||||
"Returned if any framebuffer attachment is layered, and any "
|
||||
"populated attachment is not layered, or if all populated color "
|
||||
"attachments are not from textures of the same target."
|
||||
);
|
||||
break;
|
||||
default:
|
||||
LDEBUG("No error found checking framebuffer: " + codePosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
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<float>,
|
||||
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);
|
||||
}
|
||||
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
_shadowMapDictionary,
|
||||
"ShadowComponent"
|
||||
);
|
||||
|
||||
if (_shadowMapDictionary.hasKey(DistanceFractionInfo.identifier)) {
|
||||
_distanceFraction = static_cast<int>(
|
||||
_shadowMapDictionary.value<float>(DistanceFractionInfo.identifier)
|
||||
);
|
||||
}
|
||||
_saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; });
|
||||
|
||||
|
||||
if (_shadowMapDictionary.hasKey(DepthMapSizeInfo.identifier)) {
|
||||
glm::vec2 depthMapSize =
|
||||
_shadowMapDictionary.value<glm::vec2>(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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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<double>(_distanceFraction)/1.0E5);
|
||||
|
||||
double multiplier = originalLightDistance *
|
||||
(static_cast<double>(_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<Camera>(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&) {
|
||||
_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();
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowComponent::createDepthTexture() {
|
||||
glGenTextures(1, &_shadowDepthTexture);
|
||||
updateDepthTexture();
|
||||
|
||||
_shadowData.shadowDepthTexture = _shadowDepthTexture;
|
||||
//_shadowData.positionInLightSpaceTexture = _positionInLightSpaceTexture;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
//glFramebufferTexture(
|
||||
// GL_FRAMEBUFFER,
|
||||
// GL_COLOR_ATTACHMENT0,
|
||||
// _positionInLightSpaceTexture,
|
||||
// 0
|
||||
//);
|
||||
|
||||
//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() {
|
||||
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;
|
||||
std::vector<GLubyte> buffer(size);
|
||||
|
||||
glReadPixels(
|
||||
0,
|
||||
0,
|
||||
_shadowDepthTextureWidth,
|
||||
_shadowDepthTextureHeight,
|
||||
GL_DEPTH_COMPONENT,
|
||||
GL_UNSIGNED_BYTE,
|
||||
buffer.data()
|
||||
);
|
||||
|
||||
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<unsigned int>(buffer[k]);
|
||||
ppmFile << val << " " << val << " " << val << " ";
|
||||
}
|
||||
ppmFile << std::endl;
|
||||
}
|
||||
|
||||
ppmFile.close();
|
||||
|
||||
std::cout << "Texture saved to file depthBufferShadowMapping.ppm\n\n";
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
|
||||
std::vector<GLfloat> bBuffer(size * 4);
|
||||
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT3);
|
||||
glReadPixels(
|
||||
0,
|
||||
0,
|
||||
_shadowDepthTextureWidth,
|
||||
_shadowDepthTextureHeight,
|
||||
GL_RGBA,
|
||||
GL_FLOAT,
|
||||
bBuffer.data()
|
||||
);
|
||||
|
||||
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<unsigned int>(bBuffer[k] / biggestValue) << " "
|
||||
<< static_cast<unsigned int>(bBuffer[k + 1] / biggestValue) << " "
|
||||
<< static_cast<unsigned int>(bBuffer[k + 2] / biggestValue) << " ";
|
||||
k += 4;
|
||||
}
|
||||
ppmFile << std::endl;
|
||||
}
|
||||
|
||||
ppmFile.close();
|
||||
|
||||
LINFO("Texture saved to file positionBufferShadowMapping.ppm");
|
||||
}
|
||||
}
|
||||
|
||||
bool ShadowComponent::isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
ShadowComponent::ShadowMapData ShadowComponent::shadowMapData() const {
|
||||
return _shadowData;
|
||||
}
|
||||
|
||||
void ShadowComponent::setViewDepthMap(bool enable) {
|
||||
_viewDepthMap = enable;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
154
modules/globebrowsing/src/shadowcomponent.h
Normal file
154
modules/globebrowsing/src/shadowcomponent.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <openspace/properties/propertyowner.h>
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/triggerproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/vector/vec2property.h>
|
||||
#include <openspace/properties/vector/vec4property.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <ghoul/opengl/uniformcache.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
namespace ghoul::filesystem { class File; }
|
||||
namespace ghoul::opengl { class ProgramObject; }
|
||||
|
||||
namespace openspace {
|
||||
struct RenderData;
|
||||
struct UpdateData;
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
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();
|
||||
|
||||
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<Camera> _lightCamera;
|
||||
|
||||
// DEBUG
|
||||
bool _executeDepthTextureSave = false;
|
||||
bool _viewDepthMap = false;
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _renderDMProgram;
|
||||
GLuint _quadVAO = 0u;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GLOBEBROWSING___SHADOWCOMPONENT___H__
|
||||
Reference in New Issue
Block a user