From 532b26bf3cda07fc73f23bdf39f07678f2024389 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Apr 2017 15:32:18 +0200 Subject: [PATCH 001/168] osgShadow experiment --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderingmanager.cpp | 43 +++++++++++++++++++++-- apps/openmw/mwrender/vismask.hpp | 4 ++- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b4e9ad4b..7c8e8cd16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,8 +206,8 @@ if(NOT HAVE_STDINT_H) message(FATAL_ERROR "stdint.h was not found" ) endif() +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX osgShadow) -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a06678488..6e4a7baab 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -126,6 +126,7 @@ target_link_libraries(openmw ${OSGDB_LIBRARIES} ${OSGVIEWER_LIBRARIES} ${OSGGA_LIBRARIES} + ${OSGSHADOW_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6ee9b8ae8..87c13f981 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,6 +13,13 @@ #include #include +#include +#include +#include +#include +#include +#include + #include #include @@ -183,6 +190,7 @@ namespace MWRender , mFieldOfViewOverridden(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); + resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders")); resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); @@ -198,7 +206,35 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - mRootNode->addChild(sceneRoot); + osg::ref_ptr shadowedScene (new osgShadow::ShadowedScene); + + osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings(); + settings->setLightNum(0); + settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player); + settings->setReceivesShadowTraversalMask(~0u); + + settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); + settings->setBaseShadowTextureUnit(1); + settings->setMinimumShadowMapNearFarRatio(0); + settings->setNumShadowMapsPerLight(1); + //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); + //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored + //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + //settings->setDebugDraw(true); + + settings->setPerspectiveShadowMapCutOffAngle(0); + settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); + + int mapres = 2048; + settings->setTextureSize(osg::Vec2s(mapres,mapres)); + + osgShadow::ShadowTechnique* tech = new osgShadow::ViewDependentShadowMap; + shadowedScene->setShadowTechnique(tech); + + //mRootNode->addChild(sceneRoot); + shadowedScene->addChild(sceneRoot); + mRootNode->addChild(shadowedScene); + mPathgrid.reset(new Pathgrid(mRootNode)); @@ -228,7 +264,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - source->setNodeMask(Mask_Lighting); + //source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -272,7 +308,8 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); - mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); + //mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); + mViewer->getCamera()->setCullMask(~(Mask_Lighting)); mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index d52c7c232..1f620b7f7 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -51,7 +51,9 @@ namespace MWRender Mask_PreCompile = (1<<16), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<17) + Mask_Lighting = (1<<17), + + Mask_CastsShadows = (1<<18) }; } From 76e8a0b768bc38c56f1711a1aa1051ac7c0a92ec Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 11 Sep 2017 22:32:45 +0100 Subject: [PATCH 002/168] Add changes I missed in a merge. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0050104cf..5f0c539a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX osgShadow) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS From 99f6a1b8e15b86aa7860b3e3c2890533bb4b8bea Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 19 Sep 2017 23:44:37 +0100 Subject: [PATCH 003/168] Switch to LispSM --- apps/openmw/mwrender/renderingmanager.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 820fdab49..1b78bef80 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -213,24 +213,31 @@ namespace MWRender settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player); settings->setReceivesShadowTraversalMask(~0u); - settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(1); - settings->setMinimumShadowMapNearFarRatio(0); - settings->setNumShadowMapsPerLight(1); + //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); + //settings->setBaseShadowTextureUnit(1); + //settings->setMinimumShadowMapNearFarRatio(0); + //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); //settings->setDebugDraw(true); - settings->setPerspectiveShadowMapCutOffAngle(0); - settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); + //settings->setPerspectiveShadowMapCutOffAngle(0); + //settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); int mapres = 2048; settings->setTextureSize(osg::Vec2s(mapres,mapres)); - osgShadow::ShadowTechnique* tech = new osgShadow::ViewDependentShadowMap; + osgShadow::MinimalShadowMap* tech = new osgShadow::LightSpacePerspectiveShadowMapDB(); shadowedScene->setShadowTechnique(tech); + tech->setMaxFarPlane(0); + tech->setTextureSize(osg::Vec2s(mapres, mapres)); + tech->setShadowTextureCoordIndex(1); + tech->setShadowTextureUnit(1); + tech->setBaseTextureCoordIndex(0); + tech->setBaseTextureUnit(0); + //mRootNode->addChild(sceneRoot); shadowedScene->addChild(sceneRoot); mRootNode->addChild(shadowedScene); From f50063402dea5ab8a2e1badd2e7566d1ca100cbf Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 21 Sep 2017 00:25:48 +0100 Subject: [PATCH 004/168] Adjust shaders to support shadows --- CI/before_script.msvc.sh | 2 +- files/shaders/lighting.glsl | 28 +++++++++++++++++++++------- files/shaders/objects_fragment.glsl | 13 ++++++++++--- files/shaders/objects_vertex.glsl | 6 ++++++ files/shaders/terrain_fragment.glsl | 13 ++++++++++--- files/shaders/terrain_vertex.glsl | 6 ++++++ 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 14998a3c6..11317a33f 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -761,7 +761,7 @@ if [ -z $CI ]; then echo " settings-default.cfg" cp settings-default.cfg $BUILD_CONFIG/settings-default.cfg echo " resources/" - cp -r resources $BUILD_CONFIG/resources + cp -r resources $BUILD_CONFIG echo fi diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 7b8486fbe..892ae485a 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,10 +1,23 @@ #define MAX_LIGHTS 8 -vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) +vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; float d; + lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); + d = length(lightDir); + lightDir = normalize(lightDir); + + return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0); +} + +#ifdef FRAGMENT +vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) +#else +vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) +#endif +{ #if @colorMode == 3 vec4 diffuse = gl_FrontMaterial.diffuse; vec3 ambient = vertexColor.xyz; @@ -17,13 +30,14 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) #endif vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); - for (int i=0; i Date: Thu, 21 Sep 2017 00:49:34 +0100 Subject: [PATCH 005/168] Stop shadowing ambient lighting from the light casting a shadow when using per-pixel lighting. --- files/shaders/lighting.glsl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 892ae485a..e50e2f9c2 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,6 +1,6 @@ #define MAX_LIGHTS 8 -vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) +vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient, float shadowing) { vec3 lightDir; float d; @@ -9,7 +9,7 @@ vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 d = length(lightDir); lightDir = normalize(lightDir); - return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0); + return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0) * shadowing; } #ifdef FRAGMENT @@ -31,13 +31,13 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); #ifdef FRAGMENT - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient) * shadowing; + lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, shadowing); #else - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient); + lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, 1.0); #endif for (int i=1; i Date: Thu, 21 Sep 2017 01:59:02 +0100 Subject: [PATCH 006/168] Make shadows play nicely with per-vertex lighting --- files/shaders/lighting.glsl | 34 +++++++++++++++++++++-------- files/shaders/objects_fragment.glsl | 3 ++- files/shaders/objects_vertex.glsl | 3 ++- files/shaders/terrain_fragment.glsl | 3 ++- files/shaders/terrain_vertex.glsl | 3 ++- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index e50e2f9c2..fe298e160 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,21 +1,33 @@ #define MAX_LIGHTS 8 -vec3 perLight(int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient, float shadowing) +vec3 lightAmbient(int lightIndex, vec3 ambient) +{ + return ambient * gl_LightSource[lightIndex].ambient.xyz; +} + +vec3 lightDiffuse(int lightIndex, vec4 diffuse, vec3 viewNormal, vec3 lightDir) +{ + return diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0); +} + +void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; - float d; + float lightDistance; - lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); - d = length(lightDir); + lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); + lightDistance = length(lightDir); lightDir = normalize(lightDir); + float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); - return (ambient * gl_LightSource[lightIndex].ambient.xyz + diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * d + gl_LightSource[lightIndex].quadraticAttenuation * d * d), 0.0, 1.0) * shadowing; + ambientOut = lightAmbient(lightIndex, ambient) * illumination; + diffuseOut = lightDiffuse(lightIndex, diffuse, viewNormal, lightDir) * illumination; } #ifdef FRAGMENT vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) #else -vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) +vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) #endif { #if @colorMode == 3 @@ -30,14 +42,18 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) #endif vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); + vec3 diffuseLight, ambientLight; + perLight(ambientLight, diffuseLight, 0, viewPos, viewNormal, diffuse, ambient); #ifdef FRAGMENT - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, shadowing); + lightResult.xyz += ambientLight + diffuseLight * shadowing; #else - lightResult.xyz += perLight(0, viewPos, viewNormal, diffuse, ambient, 1.0); + shadowDiffuse = diffuseLight; + lightResult.xyz += ambientLight; #endif for (int i=1; i Date: Thu, 21 Sep 2017 02:03:53 +0100 Subject: [PATCH 007/168] Tidy up the mess I made of lighting.glsl a bit by removing two single-line functions that are only ever called in one location. --- files/shaders/lighting.glsl | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index fe298e160..afa636e3c 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,15 +1,5 @@ #define MAX_LIGHTS 8 -vec3 lightAmbient(int lightIndex, vec3 ambient) -{ - return ambient * gl_LightSource[lightIndex].ambient.xyz; -} - -vec3 lightDiffuse(int lightIndex, vec4 diffuse, vec3 viewNormal, vec3 lightDir) -{ - return diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0); -} - void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; @@ -20,8 +10,8 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie lightDir = normalize(lightDir); float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); - ambientOut = lightAmbient(lightIndex, ambient) * illumination; - diffuseOut = lightDiffuse(lightIndex, diffuse, viewNormal, lightDir) * illumination; + ambientOut = ambient * gl_LightSource[lightIndex].ambient.xyz * illumination; + diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; } #ifdef FRAGMENT From ebd3dcf2b34e7626550bd608830fa831b78e5e14 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 3 Oct 2017 02:58:25 +0100 Subject: [PATCH 008/168] Remove unnecessary preprocessor variable in shaders --- files/shaders/lighting.glsl | 2 +- files/shaders/objects_fragment.glsl | 2 -- files/shaders/terrain_fragment.glsl | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index afa636e3c..8678d18dd 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -14,7 +14,7 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; } -#ifdef FRAGMENT +#ifdef PER_PIXEL_LIGHTING vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) #else vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index f90e5f8ba..b3bfa600b 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define FRAGMENT - #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 2e61caeb0..9da9dfad5 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define FRAGMENT - varying vec2 uv; uniform sampler2D diffuseMap; From 0568c93b39d2b08713caa327021938994213a016 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 3 Oct 2017 03:40:23 +0100 Subject: [PATCH 009/168] Add specific shadow source files to MWRender --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++----- apps/openmw/mwrender/shadow.cpp | 11 +++++++++ apps/openmw/mwrender/shadow.hpp | 27 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 apps/openmw/mwrender/shadow.cpp create mode 100644 apps/openmw/mwrender/shadow.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 47a30f9a0..97744d4dd 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,6 +24,7 @@ add_openmw_dir (mwrender creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation renderbin actoranimation landmanager + shadow ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 04c3355ca..e670eaebc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -14,11 +14,6 @@ #include #include -#include -#include -#include -#include -#include #include #include @@ -57,6 +52,7 @@ #include "water.hpp" #include "terrainstorage.hpp" #include "util.hpp" +#include "shadow.hpp" namespace MWRender { @@ -228,7 +224,7 @@ namespace MWRender int mapres = 2048; settings->setTextureSize(osg::Vec2s(mapres,mapres)); - osgShadow::MinimalShadowMap* tech = new osgShadow::LightSpacePerspectiveShadowMapDB(); + MWShadow* tech = new MWShadow(); shadowedScene->setShadowTechnique(tech); tech->setMaxFarPlane(0); diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp new file mode 100644 index 000000000..17cc5156b --- /dev/null +++ b/apps/openmw/mwrender/shadow.cpp @@ -0,0 +1,11 @@ +#include "shadow.hpp" + +namespace MWRender +{ + void MWShadow::ViewData::init(MWShadow * st, osgUtil::CullVisitor * cv) + { + LightSpacePerspectiveShadowMapDB::ViewData::init(st, cv); + osg::StateSet * stateset = _camera->getOrCreateStateSet(); + stateset->removeAttribute(osg::StateAttribute::CULLFACE); + } +} diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp new file mode 100644 index 000000000..51338c5bf --- /dev/null +++ b/apps/openmw/mwrender/shadow.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_MWRENDER_SHADOW_H +#define OPENMW_MWRENDER_SHADOW_H + +#include + +namespace MWRender +{ + class MWShadow : public osgShadow::LightSpacePerspectiveShadowMapDB + { + protected: + struct ViewData : public LightSpacePerspectiveShadowMapDB::ViewData + { + virtual void init(MWShadow * st, osgUtil::CullVisitor * cv); + }; + + virtual ViewDependentShadowTechnique::ViewData * initViewDependentData(osgUtil::CullVisitor *cv, ViewDependentShadowTechnique::ViewData * vd) + { + MWShadow::ViewData* td = dynamic_cast(vd); + if (!td) + td = new MWShadow::ViewData; + td->init(this, cv); + return td; + } + }; +} + +#endif //OPENMW_MWRENDER_SHADOW_H From 2b78fb436d3f5c47c961c9a46780464219cf7f6b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 8 Oct 2017 00:44:35 +0100 Subject: [PATCH 010/168] Fix issue with shader preprocessor variables --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 8678d18dd..5d59754ec 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -14,7 +14,7 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; } -#ifdef PER_PIXEL_LIGHTING +#if PER_PIXEL_LIGHTING vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing) #else vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) From e0ce28427213177c87b092646592ffc32dbef578 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 8 Oct 2017 01:34:54 +0100 Subject: [PATCH 011/168] Fix the same shader preprocessor variable issue for the third time now --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 5d59754ec..09b78b596 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -34,7 +34,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow vec3 diffuseLight, ambientLight; perLight(ambientLight, diffuseLight, 0, viewPos, viewNormal, diffuse, ambient); -#ifdef FRAGMENT +#if PER_PIXEL_LIGHTING lightResult.xyz += ambientLight + diffuseLight * shadowing; #else shadowDiffuse = diffuseLight; From c2cd3380862bb3819e288c94d0e1ae6ca96762a9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 13 Oct 2017 18:05:25 +0100 Subject: [PATCH 012/168] Add shadow DLL under Windows automatically --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 11317a33f..8c73bf78d 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -557,7 +557,7 @@ printf "OSG 3.4.0-scrawl... " "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll echo Done. } From 20607bdcd98f7fff60a93084a6d90ab83c884595 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 13 Oct 2017 18:17:49 +0100 Subject: [PATCH 013/168] Actually add shadow DLL under Windows automatically for real this time --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 8c73bf78d..3895a0a96 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -554,7 +554,7 @@ printf "OSG 3.4.0-scrawl... " fi add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ - "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll + "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer,Shadow}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll From 26a7b48d692c27baf353bd748fb6db40348184cb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 20:47:19 +0100 Subject: [PATCH 014/168] Attempt to make a VDSM work, and also to set up a debug HUD, but without success. --- apps/openmw/mwrender/renderingmanager.cpp | 6 +- apps/openmw/mwrender/shadow.cpp | 698 +++++++++++++++++++++- apps/openmw/mwrender/shadow.hpp | 26 +- files/shaders/objects_fragment.glsl | 4 +- files/shaders/terrain_fragment.glsl | 4 +- 5 files changed, 713 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e670eaebc..172ff34a8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,7 +210,7 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - //settings->setBaseShadowTextureUnit(1); + settings->setBaseShadowTextureUnit(1); //settings->setMinimumShadowMapNearFarRatio(0); //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); @@ -227,12 +227,12 @@ namespace MWRender MWShadow* tech = new MWShadow(); shadowedScene->setShadowTechnique(tech); - tech->setMaxFarPlane(0); + /*tech->setMaxFarPlane(0); tech->setTextureSize(osg::Vec2s(mapres, mapres)); tech->setShadowTextureCoordIndex(1); tech->setShadowTextureUnit(1); tech->setBaseTextureCoordIndex(0); - tech->setBaseTextureUnit(0); + tech->setBaseTextureUnit(0);*/ //mRootNode->addChild(sceneRoot); shadowedScene->addChild(sceneRoot); diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 17cc5156b..c58334a51 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -1,11 +1,701 @@ #include "shadow.hpp" +#include +#include +#include +#include +#include +#include + namespace MWRender { - void MWShadow::ViewData::init(MWShadow * st, osgUtil::CullVisitor * cv) + using namespace osgShadow; + + std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; + std::string debugFragmentShaderSource = + "uniform sampler2D texture; \n" + " \n" + "void main(void) \n" + "{ \n" +#if 0 + " float f = texture2D( texture, gl_TexCoord[0] ).r; \n" + " \n" + " f = 256.0 * f; \n" + " float fC = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fS = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fH = floor( f ) / 256.0; \n" + " \n" + " fS *= 0.5; \n" + " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" + " \n" + " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" + " abs( fC - 0.333333 ), \n" + " abs( fC - 0.666667 ) ); \n" + " \n" + " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" + " \n" + " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" + " fMax = 1.0 / fMax; \n" + " \n" + " vec3 color = fMax * rgb; \n" + " \n" + " gl_FragColor = vec4( fS + fH * color, 1 ); \n" +#else + " gl_FragColor = texture2D(texture, gl_TexCoord[0]); \n" + " //gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0); \n" +#endif + "} \n"; + + + MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), testTex(new osg::Texture2D) + { + debugCamera->setViewport(0, 0, 200, 200); + debugCamera->setRenderOrder(osg::Camera::POST_RENDER); + debugCamera->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); + debugProgram->addShader(vertexShader); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); + debugProgram->addShader(fragmentShader); + + debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0));- + debugCamera->addChild(debugGeometry); + osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); + stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", 0); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + + testTex->setDataVariance(osg::Object::DYNAMIC); + osg::ref_ptr testImage = osgDB::readRefImageFile("path/to/an/image/file.png"); + testTex->setImage(testImage); + } + + class VDSMCameraCullCallback : public osg::NodeCallback + { + public: + + VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); + + virtual void operator()(osg::Node*, osg::NodeVisitor* nv); + + osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); } + osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); } + + protected: + + ViewDependentShadowMap* _vdsm; + osg::ref_ptr _projectionMatrix; + osg::ref_ptr _renderStage; + osg::Polytope _polytope; + }; + + VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope) : + _vdsm(vdsm), + _polytope(polytope) + { + } + + void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = dynamic_cast(nv); + osg::Camera* camera = dynamic_cast(node); + OSG_INFO << "VDSMCameraCullCallback::operator()(osg::Node* " << camera << ", osg::NodeVisitor* " << cv << ")" << std::endl; + +#if 1 + if (!_polytope.empty()) + { + OSG_INFO << "Pushing custom Polytope" << std::endl; + + osg::CullingSet& cs = cv->getProjectionCullingStack().back(); + + cs.setFrustum(_polytope); + + cv->pushCullingSet(); + } +#endif + if (_vdsm->getShadowedScene()) + { + _vdsm->getShadowedScene()->osg::Group::traverse(*nv); + } +#if 1 + if (!_polytope.empty()) + { + OSG_INFO << "Popping custom Polytope" << std::endl; + cv->popCullingSet(); + } +#endif + + _renderStage = cv->getCurrentRenderBin()->getStage(); + + OSG_INFO << "VDSM second : _renderStage = " << _renderStage << std::endl; + + if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + // make sure that the near plane is computed correctly. + cv->computeNearPlane(); + + osg::Matrixd projection = *(cv->getProjectionMatrix()); + + OSG_INFO << "RTT Projection matrix " << projection << std::endl; + + osg::Matrix::value_type left, right, bottom, top, zNear, zFar; + osg::Matrix::value_type epsilon = 1e-6; + if (fabs(projection(0, 3))setProjectionMatrix(projection); + + _projectionMatrix = cv->getProjectionMatrix(); + } + } + + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { - LightSpacePerspectiveShadowMapDB::ViewData::init(st, cv); - osg::StateSet * stateset = _camera->getOrCreateStateSet(); - stateset->removeAttribute(osg::StateAttribute::CULLFACE); + public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + { + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + } + + void apply(osg::Node& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Geode& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + for (unsigned int i = 0; igetBoundingBox()); + } + } + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Billboard&) + { + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; + } + + void apply(osg::Projection&) + { + // projection nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void apply(osg::Transform& transform) + { + if (isCulled(transform)) return; + + // push the culling mode. + pushCurrentMask(); + + // absolute transforms won't affect a shadow map so their subgraphs should be ignored. + if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) + { + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); + + traverse(transform); + + popModelViewMatrix(); + } + + // pop the culling mode. + popCurrentMask(); + + } + + void apply(osg::Camera&) + { + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void updateBound(const osg::BoundingBox& bb) + { + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); + } + + void update(const osg::Vec3& v) + { + if (v.z()<-1.0f) + { + //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; + float y = v.y(); + if (y<-1.0f) y = -1.0f; + if (y>1.0f) y = 1.0f; + _bb.expandBy(osg::Vec3(x, y, v.z())); + } + + osg::BoundingBox _bb; + }; + + void MWShadow::cull(osgUtil::CullVisitor& cv) + { + OSG_INFO << std::endl << std::endl << "ViewDependentShadowMap::cull(osg::CullVisitor&" << &cv << ")" << std::endl; + + if (!_shadowCastingStateSet) + { + OSG_INFO << "Warning, init() has not yet been called so ShadowCastingStateSet has not been setup yet, unable to create shadows." << std::endl; + _shadowedScene->osg::Group::traverse(cv); + return; + } + + ViewDependentData* vdd = getViewDependentData(&cv); + + if (!vdd) + { + OSG_INFO << "Warning, now ViewDependentData created, unable to create shadows." << std::endl; + _shadowedScene->osg::Group::traverse(cv); + return; + } + + ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + OSG_INFO << "cv->getProjectionMatrix()=" << *cv.getProjectionMatrix() << std::endl; + + osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode(); + + osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix(); + + // check whether this main views projection is perspective or orthographic + bool orthographicViewFrustum = viewProjectionMatrix(0, 3) == 0.0 && + viewProjectionMatrix(1, 3) == 0.0 && + viewProjectionMatrix(2, 3) == 0.0; + + double minZNear = 0.0; + double maxZFar = DBL_MAX; + + if (cachedNearFarMode == osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + double left, right, top, bottom; + if (orthographicViewFrustum) + { + viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar); + } + else + { + viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar); + } + OSG_INFO << "minZNear=" << minZNear << ", maxZFar=" << maxZFar << std::endl; + } + + // set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible + if (settings->getComputeNearFarModeOverride() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride()); + } + + // 1. Traverse main scene graph + cv.pushStateSet(_shadowRecievingPlaceholderStateSet.get()); + + osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); + + cullShadowReceivingScene(&cv); + + cv.popStateSet(); + + if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + OSG_INFO << "Just done main subgraph traversak" << std::endl; + // make sure that the near plane is computed correctly so that any projection matrix computations + // are all done correctly. + cv.computeNearPlane(); + } + + // clamp the minZNear and maxZFar to those provided by ShadowSettings + maxZFar = osg::minimum(settings->getMaximumShadowMapDistance(), maxZFar); + if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); + + //OSG_NOTICE<<"maxZFar "<getLightDataList(); + for (LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = **itr; + + // 3.1 compute light space polytope + // + osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); + + // if polytope is empty then no rendering. + if (polytope.empty()) + { + OSG_NOTICE << "Polytope empty no shadow to render" << std::endl; + continue; + } + + // 3.2 compute RTT camera view+projection matrix settings + // + osg::Matrixd projectionMatrix; + osg::Matrixd viewMatrix; + if (!computeShadowCameraSettings(frustum, pl, projectionMatrix, viewMatrix)) + { + OSG_NOTICE << "No valid Camera settings, no shadow to render" << std::endl; + continue; + } + + // if we are using multiple shadow maps and CastShadowTraversalMask is being used + // traverse the scene to compute the extents of the objects + if (/*numShadowMapsPerLight>1 &&*/ _shadowedScene->getCastsShadowTraversalMask() != 0xffffffff) + { + // osg::ElapsedTime timer; + + osg::ref_ptr viewport = new osg::Viewport(0, 0, 2048, 2048); + ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); + clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); + + osg::Matrixd invertModelView; + invertModelView.invert(viewMatrix); + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); + cs.setFrustum(local_polytope); + clsb.pushCullingSet(); + + _shadowedScene->accept(clsb); + + // OSG_NOTICE<<"Extents of LightSpace "< texture = sd->_texture; + osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); + if (false) + stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + else + stateSet->setTextureAttributeAndModes(0, testTex, osg::StateAttribute::ON); + + unsigned int traversalMask = cv.getTraversalMask(); + cv.setTraversalMask(debugGeometry->getNodeMask()); + cv.pushStateSet(stateSet); + debugCamera->accept(cv); + cv.popStateSet(); + cv.setTraversalMask(traversalMask); + + cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); + } + + osg::ref_ptr camera = sd->_camera; + + camera->setProjectionMatrix(projectionMatrix); + camera->setViewMatrix(viewMatrix); + + if (settings->getDebugDraw()) + { + camera->getViewport()->x() = pos_x; + pos_x += static_cast(camera->getViewport()->width()) + 40; + } + + // transform polytope in model coords into light spaces eye coords. + osg::Matrixd invertModelView; + invertModelView.invert(camera->getViewMatrix()); + + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + + if (numShadowMapsPerLight>1) + { + // compute the start and end range in non-dimensional coords +#if 0 + double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); + double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); +#endif + + // hardwired for 2 splits + double r_start = (sm_i == 0) ? -1.0 : splitPoint; + double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; + + // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap + // to prevent a seam showing through between the shadowmaps + if (sm_i + 10) + { + // not the first shadowmap so insert a polytope to clip the scene from before r_start + + // plane in clip space coords + osg::Plane plane(0.0, 1.0, 0.0, -r_start); + + // transform into eye coords + plane.transformProvidingInverse(projectionMatrix); + local_polytope.getPlaneList().push_back(plane); + + //OSG_NOTICE<<"Adding r_start plane "<0) + { + decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); + } + + // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< +#include namespace MWRender { - class MWShadow : public osgShadow::LightSpacePerspectiveShadowMapDB + class MWShadow : public osgShadow::ViewDependentShadowMap { + public: + MWShadow(); + + virtual void cull(osgUtil::CullVisitor& cv); protected: - struct ViewData : public LightSpacePerspectiveShadowMapDB::ViewData - { - virtual void init(MWShadow * st, osgUtil::CullVisitor * cv); - }; + osg::ref_ptr debugCamera; + + osg::ref_ptr debugProgram; + + osg::ref_ptr debugGeometry; - virtual ViewDependentShadowTechnique::ViewData * initViewDependentData(osgUtil::CullVisitor *cv, ViewDependentShadowTechnique::ViewData * vd) - { - MWShadow::ViewData* td = dynamic_cast(vd); - if (!td) - td = new MWShadow::ViewData; - td->init(this, cv); - return td; - } + osg::ref_ptr testTex; }; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index b3bfa600b..4dd282dc4 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -55,7 +55,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture; +uniform sampler2DShadow shadowTexture0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -116,7 +116,7 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = shadow2DProj(shadowTexture, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 9da9dfad5..e27dd384e 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -25,7 +25,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture; +uniform sampler2DShadow shadowTexture0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -68,7 +68,7 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = shadow2DProj(shadowTexture, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); From be50ed738728d6e884013be19f35039cf9036e29 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 13 Oct 2017 18:27:32 +0100 Subject: [PATCH 015/168] Use a test image guaranteed to exist. --- apps/openmw/mwrender/shadow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index c58334a51..65ce8d5bd 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -71,7 +71,7 @@ namespace MWRender stateSet->addUniform(textureUniform.get()); testTex->setDataVariance(osg::Object::DYNAMIC); - osg::ref_ptr testImage = osgDB::readRefImageFile("path/to/an/image/file.png"); + osg::ref_ptr testImage = osgDB::readRefImageFile("resources/mygui/openmw.png"); testTex->setImage(testImage); } From 737563875ab4929c902327310e04ad77b9e056f0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 14 Oct 2017 01:13:45 +0100 Subject: [PATCH 016/168] Remove superfluous - sign and switch to other debug shader --- apps/openmw/mwrender/shadow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 65ce8d5bd..2f57f6e06 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -17,7 +17,7 @@ namespace MWRender " \n" "void main(void) \n" "{ \n" -#if 0 +#if 1 " float f = texture2D( texture, gl_TexCoord[0] ).r; \n" " \n" " f = 256.0 * f; \n" @@ -62,7 +62,7 @@ namespace MWRender osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); debugProgram->addShader(fragmentShader); - debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0));- + debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0)); debugCamera->addChild(debugGeometry); osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); From cf54b4a13044a397098ae0382b29589870f07bad Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 26 Oct 2017 20:38:36 +0100 Subject: [PATCH 017/168] Prevent debug HUD geometry from being culled erroneously. --- apps/openmw/mwrender/shadow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 2f57f6e06..b8600e211 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -63,6 +63,7 @@ namespace MWRender debugProgram->addShader(fragmentShader); debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0)); + debugGeometry->setCullingActive(false); debugCamera->addChild(debugGeometry); osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); From ab669a434efb3f9c42667f60bcdac68ccb151a49 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 30 Oct 2017 19:54:54 +0000 Subject: [PATCH 018/168] Update the shadow frustrum bounds properly --- apps/openmw/mwrender/shadow.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index b8600e211..089a4da3d 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -227,6 +227,19 @@ namespace MWRender popCurrentMask(); } + void apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); + } + void apply(osg::Billboard&) { OSG_INFO << "Warning Billboards not yet supported" << std::endl; @@ -547,7 +560,7 @@ namespace MWRender { osg::ref_ptr texture = sd->_texture; osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); - if (false) + if (true) stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); else stateSet->setTextureAttributeAndModes(0, testTex, osg::StateAttribute::ON); From e15d4619210478e8331472cfa784923476d200be Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 30 Oct 2017 20:06:52 +0000 Subject: [PATCH 019/168] Add (potentially physically-flawed) shadow support to the water shader --- files/shaders/water_fragment.glsl | 5 ++++- files/shaders/water_vertex.glsl | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 931422d5e..f04a9d8a8 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -142,6 +142,9 @@ uniform vec3 nodePosition; uniform float rainIntensity; +uniform sampler2DShadow shadowTexture0; +varying vec4 shadowSpaceCoords; + float frustumDepth; float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value @@ -158,7 +161,7 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - float shadow = 1.0; + float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 7d7b7b18a..513edc730 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,6 +4,8 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +varying vec4 shadowSpaceCoords; + void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; @@ -19,4 +21,8 @@ void main(void) position = gl_Vertex; depthPassthrough = gl_Position.z; + + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + shadowSpaceCoords = (gl_ModelViewMatrix * gl_Vertex) * eyePlaneMat; } From d0866d1b3ce7604a7b6590dbc3d198430d867bfa Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 31 Oct 2017 20:21:54 +0100 Subject: [PATCH 020/168] Revert change to node mask that appears to not serve any purpose --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e871e1cfc..3c4c1101f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -268,7 +268,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; - //source->setNodeMask(Mask_Lighting); + source->setNodeMask(Mask_Lighting); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -315,8 +315,7 @@ namespace MWRender mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); mViewer->getCamera()->setCullingMode(cullingMode); - //mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); - mViewer->getCamera()->setCullMask(~(Mask_Lighting)); + mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); From 8141ee47d59a9c951851586b3e6d73d56d3e6359 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 31 Oct 2017 20:22:14 +0100 Subject: [PATCH 021/168] Fix shader compile error --- apps/openmw/mwrender/shadow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 089a4da3d..915979bac 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -18,7 +18,7 @@ namespace MWRender "void main(void) \n" "{ \n" #if 1 - " float f = texture2D( texture, gl_TexCoord[0] ).r; \n" + " float f = texture2D( texture, gl_TexCoord[0].xy ).r; \n" " \n" " f = 256.0 * f; \n" " float fC = floor( f ) / 256.0; \n" @@ -45,7 +45,7 @@ namespace MWRender " \n" " gl_FragColor = vec4( fS + fH * color, 1 ); \n" #else - " gl_FragColor = texture2D(texture, gl_TexCoord[0]); \n" + " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" " //gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0); \n" #endif "} \n"; From ceaf0ee4092982075ea035238e46fc8d573bc64a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 31 Oct 2017 21:21:05 +0100 Subject: [PATCH 022/168] Enable shadow casting for terrain Add a check to TerrainDrawable to make sure shadows are only drawn once, not once per blending pass --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/terrain/terraindrawable.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3c4c1101f..cdf4ed16a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -206,7 +206,7 @@ namespace MWRender osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings(); settings->setLightNum(0); - settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player); + settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player|Mask_Terrain); settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); diff --git a/components/terrain/terraindrawable.cpp b/components/terrain/terraindrawable.cpp index f3080e31c..60d591707 100644 --- a/components/terrain/terraindrawable.cpp +++ b/components/terrain/terraindrawable.cpp @@ -51,6 +51,12 @@ void TerrainDrawable::cull(osgUtil::CullVisitor *cv) if (osg::isNaN(depth)) return; + if (cv->getCurrentCamera()->getName() == "ShadowCamera") + { + cv->addDrawableAndDepth(this, &matrix, depth); + return; + } + bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv); for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it) From ce0e937e8d2c654ad3280604024d619e443785a1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 1 Nov 2017 18:22:59 +0000 Subject: [PATCH 023/168] Attempt to force the sky to not accept the default shadow shader or shadow texture. --- apps/openmw/mwrender/sky.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 6c599fc3f..4256f6987 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1122,7 +1122,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana skyroot->setName("Sky Root"); // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need - skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE); + skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); + skyroot->getOrCreateStateSet()->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); From d0587a3ad5c922d97cea5544c710181d662802c8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 3 Nov 2017 14:33:06 +0000 Subject: [PATCH 024/168] Clean up the debug hud now it's working. --- apps/openmw/mwrender/shadow.cpp | 13 +++---------- apps/openmw/mwrender/shadow.hpp | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 915979bac..347952b4c 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -51,7 +51,7 @@ namespace MWRender "} \n"; - MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), testTex(new osg::Texture2D) + MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), debugTextureUnit(0) { debugCamera->setViewport(0, 0, 200, 200); debugCamera->setRenderOrder(osg::Camera::POST_RENDER); @@ -67,13 +67,9 @@ namespace MWRender debugCamera->addChild(debugGeometry); osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", 0); + osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); //textureUniform->setType(osg::Uniform::SAMPLER_2D); stateSet->addUniform(textureUniform.get()); - - testTex->setDataVariance(osg::Object::DYNAMIC); - osg::ref_ptr testImage = osgDB::readRefImageFile("resources/mygui/openmw.png"); - testTex->setImage(testImage); } class VDSMCameraCullCallback : public osg::NodeCallback @@ -560,10 +556,7 @@ namespace MWRender { osg::ref_ptr texture = sd->_texture; osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); - if (true) - stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - else - stateSet->setTextureAttributeAndModes(0, testTex, osg::StateAttribute::ON); + stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); unsigned int traversalMask = cv.getTraversalMask(); cv.setTraversalMask(debugGeometry->getNodeMask()); diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index 4a4e8b8a5..a941f9c2e 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -12,13 +12,13 @@ namespace MWRender virtual void cull(osgUtil::CullVisitor& cv); protected: + const int debugTextureUnit; + osg::ref_ptr debugCamera; osg::ref_ptr debugProgram; osg::ref_ptr debugGeometry; - - osg::ref_ptr testTex; }; } From 3f63ebce77c3c300d725b0954a4e137147365c2b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 5 Nov 2017 14:37:36 +0000 Subject: [PATCH 025/168] Theoretically, at least, fix everything (except hte sky issue which is resolved in another branch) --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- files/shaders/objects_vertex.glsl | 3 ++- files/shaders/terrain_vertex.glsl | 3 ++- files/shaders/water_vertex.glsl | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cdf4ed16a..aa5240618 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,7 +210,7 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(1); + settings->setBaseShadowTextureUnit(7); //settings->setMinimumShadowMapNearFarRatio(0); //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 42949dccb..4046386dd 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -46,6 +46,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; +uniform int shadowTextureUnit0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -104,6 +105,6 @@ void main(void) passNormal = gl_Normal.xyz; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); shadowSpaceCoords = viewPos * eyePlaneMat; } diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 89a2307a1..17a9c436e 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -14,6 +14,7 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; +uniform int shadowTextureUnit0; varying vec4 shadowSpaceCoords; #include "lighting.glsl" @@ -38,6 +39,6 @@ void main(void) uv = gl_MultiTexCoord0.xy; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); shadowSpaceCoords = viewPos * eyePlaneMat; } diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 513edc730..6aaa0537c 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,6 +4,7 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +uniform int shadowTextureUnit0; varying vec4 shadowSpaceCoords; void main(void) @@ -23,6 +24,6 @@ void main(void) depthPassthrough = gl_Position.z; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[1], gl_EyePlaneT[1], gl_EyePlaneR[1], gl_EyePlaneQ[1]); + mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); shadowSpaceCoords = (gl_ModelViewMatrix * gl_Vertex) * eyePlaneMat; } From 7a03ad65584451a63b5db47885d4265bebd6ae89 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 5 Nov 2017 14:46:03 +0000 Subject: [PATCH 026/168] Switch to a tidier way of disabling the correct texture unit --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/shadow.hpp | 2 ++ apps/openmw/mwrender/sky.cpp | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa5240618..bdabdaeab 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,7 +210,7 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(7); + settings->setBaseShadowTextureUnit(MWShadow::baseShadowTextureUnit); //settings->setMinimumShadowMapNearFarRatio(0); //settings->setNumShadowMapsPerLight(1); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index a941f9c2e..4e1725c7f 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -10,6 +10,8 @@ namespace MWRender public: MWShadow(); + const static int baseShadowTextureUnit = 7; + virtual void cull(osgUtil::CullVisitor& cv); protected: const int debugTextureUnit; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4256f6987..9f4542ae9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -48,6 +48,7 @@ #include "vismask.hpp" #include "renderbin.hpp" +#include "shadow.hpp" namespace { @@ -1123,7 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - skyroot->getOrCreateStateSet()->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); + skyroot->getOrCreateStateSet()->setTextureMode(MWShadow::baseShadowTextureUnit, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); From 56fa33af66183d79275cea742b0e6dcf743981ae Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 00:32:04 +0000 Subject: [PATCH 027/168] Enable parallel split shadow maps --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++-- apps/openmw/mwrender/shadow.cpp | 40 +++++++++++++---------- apps/openmw/mwrender/shadow.hpp | 7 ++-- files/shaders/objects_fragment.glsl | 7 ++-- files/shaders/objects_vertex.glsl | 8 +++-- files/shaders/terrain_fragment.glsl | 7 ++-- files/shaders/terrain_vertex.glsl | 8 +++-- files/shaders/water_fragment.glsl | 7 ++-- files/shaders/water_vertex.glsl | 9 +++-- 9 files changed, 65 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa5240618..645c10667 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -210,13 +210,13 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(7); + settings->setBaseShadowTextureUnit(8 - MWShadow::numberOfShadowMapsPerLight); //settings->setMinimumShadowMapNearFarRatio(0); - //settings->setNumShadowMapsPerLight(1); + settings->setNumShadowMapsPerLight(MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); - //settings->setDebugDraw(true); + //settings->setDebugDraw(true); // don't turn this on because it makes everything break //settings->setPerspectiveShadowMapCutOffAngle(0); //settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 347952b4c..40b2ff311 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -51,25 +51,31 @@ namespace MWRender "} \n"; - MWShadow::MWShadow() : debugCamera(new osg::Camera), debugProgram(new osg::Program), debugTextureUnit(0) + MWShadow::MWShadow() : debugProgram(new osg::Program), debugTextureUnit(0) { - debugCamera->setViewport(0, 0, 200, 200); - debugCamera->setRenderOrder(osg::Camera::POST_RENDER); - debugCamera->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); debugProgram->addShader(vertexShader); osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); debugProgram->addShader(fragmentShader); - debugGeometry = osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0)); - debugGeometry->setCullingActive(false); - debugCamera->addChild(debugGeometry); - osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); - stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + { + std::cout << i << std::endl; + + debugCameras.push_back(new osg::Camera); + debugCameras[i]->setViewport(200 * i, 0, 200, 200); + debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); + debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + debugGeometry[i]->setCullingActive(false); + debugCameras[i]->addChild(debugGeometry[i]); + osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + } } class VDSMCameraCullCallback : public osg::NodeCallback @@ -552,16 +558,16 @@ namespace MWRender previous_sdl.erase(previous_sdl.begin()); } - if (true) + if (debugHud) { osg::ref_ptr texture = sd->_texture; - osg::ref_ptr stateSet = debugGeometry->getOrCreateStateSet(); + osg::ref_ptr stateSet = debugGeometry[sm_i]->getOrCreateStateSet(); stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); unsigned int traversalMask = cv.getTraversalMask(); - cv.setTraversalMask(debugGeometry->getNodeMask()); + cv.setTraversalMask(debugGeometry[sm_i]->getNodeMask()); cv.pushStateSet(stateSet); - debugCamera->accept(cv); + debugCameras[sm_i]->accept(cv); cv.popStateSet(); cv.setTraversalMask(traversalMask); diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index a941f9c2e..e7663c55a 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -8,17 +8,20 @@ namespace MWRender class MWShadow : public osgShadow::ViewDependentShadowMap { public: + static const int numberOfShadowMapsPerLight = 2; + static const bool debugHud = true; + MWShadow(); virtual void cull(osgUtil::CullVisitor& cv); protected: const int debugTextureUnit; - osg::ref_ptr debugCamera; + std::vector> debugCameras; osg::ref_ptr debugProgram; - osg::ref_ptr debugGeometry; + std::vector> debugGeometry; }; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 4dd282dc4..f6355aaa6 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -56,7 +56,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform sampler2DShadow shadowTexture0; -varying vec4 shadowSpaceCoords; +uniform sampler2DShadow shadowTexture1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" #include "parallax.glsl" @@ -116,7 +118,8 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; + shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 4046386dd..b90a8722b 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -47,7 +47,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform int shadowTextureUnit0; -varying vec4 shadowSpaceCoords; +uniform int shadowTextureUnit1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" @@ -106,5 +108,7 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords = viewPos * eyePlaneMat; + shadowSpaceCoords0 = viewPos * eyePlaneMat; + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); + shadowSpaceCoords1 = viewPos * eyePlaneMat; } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e27dd384e..e79adaafb 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -26,7 +26,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform sampler2DShadow shadowTexture0; -varying vec4 shadowSpaceCoords; +uniform sampler2DShadow shadowTexture1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" #include "parallax.glsl" @@ -68,7 +70,8 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; + float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; + shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 17a9c436e..015039252 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -15,7 +15,9 @@ varying vec3 passViewPos; varying vec3 passNormal; uniform int shadowTextureUnit0; -varying vec4 shadowSpaceCoords; +uniform int shadowTextureUnit1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; #include "lighting.glsl" @@ -40,5 +42,7 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords = viewPos * eyePlaneMat; + shadowSpaceCoords0 = viewPos * eyePlaneMat; + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); + shadowSpaceCoords1 = viewPos * eyePlaneMat; } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index f04a9d8a8..3529b7347 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -143,7 +143,9 @@ uniform vec3 nodePosition; uniform float rainIntensity; uniform sampler2DShadow shadowTexture0; -varying vec4 shadowSpaceCoords; +uniform sampler2DShadow shadowTexture1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; float frustumDepth; @@ -161,7 +163,8 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords).r; + float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; + shadow *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 6aaa0537c..0c280fb7e 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -5,7 +5,9 @@ varying vec4 position; varying float depthPassthrough; uniform int shadowTextureUnit0; -varying vec4 shadowSpaceCoords; +uniform int shadowTextureUnit1; +varying vec4 shadowSpaceCoords0; +varying vec4 shadowSpaceCoords1; void main(void) { @@ -23,7 +25,10 @@ void main(void) depthPassthrough = gl_Position.z; + vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords = (gl_ModelViewMatrix * gl_Vertex) * eyePlaneMat; + shadowSpaceCoords0 = viewPos * eyePlaneMat; + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); + shadowSpaceCoords1 = viewPos * eyePlaneMat; } From 3106159721239e59cf9d2229dd62bd792554c33f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 16:40:32 +0000 Subject: [PATCH 028/168] Turn off all shadow texture units for the sky now it is possible for there to be more than one --- apps/openmw/mwrender/sky.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 9f4542ae9..8eec3f30b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1124,7 +1124,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - skyroot->getOrCreateStateSet()->setTextureMode(MWShadow::baseShadowTextureUnit, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); + for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + skyroot->getOrCreateStateSet()->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); From 715f29165ba385a62177ae92fbe4f5cf526bfae1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 20:22:45 +0000 Subject: [PATCH 029/168] Dynamically adjust shaders to have the required number of shadow maps. --- components/shader/shadermanager.cpp | 37 +++++++++++++++++++++++++---- components/shader/shadermanager.hpp | 3 ++- files/shaders/objects_fragment.glsl | 16 ++++++++----- files/shaders/objects_vertex.glsl | 18 +++++++------- files/shaders/terrain_fragment.glsl | 16 ++++++++----- files/shaders/terrain_vertex.glsl | 20 +++++++++------- files/shaders/water_fragment.glsl | 21 +++++++++++----- files/shaders/water_vertex.glsl | 24 +++++++++++-------- 8 files changed, 105 insertions(+), 50 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 7cb49c6cb..02488dd42 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -99,10 +99,39 @@ namespace Shader return true; } - osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType) + osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType, bool disableShadows) { OpenThreads::ScopedLock lock(mMutex); + // set up shadows in the shader + // get these values from settings manager + bool shadows = true & !disableShadows; + int numShadowMaps = 2; + DefineMap definesWithShadows; + if (shadows) + { + definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); + + /*definesWithShadows.insert(std::string("shadow_texture_unit_declarations"), std::string("")); + definesWithShadows.insert(std::string("shadow_space_coordinate_declarations"), std::string("")); + definesWithShadows.insert(std::string("shadow_space_coordinate_calculations"), std::string("")); + definesWithShadows.insert(std::string("shadow_texture_sampler_declarations"), std::string("")); + definesWithShadows.insert(std::string("shadow_texture_lookup_calculations"), std::string(""));*/ + for (int i = 0; i < numShadowMaps; ++i) + { + definesWithShadows["shadow_texture_unit_declarations"] += "uniform int shadowTextureUnit" + std::to_string(i) + ";\n"; + definesWithShadows["shadow_space_coordinate_declarations"] += "varying vec4 shadowSpaceCoords" + std::to_string(i) + ";\n"; + + definesWithShadows["shadow_space_coordinate_calculations"] += "eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneT[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneR[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneQ[shadowTextureUnit" + std::to_string(i) + "]);\n" + + "shadowSpaceCoords" + std::to_string(i) + " = viewPos * eyePlaneMat;\n"; + + definesWithShadows["shadow_texture_sampler_declarations"] += "uniform sampler2DShadow shadowTexture" + std::to_string(i) + ";\n"; + definesWithShadows["shadow_texture_lookup_calculations"] += "shadowing *= shadow2DProj(shadowTexture" + std::to_string(i) + ", shadowSpaceCoords" + std::to_string(i) + ").r;\n"; + } + } + + definesWithShadows.insert(defines.begin(), defines.end()); + // read the template if we haven't already TemplateMap::iterator templateIt = mShaderTemplates.find(shaderTemplate); if (templateIt == mShaderTemplates.end()) @@ -126,11 +155,11 @@ namespace Shader templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; } - ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, defines)); + ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, definesWithShadows)); if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, defines)) + if (!parseDefines(shaderSource, definesWithShadows)) return NULL; osg::ref_ptr shader (new osg::Shader(shaderType)); @@ -139,7 +168,7 @@ namespace Shader static unsigned int counter = 0; shader->setName(std::to_string(counter++)); - shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), shader)).first; + shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, definesWithShadows), shader)).first; } return shaderIt->second; } diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index bd820a725..17c46f58c 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -26,9 +26,10 @@ namespace Shader /// @param shaderTemplate The filename of the shader template. /// @param defines Define values that can be retrieved by the shader template. /// @param shaderType The type of shader (usually vertex or fragment shader). + /// @param disableShadows Whether to disable shadows in the shader regardless of the overall setting. False by default. /// @note May return NULL on failure. /// @note Thread safe. - osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType); + osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType, bool disableShadows = false); osg::ref_ptr getProgram(osg::ref_ptr vertexShader, osg::ref_ptr fragmentShader); diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index f6355aaa6..7d9372c71 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; @@ -55,10 +57,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture0; -uniform sampler2DShadow shadowTexture1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_sampler_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" #include "parallax.glsl" @@ -118,8 +120,10 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; - shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; + float shadowing = 1.0; +#if SHADOWS + @shadow_texture_lookup_calculations +#endif // SHADOWS #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index b90a8722b..fb612afc8 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -46,10 +48,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform int shadowTextureUnit0; -uniform int shadowTextureUnit1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_unit_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" @@ -106,9 +108,9 @@ void main(void) passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; +#if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords0 = viewPos * eyePlaneMat; - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); - shadowSpaceCoords1 = viewPos * eyePlaneMat; + mat4 eyePlaneMat; + @shadow_space_coordinate_calculations +#endif // SHADOWS } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e79adaafb..e512d7475 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + varying vec2 uv; uniform sampler2D diffuseMap; @@ -25,10 +27,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform sampler2DShadow shadowTexture0; -uniform sampler2DShadow shadowTexture1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_sampler_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" #include "parallax.glsl" @@ -70,8 +72,10 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; - shadowing *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; + float shadowing = 1.0; +#if SHADOWS + @shadow_texture_lookup_calculations +#endif // SHADOWS #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 015039252..692e76cce 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#define SHADOWS @shadows_enabled + varying vec2 uv; varying float depth; @@ -14,10 +16,10 @@ varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -uniform int shadowTextureUnit0; -uniform int shadowTextureUnit1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_unit_declarations + @shadow_space_coordinate_declarations +#endif // SHADOWS #include "lighting.glsl" @@ -40,9 +42,9 @@ void main(void) uv = gl_MultiTexCoord0.xy; - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords0 = viewPos * eyePlaneMat; - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); - shadowSpaceCoords1 = viewPos * eyePlaneMat; + #if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @shadow_space_coordinate_calculations + #endif // SHADOWS } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 3529b7347..586a247a4 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,6 +1,7 @@ #version 120 #define REFRACTION @refraction_enabled +#define SHADOWS @shadows_enabled // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) @@ -142,10 +143,11 @@ uniform vec3 nodePosition; uniform float rainIntensity; -uniform sampler2DShadow shadowTexture0; -uniform sampler2DShadow shadowTexture1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#if SHADOWS + @shadow_texture_sampler_declarations + + @shadow_space_coordinate_declarations +#endif // SHADOWS float frustumDepth; @@ -163,8 +165,15 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - float shadow = shadow2DProj(shadowTexture0, shadowSpaceCoords0).r; - shadow *= shadow2DProj(shadowTexture1, shadowSpaceCoords1).r; + #if SHADOWS + float shadowing = 1.0; + + @shadow_texture_lookup_calculations + + float shadow = shadowing; + #else // NOT SHADOWS + float shadow = 1.0; + #endif // SHADOWS vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 0c280fb7e..6381155d0 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,10 +4,13 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; -uniform int shadowTextureUnit0; -uniform int shadowTextureUnit1; -varying vec4 shadowSpaceCoords0; -varying vec4 shadowSpaceCoords1; +#define SHADOWS @shadows_enabled + +#if SHADOWS + @shadow_texture_unit_declarations + + @shadow_space_coordinate_declarations +#endif // SHADOWS void main(void) { @@ -25,10 +28,11 @@ void main(void) depthPassthrough = gl_Position.z; - vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit0], gl_EyePlaneT[shadowTextureUnit0], gl_EyePlaneR[shadowTextureUnit0], gl_EyePlaneQ[shadowTextureUnit0]); - shadowSpaceCoords0 = viewPos * eyePlaneMat; - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit1], gl_EyePlaneT[shadowTextureUnit1], gl_EyePlaneR[shadowTextureUnit1], gl_EyePlaneQ[shadowTextureUnit1]); - shadowSpaceCoords1 = viewPos * eyePlaneMat; + #if SHADOWS + vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + + @shadow_space_coordinate_calculations + #endif // SHADOWS } From 34032052319b621c776a0427f5348e2b0f51109c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Nov 2017 20:34:48 +0000 Subject: [PATCH 030/168] Use three shadow maps per light --- apps/openmw/mwrender/shadow.cpp | 9 +++++---- apps/openmw/mwrender/shadow.hpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/shadow.cpp b/apps/openmw/mwrender/shadow.cpp index 40b2ff311..9a4e2688a 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/apps/openmw/mwrender/shadow.cpp @@ -420,11 +420,11 @@ namespace MWRender previous_sdl.swap(sdl); unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight(); - if (numShadowMapsPerLight>2) + /*if (numShadowMapsPerLight>2) { OSG_NOTICE << "numShadowMapsPerLight of " << numShadowMapsPerLight << " is greater than maximum supported, falling back to 2." << std::endl; numShadowMapsPerLight = 2; - } + }*/ LightDataList& pll = vdd->getLightDataList(); for (LightDataList::iterator itr = pll.begin(); @@ -596,14 +596,15 @@ namespace MWRender if (numShadowMapsPerLight>1) { // compute the start and end range in non-dimensional coords -#if 0 +#if 1 double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); -#endif +#else // hardwired for 2 splits double r_start = (sm_i == 0) ? -1.0 : splitPoint; double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; +#endif // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap // to prevent a seam showing through between the shadowmaps diff --git a/apps/openmw/mwrender/shadow.hpp b/apps/openmw/mwrender/shadow.hpp index e7663c55a..e8d5b1b51 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/apps/openmw/mwrender/shadow.hpp @@ -8,7 +8,7 @@ namespace MWRender class MWShadow : public osgShadow::ViewDependentShadowMap { public: - static const int numberOfShadowMapsPerLight = 2; + static const int numberOfShadowMapsPerLight = 3; static const bool debugHud = true; MWShadow(); From aa31cbba4ffba8630ce80f8ec25333c81984aa48 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 01:20:52 +0000 Subject: [PATCH 031/168] Attempt (and fail) to make the local map show without unwanted shadow --- apps/openmw/mwrender/localmap.cpp | 8 ++++++++ components/shader/shadermanager.cpp | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b78c4dcd2..4b60a7cf2 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -23,6 +23,7 @@ #include "../mwworld/cellstore.hpp" #include "vismask.hpp" +#include "shadow.hpp" namespace { @@ -201,6 +202,13 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + osg::ref_ptr fakeShadowMapImage = new osg::Image(); + fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); + *(float*)fakeShadowMapImage->data() = -std::numeric_limits::infinity(); // this has been tried both positive and negative + osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + camera->addChild(lightSource); camera->setStateSet(stateset); camera->setViewport(0, 0, mMapResolution, mMapResolution); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 02488dd42..93b0168ae 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -11,6 +11,8 @@ #include #include +#include "apps/openmw/mwrender/shadow.hpp" + namespace Shader { @@ -106,7 +108,7 @@ namespace Shader // set up shadows in the shader // get these values from settings manager bool shadows = true & !disableShadows; - int numShadowMaps = 2; + int numShadowMaps = MWRender::MWShadow::numberOfShadowMapsPerLight; DefineMap definesWithShadows; if (shadows) { From 2e7951c83f552b82d5054b1ce2f5072a2577186d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 01:28:10 +0000 Subject: [PATCH 032/168] Remove unused mask --- apps/openmw/mwrender/vismask.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 1f620b7f7..d52c7c232 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -51,9 +51,7 @@ namespace MWRender Mask_PreCompile = (1<<16), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<17), - - Mask_CastsShadows = (1<<18) + Mask_Lighting = (1<<17) }; } From e201e359a91369b084d67ad9485ec2ad4457c8fe Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 01:44:49 +0000 Subject: [PATCH 033/168] Move Shadow to Components --- apps/openmw/CMakeLists.txt | 1 - apps/openmw/mwrender/localmap.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- apps/openmw/mwrender/sky.cpp | 4 ++-- components/CMakeLists.txt | 2 +- {apps/openmw/mwrender => components/sceneutil}/shadow.cpp | 2 +- {apps/openmw/mwrender => components/sceneutil}/shadow.hpp | 8 ++++---- components/shader/shadermanager.cpp | 4 ++-- 8 files changed, 16 insertions(+), 17 deletions(-) rename {apps/openmw/mwrender => components/sceneutil}/shadow.cpp (99%) rename {apps/openmw/mwrender => components/sceneutil}/shadow.hpp (82%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 97744d4dd..47a30f9a0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,7 +24,6 @@ add_openmw_dir (mwrender creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation renderbin actoranimation landmanager - shadow ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 4b60a7cf2..c7f90bc5f 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "../mwbase/environment.hpp" @@ -23,7 +24,6 @@ #include "../mwworld/cellstore.hpp" #include "vismask.hpp" -#include "shadow.hpp" namespace { @@ -206,7 +206,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); *(float*)fakeShadowMapImage->data() = -std::numeric_limits::infinity(); // this has been tried both positive and negative osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); - for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); camera->addChild(lightSource); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 176d179f4..1b34e433d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,6 @@ #include "water.hpp" #include "terrainstorage.hpp" #include "util.hpp" -#include "shadow.hpp" namespace MWRender { @@ -210,9 +210,9 @@ namespace MWRender settings->setReceivesShadowTraversalMask(~0u); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(MWShadow::baseShadowTextureUnit); + settings->setBaseShadowTextureUnit(SceneUtil::MWShadow::baseShadowTextureUnit); //settings->setMinimumShadowMapNearFarRatio(0); - settings->setNumShadowMapsPerLight(MWShadow::numberOfShadowMapsPerLight); + settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); @@ -224,7 +224,7 @@ namespace MWRender int mapres = 2048; settings->setTextureSize(osg::Vec2s(mapres,mapres)); - MWShadow* tech = new MWShadow(); + SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); shadowedScene->setShadowTechnique(tech); /*tech->setMaxFarPlane(0); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8eec3f30b..331782c7b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -42,13 +42,13 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "vismask.hpp" #include "renderbin.hpp" -#include "shadow.hpp" namespace { @@ -1124,7 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - for (int i = MWShadow::baseShadowTextureUnit; i < MWShadow::baseShadowTextureUnit + MWShadow::numberOfShadowMapsPerLight; ++i) + for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) skyroot->getOrCreateStateSet()->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); skyroot->setNodeMask(Mask_Sky); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a0b426a16..f6af33b25 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -56,7 +56,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer shadow ) add_component_dir (nif diff --git a/apps/openmw/mwrender/shadow.cpp b/components/sceneutil/shadow.cpp similarity index 99% rename from apps/openmw/mwrender/shadow.cpp rename to components/sceneutil/shadow.cpp index 9a4e2688a..e8b267dad 100644 --- a/apps/openmw/mwrender/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -7,7 +7,7 @@ #include #include -namespace MWRender +namespace SceneUtil { using namespace osgShadow; diff --git a/apps/openmw/mwrender/shadow.hpp b/components/sceneutil/shadow.hpp similarity index 82% rename from apps/openmw/mwrender/shadow.hpp rename to components/sceneutil/shadow.hpp index 445a7b0f5..8d8278deb 100644 --- a/apps/openmw/mwrender/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -1,9 +1,9 @@ -#ifndef OPENMW_MWRENDER_SHADOW_H -#define OPENMW_MWRENDER_SHADOW_H +#ifndef COMPONENTS_SCENEUTIL_SHADOW_H +#define COMPONENTS_SCENEUTIL_SHADOW_H #include -namespace MWRender +namespace SceneUtil { class MWShadow : public osgShadow::ViewDependentShadowMap { @@ -27,4 +27,4 @@ namespace MWRender }; } -#endif //OPENMW_MWRENDER_SHADOW_H +#endif //COMPONENTS_SCENEUTIL_SHADOW_H diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 3b4373387..a0b1aca83 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -11,7 +11,7 @@ #include #include -#include "apps/openmw/mwrender/shadow.hpp" +#include "components/sceneutil/shadow.hpp" namespace Shader { @@ -108,7 +108,7 @@ namespace Shader // set up shadows in the shader // get these values from settings manager bool shadows = true & !disableShadows; - int numShadowMaps = MWRender::MWShadow::numberOfShadowMapsPerLight; + int numShadowMaps = SceneUtil::MWShadow::numberOfShadowMapsPerLight; DefineMap definesWithShadows; if (shadows) { From 6e0b61d084c5a98ecbfd43b3e6d733db28805ca2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 04:09:14 +0000 Subject: [PATCH 034/168] Add missing libraries to components target --- components/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f6af33b25..1e3a68ac8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -210,6 +210,7 @@ target_link_libraries(components ${OSGVIEWER_LIBRARIES} ${OSGTEXT_LIBRARIES} ${OSGGA_LIBRARIES} + ${OSGSHADOW_LIBRARIES} ${OSGANIMATION_LIBRARIES} ${Bullet_LIBRARIES} ${SDL2_LIBRARIES} From 64d5d0fd667eec0e0b074898453483068564b73c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 13:30:13 +0000 Subject: [PATCH 035/168] Prevent the local map from being considered to be shadowed. --- apps/openmw/mwrender/localmap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index c7f90bc5f..7f3132a9e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -204,8 +204,10 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f osg::ref_ptr fakeShadowMapImage = new osg::Image(); fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - *(float*)fakeShadowMapImage->data() = -std::numeric_limits::infinity(); // this has been tried both positive and negative + *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + fakeShadowMapTexture->setShadowComparison(true); + fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); From 548c42b5fd204dcb596462ada9a626cde97ac803 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Nov 2017 13:38:30 +0000 Subject: [PATCH 036/168] Disable over-zealous shadows in the character preview. --- apps/openmw/mwrender/characterpreview.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index f7219959a..15cc63893 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -150,6 +151,15 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); + osg::ref_ptr fakeShadowMapImage = new osg::Image(); + fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); + *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); + osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + fakeShadowMapTexture->setShadowComparison(true); + fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); + for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) + stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) osg::ref_ptr fog (new osg::Fog); From 590531595b9033641be6d7661cd6757d5bdca96f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 Nov 2017 02:02:27 +0000 Subject: [PATCH 037/168] Create @foreach shader preprocessor macro in preparation for moving shadow setup out of shadermanager.cpp --- components/shader/shadermanager.cpp | 121 +++++++++++++++++++++++----- files/shaders/objects_fragment.glsl | 10 ++- files/shaders/objects_vertex.glsl | 11 ++- files/shaders/terrain_fragment.glsl | 10 ++- files/shaders/terrain_vertex.glsl | 19 +++-- files/shaders/water_fragment.glsl | 25 +++--- files/shaders/water_vertex.glsl | 12 ++- 7 files changed, 159 insertions(+), 49 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a0b1aca83..ea971586a 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -74,13 +74,82 @@ namespace Shader return true; } + bool parseFors(std::string& source) + { + const char escapeCharacter = '$'; + size_t foundPos = 0; + while ((foundPos = source.find(escapeCharacter)) != std::string::npos) + { + size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); + if (endPos == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string command = source.substr(foundPos + 1, endPos - (foundPos + 1)); + if (command != "foreach") + { + std::cerr << "Unknown shader directive: $" << command << std::endl; + return false; + } + + size_t iterNameStart = endPos + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string iteratorName = "$" + source.substr(iterNameStart, iterNameEnd - iterNameStart); + + size_t listStart = iterNameEnd + 1; + size_t listEnd = source.find_first_of("\n\r", listStart); + if (listEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string list = source.substr(listStart, listEnd - listStart); + std::vector listElements; + boost::split(listElements, list, boost::is_any_of(",")); + + size_t contentStart = source.find_first_not_of("\n\r", listEnd); + size_t contentEnd = source.find("$endforeach", contentStart); + if (contentEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string content = source.substr(contentStart, contentEnd - contentStart); + + size_t overallEnd = contentEnd + std::string("$endforeach").length(); + // This will be wrong if there are other #line directives, so that needs fixing + int lineNumber = std::count(source.begin(), source.begin() + overallEnd, '\n') + 2; + + std::string replacement = ""; + for (std::vector::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++) + { + std::string contentInstance = content; + size_t foundIterator; + while ((foundIterator = contentInstance.find(iteratorName)) != std::string::npos) + contentInstance.replace(foundIterator, iteratorName.length(), *element); + replacement += contentInstance; + } + replacement += "\n#line " + std::to_string(lineNumber); + source.replace(foundPos, overallEnd - foundPos, replacement); + } + + return true; + } + bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines) { const char escapeCharacter = '@'; size_t foundPos = 0; + std::vector forIterators; while ((foundPos = source.find(escapeCharacter)) != std::string::npos) { - size_t endPos = source.find_first_of(" \n\r()[].;", foundPos); + size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); if (endPos == std::string::npos) { std::cerr << "Unexpected EOF" << std::endl; @@ -88,7 +157,34 @@ namespace Shader } std::string define = source.substr(foundPos+1, endPos - (foundPos+1)); ShaderManager::DefineMap::const_iterator defineFound = defines.find(define); - if (defineFound == defines.end()) + if (define == "foreach") + { + source.replace(foundPos, 1, "$"); + size_t iterNameStart = endPos + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + forIterators.push_back(source.substr(iterNameStart, iterNameEnd - iterNameStart)); + } + else if (define == "endforeach") + { + source.replace(foundPos, 1, "$"); + if (forIterators.empty()) + { + std::cerr << "endforeach without foreach" << std::endl; + return false; + } + else + forIterators.pop_back(); + } + else if (std::find(forIterators.begin(), forIterators.end(), define) != forIterators.end()) + { + source.replace(foundPos, 1, "$"); + } + else if (defineFound == defines.end()) { std::cerr << "Undefined " << define << std::endl; return false; @@ -113,23 +209,10 @@ namespace Shader if (shadows) { definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - - /*definesWithShadows.insert(std::string("shadow_texture_unit_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_space_coordinate_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_space_coordinate_calculations"), std::string("")); - definesWithShadows.insert(std::string("shadow_texture_sampler_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_texture_lookup_calculations"), std::string(""));*/ for (int i = 0; i < numShadowMaps; ++i) - { - definesWithShadows["shadow_texture_unit_declarations"] += "uniform int shadowTextureUnit" + std::to_string(i) + ";\n"; - definesWithShadows["shadow_space_coordinate_declarations"] += "varying vec4 shadowSpaceCoords" + std::to_string(i) + ";\n"; - - definesWithShadows["shadow_space_coordinate_calculations"] += "eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneT[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneR[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneQ[shadowTextureUnit" + std::to_string(i) + "]);\n" - + "shadowSpaceCoords" + std::to_string(i) + " = viewPos * eyePlaneMat;\n"; - - definesWithShadows["shadow_texture_sampler_declarations"] += "uniform sampler2DShadow shadowTexture" + std::to_string(i) + ";\n"; - definesWithShadows["shadow_texture_lookup_calculations"] += "shadowing *= shadow2DProj(shadowTexture" + std::to_string(i) + ", shadowSpaceCoords" + std::to_string(i) + ").r;\n"; - } + definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; + // remove extra comma + definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); } definesWithShadows.insert(defines.begin(), defines.end()); @@ -161,7 +244,7 @@ namespace Shader if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, definesWithShadows)) + if (!parseDefines(shaderSource, definesWithShadows) || !parseFors(shaderSource)) { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 7d9372c71..9196c1490 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -58,8 +58,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_sampler_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -122,7 +124,9 @@ void main() float shadowing = 1.0; #if SHADOWS - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index fb612afc8..f84971c97 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -49,8 +49,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_unit_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -111,6 +113,9 @@ void main(void) #if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; - @shadow_space_coordinate_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach #endif // SHADOWS } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e512d7475..1b985e14b 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -28,8 +28,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_sampler_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -74,7 +76,9 @@ void main() float shadowing = 1.0; #if SHADOWS - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 692e76cce..7cb959d3e 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -17,8 +17,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_unit_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -42,9 +44,12 @@ void main(void) uv = gl_MultiTexCoord0.xy; - #if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @shadow_space_coordinate_calculations - #endif // SHADOWS +#if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach +#endif // SHADOWS } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 586a247a4..ca09aa94b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +//DUMPME + #define REFRACTION @refraction_enabled #define SHADOWS @shadows_enabled @@ -144,9 +146,10 @@ uniform vec3 nodePosition; uniform float rainIntensity; #if SHADOWS - @shadow_texture_sampler_declarations - - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS float frustumDepth; @@ -165,15 +168,17 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - #if SHADOWS - float shadowing = 1.0; +#if SHADOWS + float shadowing = 1.0; - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach - float shadow = shadowing; - #else // NOT SHADOWS - float shadow = 1.0; - #endif // SHADOWS + float shadow = shadowing; +#else // NOT SHADOWS + float shadow = 1.0; +#endif // SHADOWS vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 6381155d0..1a14bcaa6 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -7,9 +7,10 @@ varying float depthPassthrough; #define SHADOWS @shadows_enabled #if SHADOWS - @shadow_texture_unit_declarations - - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS void main(void) @@ -33,6 +34,9 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; - @shadow_space_coordinate_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach #endif // SHADOWS } From 3d18ddc8e4b607cadf9caecb37fb94872ae3b0f8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 17 Nov 2017 17:18:33 +0000 Subject: [PATCH 038/168] Take into account previous #line directives when expanding @foreach shader macros --- components/shader/shadermanager.cpp | 18 ++++++++++++++++-- files/shaders/water_fragment.glsl | 2 -- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index ea971586a..59c81f40a 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -123,8 +123,22 @@ namespace Shader std::string content = source.substr(contentStart, contentEnd - contentStart); size_t overallEnd = contentEnd + std::string("$endforeach").length(); - // This will be wrong if there are other #line directives, so that needs fixing - int lineNumber = std::count(source.begin(), source.begin() + overallEnd, '\n') + 2; + + size_t lineDirectivePosition = source.rfind("#line", overallEnd); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString); + } + else + { + lineDirectivePosition = 0; + lineNumber = 2; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n'); std::string replacement = ""; for (std::vector::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ca09aa94b..fddd81eff 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -//DUMPME - #define REFRACTION @refraction_enabled #define SHADOWS @shadows_enabled From 166ba220720b8f65b4f8de7b2349a65ac0eb5f8a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 21 Nov 2017 16:53:12 +0000 Subject: [PATCH 039/168] Prevent line count changes within conditional blocks (because of conditional includes or @foreach expansion) ruining line numbering. --- components/shader/shadermanager.cpp | 60 +++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 59c81f40a..b5c292ad7 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -21,6 +21,44 @@ namespace Shader mPath = path; } + bool addLineDirectivesAfterConditionalBlocks(std::string& source) + { + for (size_t position = 0; position < source.length(); ) + { + size_t foundPos = source.find("#endif", position); + foundPos = std::min(foundPos, source.find("#elif", position)); + foundPos = std::min(foundPos, source.find("#else", position)); + + if (foundPos == std::string::npos) + break; + + foundPos = source.find_first_of("\n\r", foundPos); + foundPos = source.find_first_not_of("\n\r", foundPos); + + size_t lineDirectivePosition = source.rfind("#line", foundPos); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString) - 1; + } + else + { + lineDirectivePosition = 0; + lineNumber = 1; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); + + source.replace(foundPos, 0, "#line " + std::to_string(lineNumber) + "\n"); + + position = foundPos; + } + + return true; + } + bool parseIncludes(boost::filesystem::path shaderPath, std::string& source) { boost::replace_all(source, "\r\n", "\n"); @@ -54,14 +92,30 @@ namespace Shader std::stringstream buffer; buffer << includeFstream.rdbuf(); + std::string stringRepresentation = buffer.str(); + addLineDirectivesAfterConditionalBlocks(stringRepresentation); // insert #line directives so we get correct line numbers in compiler errors int includedFileNumber = fileNumber++; - int lineNumber = std::count(source.begin(), source.begin() + foundPos, '\n'); + size_t lineDirectivePosition = source.rfind("#line", foundPos); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString) - 1; + } + else + { + lineDirectivePosition = 0; + lineNumber = 1; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n'); std::stringstream toInsert; - toInsert << "#line 0 " << includedFileNumber << "\n" << buffer.str() << "\n#line " << lineNumber << " 0\n"; + toInsert << "#line 0 " << includedFileNumber << "\n" << stringRepresentation << "\n#line " << lineNumber << " 0\n"; source.replace(foundPos, (end-foundPos+1), toInsert.str()); @@ -248,7 +302,7 @@ namespace Shader // parse includes std::string source = buffer.str(); - if (!parseIncludes(boost::filesystem::path(mPath), source)) + if (!addLineDirectivesAfterConditionalBlocks(source) || !parseIncludes(boost::filesystem::path(mPath), source)) return NULL; templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; From 7a9df977c7b0a6ac689964550aa04889bf56a7fb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 21 Nov 2017 17:20:57 +0000 Subject: [PATCH 040/168] Add some prerequisits for making shadows disableable --- components/shader/shadermanager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index b5c292ad7..a7a5e99a0 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -165,7 +165,8 @@ namespace Shader } std::string list = source.substr(listStart, listEnd - listStart); std::vector listElements; - boost::split(listElements, list, boost::is_any_of(",")); + if (list != "") + boost::split(listElements, list, boost::is_any_of(",")); size_t contentStart = source.find_first_not_of("\n\r", listEnd); size_t contentEnd = source.find("$endforeach", contentStart); @@ -282,6 +283,11 @@ namespace Shader // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); } + else + { + definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); + definesWithShadows["shadow_texture_unit_list"] = ""; + } definesWithShadows.insert(defines.begin(), defines.end()); From 98cd9fc144fef83724d7c16a12c41d66ba972240 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 22 Nov 2017 20:07:07 +0000 Subject: [PATCH 041/168] Add preliminary support for global shader defines. --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++ components/sceneutil/shadow.cpp | 24 ++++++++++ components/sceneutil/shadow.hpp | 7 +++ components/shader/shadermanager.cpp | 57 ++++++++++------------- components/shader/shadermanager.hpp | 12 ++++- 5 files changed, 70 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1b34e433d..c2ade69d9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -238,6 +238,10 @@ namespace MWRender shadowedScene->addChild(sceneRoot); mRootNode->addChild(shadowedScene); + Shader::ShaderManager::DefineMap shadowDefines = tech->getShadowDefines(); + Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); + globalDefines.insert(shadowDefines.begin(), shadowDefines.end()); + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mPathgrid.reset(new Pathgrid(mRootNode)); diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e8b267dad..87aeb051e 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -712,4 +712,28 @@ namespace SceneUtil // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< +#include + namespace SceneUtil { class MWShadow : public osgShadow::ViewDependentShadowMap { public: static const int numberOfShadowMapsPerLight = 3; + static const int enableShadows = true; static const bool debugHud = true; MWShadow(); @@ -16,6 +19,10 @@ namespace SceneUtil const static int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; virtual void cull(osgUtil::CullVisitor& cv); + + virtual Shader::ShaderManager::DefineMap getShadowDefines(); + + virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); protected: const int debugTextureUnit; diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a7a5e99a0..b8beffa2e 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -11,8 +11,6 @@ #include #include -#include "components/sceneutil/shadow.hpp" - namespace Shader { @@ -211,7 +209,7 @@ namespace Shader return true; } - bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines) + bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines) { const char escapeCharacter = '@'; size_t foundPos = 0; @@ -226,6 +224,7 @@ namespace Shader } std::string define = source.substr(foundPos+1, endPos - (foundPos+1)); ShaderManager::DefineMap::const_iterator defineFound = defines.find(define); + ShaderManager::DefineMap::const_iterator globalDefineFound = globalDefines.find(define); if (define == "foreach") { source.replace(foundPos, 1, "$"); @@ -253,44 +252,27 @@ namespace Shader { source.replace(foundPos, 1, "$"); } - else if (defineFound == defines.end()) + else if (defineFound != defines.end()) { - std::cerr << "Undefined " << define << std::endl; - return false; + source.replace(foundPos, endPos - foundPos, defineFound->second); + } + else if (globalDefineFound != globalDefines.end()) + { + source.replace(foundPos, endPos - foundPos, globalDefineFound->second); } else { - source.replace(foundPos, endPos-foundPos, defineFound->second); + std::cerr << "Undefined " << define << std::endl; + return false; } } return true; } - osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType, bool disableShadows) + osg::ref_ptr ShaderManager::getShader(const std::string &shaderTemplate, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType) { OpenThreads::ScopedLock lock(mMutex); - // set up shadows in the shader - // get these values from settings manager - bool shadows = true & !disableShadows; - int numShadowMaps = SceneUtil::MWShadow::numberOfShadowMapsPerLight; - DefineMap definesWithShadows; - if (shadows) - { - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - for (int i = 0; i < numShadowMaps; ++i) - definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; - // remove extra comma - definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); - } - else - { - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); - definesWithShadows["shadow_texture_unit_list"] = ""; - } - - definesWithShadows.insert(defines.begin(), defines.end()); - // read the template if we haven't already TemplateMap::iterator templateIt = mShaderTemplates.find(shaderTemplate); if (templateIt == mShaderTemplates.end()) @@ -314,11 +296,11 @@ namespace Shader templateIt = mShaderTemplates.insert(std::make_pair(shaderTemplate, source)).first; } - ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, definesWithShadows)); + ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(shaderTemplate, defines)); if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, definesWithShadows) || !parseFors(shaderSource)) + if (!parseDefines(shaderSource, defines, mGlobalDefines) || !parseFors(shaderSource)) { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); @@ -331,7 +313,7 @@ namespace Shader static unsigned int counter = 0; shader->setName(std::to_string(counter++)); - shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, definesWithShadows), shader)).first; + shaderIt = mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), shader)).first; } return shaderIt->second; } @@ -350,6 +332,17 @@ namespace Shader return found->second; } + ShaderManager::DefineMap ShaderManager::getGlobalDefines() + { + return DefineMap(mGlobalDefines); + } + + void ShaderManager::setGlobalDefines(DefineMap & defines) + { + mGlobalDefines = defines; + // TODO: We need to trigger the regeneration of all shaders. + } + void ShaderManager::releaseGLObjects(osg::State *state) { OpenThreads::ScopedLock lock(mMutex); diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 17c46f58c..baaa73865 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -26,18 +26,26 @@ namespace Shader /// @param shaderTemplate The filename of the shader template. /// @param defines Define values that can be retrieved by the shader template. /// @param shaderType The type of shader (usually vertex or fragment shader). - /// @param disableShadows Whether to disable shadows in the shader regardless of the overall setting. False by default. /// @note May return NULL on failure. /// @note Thread safe. - osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType, bool disableShadows = false); + osg::ref_ptr getShader(const std::string& shaderTemplate, const DefineMap& defines, osg::Shader::Type shaderType); osg::ref_ptr getProgram(osg::ref_ptr vertexShader, osg::ref_ptr fragmentShader); + /// Get (a copy of) the DefineMap used to construct all shaders + DefineMap getGlobalDefines(); + + /// Set the DefineMap used to construct all shaders + /// @param defines The DefineMap to use + void setGlobalDefines(DefineMap& defines); + void releaseGLObjects(osg::State* state); private: std::string mPath; + DefineMap mGlobalDefines; + // typedef std::map TemplateMap; TemplateMap mShaderTemplates; From 4612597877e7817febe67b24dbd3e35900ce8b43 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 22 Nov 2017 20:54:39 +0000 Subject: [PATCH 042/168] Switch to insert_or_assign semantics when adding shadow defines to the global shader defines. --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c2ade69d9..52bc8de3c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -240,7 +240,10 @@ namespace MWRender Shader::ShaderManager::DefineMap shadowDefines = tech->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); - globalDefines.insert(shadowDefines.begin(), shadowDefines.end()); + + for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) + globalDefines[itr->first] = itr->second; + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mPathgrid.reset(new Pathgrid(mRootNode)); From 974e4d5299515a0b754215b06fbd5c6ee72dded5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 24 Nov 2017 22:43:40 +0000 Subject: [PATCH 043/168] Add check for null shaders when releasing OpenGL objects --- components/shader/shadermanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index b8beffa2e..3b18d0b75 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -347,7 +347,10 @@ namespace Shader { OpenThreads::ScopedLock lock(mMutex); for (auto shader : mShaders) - shader.second->releaseGLObjects(state); + { + if (shader.second != nullptr) + shader.second->releaseGLObjects(state); + } for (auto program : mPrograms) program.second->releaseGLObjects(state); } From 617473c7dadeb18a60bfcde70ffd350ab5654f3c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Dec 2017 18:06:20 +0000 Subject: [PATCH 044/168] Force near plane out further for LiSpSM projection --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 52bc8de3c..9258b754f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -211,7 +211,7 @@ namespace MWRender //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); settings->setBaseShadowTextureUnit(SceneUtil::MWShadow::baseShadowTextureUnit); - //settings->setMinimumShadowMapNearFarRatio(0); + settings->setMinimumShadowMapNearFarRatio(0.25); settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored From 7cce2d6f87113aabfb6ab2587ca45b799f38e5b9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Dec 2017 22:37:40 +0000 Subject: [PATCH 045/168] Implement a more sensible shadow map cascading system --- components/sceneutil/shadow.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 87aeb051e..dfcd5c1e8 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -596,14 +596,34 @@ namespace SceneUtil if (numShadowMapsPerLight>1) { // compute the start and end range in non-dimensional coords -#if 1 +#if 0 double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); -#else +#elif 0 // hardwired for 2 splits double r_start = (sm_i == 0) ? -1.0 : splitPoint; double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; +#else + double r_start, r_end; + // Split such that each shadow map covers a quarter of the area of the one after it + if (sm_i == 0) + r_start = -1.0; + else + { + r_start = (1 - pow(4.0, sm_i)) / (1 - pow(4.0, numShadowMapsPerLight)); + r_start *= 2.0; + r_start -= 1.0; + } + + if (sm_i + 1 == numShadowMapsPerLight) + r_end = 1.0; + else + { + r_end = (1 - pow(4.0, sm_i + 1)) / (1 - pow(4.0, numShadowMapsPerLight)); + r_end *= 2.0; + r_end -= 1.0; + } #endif // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap From 8957c92a36ae55cd77537a8ba48ba1838938f035 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Dec 2017 00:52:10 +0000 Subject: [PATCH 046/168] Switch to a more industry-standard shadow map splitting scheme --- components/sceneutil/shadow.cpp | 42 ++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index dfcd5c1e8..a4079d1a0 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -604,7 +604,7 @@ namespace SceneUtil // hardwired for 2 splits double r_start = (sm_i == 0) ? -1.0 : splitPoint; double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; -#else +#elif 0 double r_start, r_end; // Split such that each shadow map covers a quarter of the area of the one after it if (sm_i == 0) @@ -613,6 +613,7 @@ namespace SceneUtil { r_start = (1 - pow(4.0, sm_i)) / (1 - pow(4.0, numShadowMapsPerLight)); r_start *= 2.0; + //r_start += double(sm_i) / double(numShadowMapsPerLight); r_start -= 1.0; } @@ -622,8 +623,47 @@ namespace SceneUtil { r_end = (1 - pow(4.0, sm_i + 1)) / (1 - pow(4.0, numShadowMapsPerLight)); r_end *= 2.0; + //r_end += double(sm_i + 1) / double(numShadowMapsPerLight); r_end -= 1.0; } +#else + double r_start, r_end; + + // split system based on the original Parallel Split Shadow Maps paper. + double n = (frustum.eye - frustum.centerNearPlane).length(); + double f = (frustum.eye - frustum.centerFarPlane).length(); + double i = double(sm_i); + double m = double(numShadowMapsPerLight); + double deltaBias = 0; + if (sm_i == 0) + r_start = -1.0; + else + { + // compute the split point in main camera view + double ciLog = n * pow(f / n, i / m); + double ciUniform = n + (f - n) * i / m; + double ci = (ciLog + ciUniform) / 2 + deltaBias; + + // work out where this is in light space + osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; + osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; + r_start = lightSpacePos.y(); + } + + if (sm_i + 1 == numShadowMapsPerLight) + r_end = 1.0; + else + { + // compute the split point in main camera view + double ciLog = n * pow(f / n, (i + 1) / m); + double ciUniform = n + (f - n) * (i + 1) / m; + double ci = (ciLog + ciUniform) / 2 + deltaBias; + + // work out where this is in light space + osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; + osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; + r_end = lightSpacePos.y(); + } #endif // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap From 229cc9696f904b4235dffdf0394b1d6b43759a5d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Dec 2017 01:57:53 +0000 Subject: [PATCH 047/168] Make updating global shader defines update shaders. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/shader/shadermanager.cpp | 23 +++++++++++++++++++++-- components/shader/shadermanager.hpp | 4 +++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9258b754f..5449fd460 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,7 +244,7 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; - mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines, mViewer); mPathgrid.reset(new Pathgrid(mRootNode)); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 3b18d0b75..533b3ae56 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -337,10 +337,29 @@ namespace Shader return DefineMap(mGlobalDefines); } - void ShaderManager::setGlobalDefines(DefineMap & defines) + void ShaderManager::setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer) { mGlobalDefines = defines; - // TODO: We need to trigger the regeneration of all shaders. + bool threadsStarted = viewer->areThreadsRunning(); + if (threadsStarted) + viewer->stopThreading(); + for (auto shaderMapElement: mShaders) + { + std::string templateId = shaderMapElement.first.first; + ShaderManager::DefineMap defines = shaderMapElement.first.second; + osg::ref_ptr shader = shaderMapElement.second; + if (shader == nullptr) + // I'm not sure how to handle a shader that was already broken as there's no way to get a potential replacement to the nodes that need it. + continue; + std::string shaderSource = mShaderTemplates[templateId]; + if (!parseDefines(shaderSource, defines, mGlobalDefines) || !parseFors(shaderSource)) + // We just broke the shader and there's no way to force existing objects back to fixed-function mode as we would when creating the shader. + // If we put a nullptr in the shader map, we just lose the ability to put a working one in later. + continue; + shader->setShaderSource(shaderSource); + } + if (threadsStarted) + viewer->startThreading(); } void ShaderManager::releaseGLObjects(osg::State *state) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index baaa73865..16b4d639b 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -8,6 +8,8 @@ #include +#include + #include namespace Shader @@ -37,7 +39,7 @@ namespace Shader /// Set the DefineMap used to construct all shaders /// @param defines The DefineMap to use - void setGlobalDefines(DefineMap& defines); + void setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer); void releaseGLObjects(osg::State* state); From b08938485f362f081cb9880bc8dad8c88964c15a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Dec 2017 23:55:19 +0000 Subject: [PATCH 048/168] Make suspending viewer threads the responsibility of the caller, not the shader manager. --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- components/shader/shadermanager.cpp | 9 ++------- components/shader/shadermanager.hpp | 3 ++- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5449fd460..41d9969d4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,7 +244,8 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; - mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines, mViewer); + // It is unnecessary to stop/start the viewer as no frames are being rendered yet. + mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mPathgrid.reset(new Pathgrid(mRootNode)); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 533b3ae56..eb3a88eb4 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -337,12 +337,9 @@ namespace Shader return DefineMap(mGlobalDefines); } - void ShaderManager::setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer) + void ShaderManager::setGlobalDefines(DefineMap & globalDefines) { - mGlobalDefines = defines; - bool threadsStarted = viewer->areThreadsRunning(); - if (threadsStarted) - viewer->stopThreading(); + mGlobalDefines = globalDefines; for (auto shaderMapElement: mShaders) { std::string templateId = shaderMapElement.first.first; @@ -358,8 +355,6 @@ namespace Shader continue; shader->setShaderSource(shaderSource); } - if (threadsStarted) - viewer->startThreading(); } void ShaderManager::releaseGLObjects(osg::State *state) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 16b4d639b..02f35975d 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -39,7 +39,8 @@ namespace Shader /// Set the DefineMap used to construct all shaders /// @param defines The DefineMap to use - void setGlobalDefines(DefineMap & defines, osg::ref_ptr viewer); + /// @note This will change the source code for any shaders already created, potentially causing problems if they're being used to render a frame. It is recommended that any associated Viewers have their threading stopped while this function is running if any shaders are in use. + void setGlobalDefines(DefineMap & globalDefines); void releaseGLObjects(osg::State* state); From 4de3a361fb790162ea991a1e2190963f024ee717 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 26 Dec 2017 23:18:50 +0000 Subject: [PATCH 049/168] Make shadow maps only cover regions where shadow receivers might be. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 41d9969d4..caa808909 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -215,7 +215,7 @@ namespace MWRender settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored - //settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); //settings->setDebugDraw(true); // don't turn this on because it makes everything break //settings->setPerspectiveShadowMapCutOffAngle(0); From c192c851dbf05e00101deaba539247216791573e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 26 Dec 2017 23:51:50 +0000 Subject: [PATCH 050/168] Make disabling shadows disable their performance impact, too. --- components/sceneutil/shadow.cpp | 6 ++++++ components/sceneutil/shadow.hpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index a4079d1a0..21a0de89a 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -321,6 +321,12 @@ namespace SceneUtil void MWShadow::cull(osgUtil::CullVisitor& cv) { + if (!enableShadows) + { + _shadowedScene->osg::Group::traverse(cv); + return; + } + OSG_INFO << std::endl << std::endl << "ViewDependentShadowMap::cull(osg::CullVisitor&" << &cv << ")" << std::endl; if (!_shadowCastingStateSet) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index aa8085f0d..3c665bac7 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -11,7 +11,7 @@ namespace SceneUtil { public: static const int numberOfShadowMapsPerLight = 3; - static const int enableShadows = true; + static const bool enableShadows = true; static const bool debugHud = true; MWShadow(); From c3e0398d1c93962ed2f4b5a79afb37032de50fb3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Dec 2017 02:32:17 +0000 Subject: [PATCH 051/168] Add settings --- apps/openmw/mwrender/characterpreview.cpp | 9 +-- apps/openmw/mwrender/localmap.cpp | 9 +-- apps/openmw/mwrender/renderingmanager.cpp | 29 +++----- apps/openmw/mwrender/sky.cpp | 3 +- components/sceneutil/shadow.cpp | 87 +++++++++++++++++------ components/sceneutil/shadow.hpp | 15 ++-- files/settings-default.cfg | 19 +++++ 7 files changed, 106 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 15cc63893..e329d9ebc 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -151,14 +151,7 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); - osg::ref_ptr fakeShadowMapImage = new osg::Image(); - fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); - osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); - fakeShadowMapTexture->setShadowComparison(true); - fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); - for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) - stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + SceneUtil::MWShadow::disableShadowsForStateSet(stateset); // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 7f3132a9e..d4f55f18b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -202,14 +202,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - osg::ref_ptr fakeShadowMapImage = new osg::Image(); - fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); - *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); - osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); - fakeShadowMapTexture->setShadowComparison(true); - fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); - for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) - stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + SceneUtil::MWShadow::disableShadowsForStateSet(stateset); camera->addChild(lightSource); camera->setStateSet(stateset); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index caa808909..e72149b76 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -204,26 +204,15 @@ namespace MWRender osg::ref_ptr shadowedScene (new osgShadow::ShadowedScene); - osgShadow::ShadowSettings* settings = shadowedScene->getShadowSettings(); - settings->setLightNum(0); - settings->setCastsShadowTraversalMask(Mask_Scene|Mask_Actor|Mask_Player|Mask_Terrain); - settings->setReceivesShadowTraversalMask(~0u); - - //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::PERSPECTIVE_SHADOW_MAP); - settings->setBaseShadowTextureUnit(SceneUtil::MWShadow::baseShadowTextureUnit); - settings->setMinimumShadowMapNearFarRatio(0.25); - settings->setNumShadowMapsPerLight(SceneUtil::MWShadow::numberOfShadowMapsPerLight); - //settings->setShadowMapProjectionHint(osgShadow::ShadowSettings::ORTHOGRAPHIC_SHADOW_MAP); - //settings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); // ignored - settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); - //settings->setDebugDraw(true); // don't turn this on because it makes everything break - - //settings->setPerspectiveShadowMapCutOffAngle(0); - //settings->setShaderHint(osgShadow::ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER); - - int mapres = 2048; - settings->setTextureSize(osg::Vec2s(mapres,mapres)); - + int shadowCastingTraversalMask = Mask_Scene; + if (Settings::Manager::getBool("actor shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Actor; + if (Settings::Manager::getBool("player shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Player; + if (Settings::Manager::getBool("terrain shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Terrain; + SceneUtil::MWShadow::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); + SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); shadowedScene->setShadowTechnique(tech); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 331782c7b..79f5f00bb 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1124,8 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - for (int i = SceneUtil::MWShadow::baseShadowTextureUnit; i < SceneUtil::MWShadow::baseShadowTextureUnit + SceneUtil::MWShadow::numberOfShadowMapsPerLight; ++i) - skyroot->getOrCreateStateSet()->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF); + SceneUtil::MWShadow::disableShadowsForStateSet(skyroot->getOrCreateStateSet()); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 21a0de89a..0d654a817 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace SceneUtil { using namespace osgShadow; @@ -46,35 +48,76 @@ namespace SceneUtil " gl_FragColor = vec4( fS + fH * color, 1 ); \n" #else " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" - " //gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0); \n" #endif "} \n"; + void MWShadow::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) + { + if (!Settings::Manager::getBool("enable shadows", "Shadows")) + return; + + settings->setLightNum(0); + settings->setCastsShadowTraversalMask(castsShadowMask); + settings->setReceivesShadowTraversalMask(~0u); + + int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); + settings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); + settings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); + + settings->setMinimumShadowMapNearFarRatio(0.25); + if (Settings::Manager::getBool("compute tight scene bounds", "Shadows")) + settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + + int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); + settings->setTextureSize(osg::Vec2s(mapres, mapres)); + } - MWShadow::MWShadow() : debugProgram(new osg::Program), debugTextureUnit(0) + void MWShadow::disableShadowsForStateSet(osg::ref_ptr stateset) { - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); - debugProgram->addShader(vertexShader); - osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); - debugProgram->addShader(fragmentShader); + int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); + int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; + + osg::ref_ptr fakeShadowMapImage = new osg::Image(); + fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); + *(float*)fakeShadowMapImage->data() = std::numeric_limits::infinity(); + osg::ref_ptr fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage); + fakeShadowMapTexture->setShadowComparison(true); + fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); + for (int i = baseShadowTextureUnit; i < baseShadowTextureUnit + numberOfShadowMapsPerLight; ++i) + stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + } - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + MWShadow::MWShadow() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), + numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), + baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), + debugHud(Settings::Manager::getBool("enable debug hud", "Shadows")), + debugProgram(new osg::Program), debugTextureUnit(0) + { + if (debugHud) { - std::cout << i << std::endl; - - debugCameras.push_back(new osg::Camera); - debugCameras[i]->setViewport(200 * i, 0, 200, 200); - debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); - debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - - debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); - debugGeometry[i]->setCullingActive(false); - debugCameras[i]->addChild(debugGeometry[i]); - osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); - stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); + debugProgram->addShader(vertexShader); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); + debugProgram->addShader(fragmentShader); + + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + { + std::cout << i << std::endl; + + debugCameras.push_back(new osg::Camera); + debugCameras[i]->setViewport(200 * i, 0, 200, 200); + debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); + debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + debugGeometry[i]->setCullingActive(false); + debugCameras[i]->addChild(debugGeometry[i]); + osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + } } } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 3c665bac7..ec7bbb8d2 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -1,6 +1,7 @@ #ifndef COMPONENTS_SCENEUTIL_SHADOW_H #define COMPONENTS_SCENEUTIL_SHADOW_H +#include #include #include @@ -10,13 +11,11 @@ namespace SceneUtil class MWShadow : public osgShadow::ViewDependentShadowMap { public: - static const int numberOfShadowMapsPerLight = 3; - static const bool enableShadows = true; - static const bool debugHud = true; + static void setupShadowSettings(osg::ref_ptr settings, int castsShadowMask); - MWShadow(); + static void disableShadowsForStateSet(osg::ref_ptr stateSet); - const static int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; + MWShadow(); virtual void cull(osgUtil::CullVisitor& cv); @@ -31,6 +30,12 @@ namespace SceneUtil osg::ref_ptr debugProgram; std::vector> debugGeometry; + + const int numberOfShadowMapsPerLight; + const bool enableShadows; + const bool debugHud; + + const int baseShadowTextureUnit; }; } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 253883402..bd63f2bc6 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -466,3 +466,22 @@ companion x = 0.25 companion y = 0.0 companion w = 0.75 companion h = 0.375 + +[Shadows] +# Enable or disable shadows. +enable shadows = false +# How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. +number of shadow maps = 1 +# Enable the debug hud to see what the shadow map(s) contain. +enable debug hud = false +# Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. +compute tight scene bounds = false +# How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. +shadow map resolution = 1024 +# Allow actors to cast shadows. Potentially decreases performance. +actor shadows = false +# Allow the player to cast shadows. Potentially decreases performance. +player shadows = false +# Allow terrain to cast shadows. Potentially decreases performance. +terrain shadows = false +# Note: Right now, there is no setting allowing toggling of shadows for statics \ No newline at end of file From 8d4b32166c5d6980aebefc5b268460190a74785d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Dec 2017 02:35:25 +0000 Subject: [PATCH 052/168] Remove outdated comments --- apps/openmw/mwrender/renderingmanager.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e72149b76..c8b3812b1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -216,14 +216,6 @@ namespace MWRender SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); shadowedScene->setShadowTechnique(tech); - /*tech->setMaxFarPlane(0); - tech->setTextureSize(osg::Vec2s(mapres, mapres)); - tech->setShadowTextureCoordIndex(1); - tech->setShadowTextureUnit(1); - tech->setBaseTextureCoordIndex(0); - tech->setBaseTextureUnit(0);*/ - - //mRootNode->addChild(sceneRoot); shadowedScene->addChild(sceneRoot); mRootNode->addChild(shadowedScene); From d63fa5c0b5acec9f7566e965d1fcbdb97df73478 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 27 Dec 2017 04:01:10 +0000 Subject: [PATCH 053/168] Add rst documentation for the shadow settings. --- .../reference/modding/settings/index.rst | 1 + .../reference/modding/settings/shadows.rst | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 docs/source/reference/modding/settings/shadows.rst diff --git a/docs/source/reference/modding/settings/index.rst b/docs/source/reference/modding/settings/index.rst index 56d76a8d1..a11df35a3 100644 --- a/docs/source/reference/modding/settings/index.rst +++ b/docs/source/reference/modding/settings/index.rst @@ -31,6 +31,7 @@ The ranges I have included with each setting are the physically possible ranges, game general shaders + shadows input saves sound diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst new file mode 100644 index 000000000..d8e862479 --- /dev/null +++ b/docs/source/reference/modding/settings/shadows.rst @@ -0,0 +1,89 @@ +Shadow Settings +############### + +enable shadows +-------------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable or disable the rendering of shadows. +Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. + +number of shadow maps +--------------------- + +:Type: integer +:Range: 1 to 8, but higher values may conflict with other texture effects +:Default: 1 + +Control how many shadow maps to use - more of these means each shadow map texel covers less area, producing better-looking shadows, but may decrease performance. +Using too many shadow maps will lead to them overriding texture slots used for other effects, producing unpleasant artefacts. +A value of three is recommended in most cases, but other values may produce better results or performance. + +enable debug hud +---------------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable or disable the debug hud to see what the shadow map(s) contain. +This setting is only recommended for developers, bug reporting and advanced users performing fine-tuning of shadow settings. + +compute tight scene bounds +-------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +With this setting enabled, attempt to better use the shadow map(s) by making them cover a smaller area. +This can be especially helpful when looking downwards with a high viewing distance but will be less useful with the default value. +The performance impact of this may be very large. + +shadow map resolution +--------------------- + +:Type: integer +:Range: Dependent on GPU/driver combination +:Default: 1024 + +Control How large to make the shadow map(s). +Higher values increase GPU load but can produce better-looking results. +Power-of-two values may turn out to be faster than smaller values which are not powers of two on some GPU/driver combinations. + +actor shadows +------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow actors to cast shadows. +Potentially decreases performance. + +player shadows +-------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow the player to cast shadows. +Potentially decreases performance. + +terrain shadows +--------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow terrain to cast shadows. +Potentially decreases performance. + + + +Note: Right now, there is no setting allowing toggling of shadows for statics \ No newline at end of file From bf9a1ded63b3c5997409cacc2fb2916bb52e191e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 2 Jan 2018 16:39:05 +0000 Subject: [PATCH 054/168] Mark a function as override --- components/sceneutil/shadow.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index ec7bbb8d2..e5c3db327 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -17,7 +17,7 @@ namespace SceneUtil MWShadow(); - virtual void cull(osgUtil::CullVisitor& cv); + virtual void cull(osgUtil::CullVisitor& cv) override; virtual Shader::ShaderManager::DefineMap getShadowDefines(); From 112ade2a3ff217da958a5b81ff8e2a30ae106929 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 22 Jan 2018 15:52:37 +0000 Subject: [PATCH 055/168] Ensure TerrainDrawables affect the computed near/far planes. --- components/terrain/terraindrawable.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/terrain/terraindrawable.cpp b/components/terrain/terraindrawable.cpp index 60d591707..f216bb33b 100644 --- a/components/terrain/terraindrawable.cpp +++ b/components/terrain/terraindrawable.cpp @@ -47,6 +47,12 @@ void TerrainDrawable::cull(osgUtil::CullVisitor *cv) osg::RefMatrix& matrix = *cv->getModelViewMatrix(); + if (cv->getComputeNearFarMode() && bb.valid()) + { + if (!cv->updateCalculatedNearFar(matrix, *this, false)) + return; + } + float depth = bb.valid() ? distance(bb.center(),matrix) : 0.0f; if (osg::isNaN(depth)) return; From c3d7c7de214d757edbc32e073a157ea6e8a4eab4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 23 Jan 2018 20:13:37 +0000 Subject: [PATCH 056/168] Prevent first-person meshes disappearing. --- apps/openmw/mwrender/npcanimation.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 08e376f08..eca9bb3e6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -350,11 +350,16 @@ public: if (cv->getProjectionMatrix()->getPerspective(fov, aspect, zNear, zFar)) { fov = mFov; - osg::RefMatrix* newProjectionMatrix = new osg::RefMatrix(*cv->getProjectionMatrix()); + osg::ref_ptr newProjectionMatrix = new osg::RefMatrix(); newProjectionMatrix->makePerspective(fov, aspect, zNear, zFar); - cv->pushProjectionMatrix(newProjectionMatrix); + osg::ref_ptr invertedOldMatrix = cv->getProjectionMatrix(); + invertedOldMatrix = new osg::RefMatrix(osg::RefMatrix::inverse(*invertedOldMatrix)); + osg::ref_ptr viewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + viewMatrix->postMult(*newProjectionMatrix); + viewMatrix->postMult(*invertedOldMatrix); + cv->pushModelViewMatrix(viewMatrix, osg::Transform::ReferenceFrame::ABSOLUTE_RF); traverse(node, nv); - cv->popProjectionMatrix(); + cv->popModelViewMatrix(); } else traverse(node, nv); From 9f20aaccfb944580655ef1e41df0e0dce0f1638c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 25 Jan 2018 16:08:34 +0000 Subject: [PATCH 057/168] Add some more advanced settings to control shadows. --- components/sceneutil/shadow.cpp | 9 +++-- .../reference/modding/settings/shadows.rst | 37 ++++++++++++++++++- files/settings-default.cfg | 6 +++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 0d654a817..f1943f08d 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -64,7 +64,7 @@ namespace SceneUtil settings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); settings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); - settings->setMinimumShadowMapNearFarRatio(0.25); + settings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows")); if (Settings::Manager::getBool("compute tight scene bounds", "Shadows")) settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); @@ -683,7 +683,8 @@ namespace SceneUtil double f = (frustum.eye - frustum.centerFarPlane).length(); double i = double(sm_i); double m = double(numShadowMapsPerLight); - double deltaBias = 0; + double ratio = Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"); + double deltaBias = Settings::Manager::getFloat("split point bias", "Shadows"); if (sm_i == 0) r_start = -1.0; else @@ -691,7 +692,7 @@ namespace SceneUtil // compute the split point in main camera view double ciLog = n * pow(f / n, i / m); double ciUniform = n + (f - n) * i / m; - double ci = (ciLog + ciUniform) / 2 + deltaBias; + double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; @@ -706,7 +707,7 @@ namespace SceneUtil // compute the split point in main camera view double ciLog = n * pow(f / n, (i + 1) / m); double ciUniform = n + (f - n) * (i + 1) / m; - double ci = (ciLog + ciUniform) / 2 + deltaBias; + double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index d8e862479..334663fe8 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -86,4 +86,39 @@ Potentially decreases performance. -Note: Right now, there is no setting allowing toggling of shadows for statics \ No newline at end of file +Note: Right now, there is no setting allowing toggling of shadows for statics + +Expert settings +*************** + +You probably shouldn't be changing these if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. +If you have, then you may get better results tuning these for your specific view distance. + +split point uniform logarithmic ratio +------------------------------------- + +:Type: float +:Range: 0.0-1.0 for sensible results. Other values may 'work' but could behave bizarrely. +:Default: 0.5 + +Controls the ratio of :math:`C_i^{log}` versus :math:`C_i^{uniform}` used to form the Practical Split Scheme as described in the linked paper. + +split point bias +---------------- + +:Type: float +:Range: Any value supported by C++ floats on your platform, although undesirable behaviour is more likely to appear the further the value is from zero. +:Default: 0.0 + +The :math:`\delta_{bias}` parameter used to form the Practical Split Scheme as described in the linked paper. + +minimum lispsm near far ratio +----------------------------- + +:Type: float +:Range: Must be greater than zero. +:Default: 0.25 + +Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. +Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. +Increasing this pushes detail further away by moving the frustum apex further from the near plane. \ No newline at end of file diff --git a/files/settings-default.cfg b/files/settings-default.cfg index bc1830242..49615dc68 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -475,12 +475,18 @@ companion h = 0.375 enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 +# Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. +split point uniform logarithmic ratio = 0.5 +# Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. +split point bias = 0.0 # Enable the debug hud to see what the shadow map(s) contain. enable debug hud = false # Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. compute tight scene bounds = false # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. shadow map resolution = 1024 +# Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. Increasing this pushes detail further away. +minimum lispsm near far ratio = 0.25 # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false # Allow the player to cast shadows. Potentially decreases performance. From 0cb9903c88f36c597d4b144dfeed5d5147ea26d1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 25 Jan 2018 21:30:11 +0000 Subject: [PATCH 058/168] Tweak headings in settings documentation --- docs/source/reference/modding/settings/shadows.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 334663fe8..a0e902d7b 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -1,6 +1,9 @@ Shadow Settings ############### +Main settings +************* + enable shadows -------------- From 6251e0519e00fa81f6c4a46257b1bdaa0c1a8a30 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 23 Feb 2018 23:31:53 +0000 Subject: [PATCH 059/168] Use CLSB results to reduce maximum shadow map distance when sensible. --- components/sceneutil/shadow.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index f1943f08d..e8c7e1947 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -449,6 +449,18 @@ namespace SceneUtil Frustum frustum(&cv, minZNear, maxZFar); + double reducedNear, reducedFar; + if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + reducedNear = osg::maximum(cv.getCalculatedNearPlane(), minZNear); + reducedFar = osg::minimum(cv.getCalculatedFarPlane(), maxZFar); + } + else + { + reducedNear = minZNear; + reducedFar = maxZFar; + } + // return compute near far mode back to it's original settings cv.setComputeNearFarMode(cachedNearFarMode); @@ -544,6 +556,20 @@ namespace SceneUtil double yMid = (clsb._bb.yMin() + clsb._bb.yMax())*0.5f; double yRange = (clsb._bb.yMax() - clsb._bb.yMin()); + osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); + double minZ = DBL_MAX; + double maxZ = -DBL_MAX; + for (unsigned int i = 0; i < 8; i++) + { + osg::Vec3 corner = clsb._bb.corner(i); + corner = corner * cornerConverter; + + maxZ = osg::maximum(maxZ, -corner.z()); + minZ = osg::minimum(minZ, -corner.z()); + } + reducedNear = osg::maximum(reducedNear, minZ); + reducedFar = osg::minimum(reducedFar, maxZ); + // OSG_NOTICE<<" xMid="< Date: Sun, 4 Feb 2018 23:27:45 +0000 Subject: [PATCH 060/168] Move the declaration of ComputeLightSpaceBounds to the header so that it can be accessed from other compilation units. (cherry picked from commit 8ac4fb208897a18da4934dd6f2fe84560b44ba9d) --- components/sceneutil/shadow.cpp | 202 ++++++++++++++++---------------- components/sceneutil/shadow.hpp | 26 ++++ 2 files changed, 124 insertions(+), 104 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e8c7e1947..1e4112971 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -227,140 +227,134 @@ namespace SceneUtil } } - class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + MWShadow::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { - public: - ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) - { - setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); - pushViewport(viewport); - pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); - pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); - } + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + } - void apply(osg::Node& node) - { - if (isCulled(node)) return; + void MWShadow::ComputeLightSpaceBounds::apply(osg::Node& node) + { + if (isCulled(node)) return; - // push the culling mode. - pushCurrentMask(); + // push the culling mode. + pushCurrentMask(); - traverse(node); + traverse(node); - // pop the culling mode. - popCurrentMask(); - } + // pop the culling mode. + popCurrentMask(); + } - void apply(osg::Geode& node) - { - if (isCulled(node)) return; + void MWShadow::ComputeLightSpaceBounds::apply(osg::Geode& node) + { + if (isCulled(node)) return; - // push the culling mode. - pushCurrentMask(); + // push the culling mode. + pushCurrentMask(); - for (unsigned int i = 0; igetBoundingBox()); - } + updateBound(node.getDrawable(i)->getBoundingBox()); } - - // pop the culling mode. - popCurrentMask(); } - void apply(osg::Drawable& drawable) - { - if (isCulled(drawable)) return; + // pop the culling mode. + popCurrentMask(); + } - // push the culling mode. - pushCurrentMask(); + void MWShadow::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; - updateBound(drawable.getBoundingBox()); + // push the culling mode. + pushCurrentMask(); - // pop the culling mode. - popCurrentMask(); - } + updateBound(drawable.getBoundingBox()); - void apply(osg::Billboard&) - { - OSG_INFO << "Warning Billboards not yet supported" << std::endl; - return; - } - - void apply(osg::Projection&) - { - // projection nodes won't affect a shadow map so their subgraphs should be ignored - return; - } + // pop the culling mode. + popCurrentMask(); + } - void apply(osg::Transform& transform) - { - if (isCulled(transform)) return; + void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) + { + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; + } - // push the culling mode. - pushCurrentMask(); + void MWShadow::ComputeLightSpaceBounds::apply(osg::Projection&) + { + // projection nodes won't affect a shadow map so their subgraphs should be ignored + return; + } - // absolute transforms won't affect a shadow map so their subgraphs should be ignored. - if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) - { - osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); - transform.computeLocalToWorldMatrix(*matrix, this); - pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); + void MWShadow::ComputeLightSpaceBounds::apply(osg::Transform& transform) + { + if (isCulled(transform)) return; - traverse(transform); + // push the culling mode. + pushCurrentMask(); - popModelViewMatrix(); - } + // absolute transforms won't affect a shadow map so their subgraphs should be ignored. + if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) + { + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - // pop the culling mode. - popCurrentMask(); + traverse(transform); + popModelViewMatrix(); } - void apply(osg::Camera&) - { - // camera nodes won't affect a shadow map so their subgraphs should be ignored - return; - } + // pop the culling mode. + popCurrentMask(); - void updateBound(const osg::BoundingBox& bb) - { - if (!bb.valid()) return; - - const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); - - update(bb.corner(0) * matrix); - update(bb.corner(1) * matrix); - update(bb.corner(2) * matrix); - update(bb.corner(3) * matrix); - update(bb.corner(4) * matrix); - update(bb.corner(5) * matrix); - update(bb.corner(6) * matrix); - update(bb.corner(7) * matrix); - } + } - void update(const osg::Vec3& v) + void MWShadow::ComputeLightSpaceBounds::apply(osg::Camera&) + { + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void MWShadow::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) + { + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); + } + + void MWShadow::ComputeLightSpaceBounds::update(const osg::Vec3& v) + { + if (v.z()<-1.0f) { - if (v.z()<-1.0f) - { - //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; - float y = v.y(); - if (y<-1.0f) y = -1.0f; - if (y>1.0f) y = 1.0f; - _bb.expandBy(osg::Vec3(x, y, v.z())); + //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; + float y = v.y(); + if (y<-1.0f) y = -1.0f; + if (y>1.0f) y = 1.0f; + _bb.expandBy(osg::Vec3(x, y, v.z())); + } void MWShadow::cull(osgUtil::CullVisitor& cv) { diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index e5c3db327..b92e8658b 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -22,6 +22,32 @@ namespace SceneUtil virtual Shader::ShaderManager::DefineMap getShadowDefines(); virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); + + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + { + public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + void apply(osg::Node& node); + + void apply(osg::Geode& node); + + void apply(osg::Drawable& drawable); + + void apply(osg::Billboard&); + + void apply(osg::Projection&); + + void apply(osg::Transform& transform); + + void apply(osg::Camera&); + + void updateBound(const osg::BoundingBox& bb); + + void update(const osg::Vec3& v); + + osg::BoundingBox _bb; + }; protected: const int debugTextureUnit; From 9ec59783bac3dd69f0e0754591842bd733d5fef5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 5 Feb 2018 23:03:18 +0000 Subject: [PATCH 061/168] Add basic support for distant terrain CLSB (cherry picked from commit 0f9dc3e65b72e6fff762f7a0933bae6f861e5fd4) --- components/sceneutil/shadow.cpp | 8 ++++++++ components/sceneutil/shadow.hpp | 3 +++ components/terrain/quadtreeworld.cpp | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 1e4112971..cc3eb0be6 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -282,6 +282,14 @@ namespace SceneUtil popCurrentMask(); } + void MWShadow::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) + { + // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. + + update(osg::Vec3(-1.0, -1.0, 0.0)); + update(osg::Vec3(1.0, 1.0, 0.0)); + } + void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) { OSG_INFO << "Warning Billboards not yet supported" << std::endl; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index b92e8658b..897b8759d 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace SceneUtil @@ -34,6 +35,8 @@ namespace SceneUtil void apply(osg::Drawable& drawable); + void apply(Terrain::QuadTreeWorld& quadTreeWorld); + void apply(osg::Billboard&); void apply(osg::Projection&); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f31064805..76baa2f45 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -4,6 +4,8 @@ #include +#include + #include "quadtreenode.hpp" #include "storage.hpp" #include "viewdata.hpp" @@ -344,7 +346,12 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) + { + SceneUtil::MWShadow::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); + if (shadowBoundsVisitor) + shadowBoundsVisitor->apply(*this); return; + } ViewData* vd = mRootNode->getView(nv); From 273914aba871eb81ff08d3a0b16c35e3c9e590cc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:13:05 +0000 Subject: [PATCH 062/168] Add osgShadow ViewDependentShadowMaps as they can be found in OSG's GitHub Repository --- components/CMakeLists.txt | 2 +- components/sceneutil/mwshadowtechnique | 196 ++ components/sceneutil/mwshadowtechnique.cpp | 2430 ++++++++++++++++++++ 3 files changed, 2627 insertions(+), 1 deletion(-) create mode 100644 components/sceneutil/mwshadowtechnique create mode 100644 components/sceneutil/mwshadowtechnique.cpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1e3a68ac8..e68e7ed07 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -56,7 +56,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer shadow + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer shadow mwshadowtechnique ) add_component_dir (nif diff --git a/components/sceneutil/mwshadowtechnique b/components/sceneutil/mwshadowtechnique new file mode 100644 index 000000000..63b80fed1 --- /dev/null +++ b/components/sceneutil/mwshadowtechnique @@ -0,0 +1,196 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP +#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 + +#include +#include +#include +#include +#include + +#include + +namespace osgShadow { + +/** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ +class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique +{ + public : + ViewDependentShadowMap(); + + ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_Object(osgShadow, ViewDependentShadowMap); + + /** initialize the ShadowedScene and local cached data structures.*/ + virtual void init(); + + /** run the update traversal of the ShadowedScene and update any loca chached data structures.*/ + virtual void update(osg::NodeVisitor& nv); + + /** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/ + virtual void cull(osgUtil::CullVisitor& cv); + + /** Resize any per context GLObject buffers to specified size. */ + virtual void resizeGLObjectBuffers(unsigned int maxSize); + + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objects + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + + /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ + virtual void cleanSceneGraph(); + + + struct OSGSHADOW_EXPORT Frustum + { + Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); + + osg::Matrixd projectionMatrix; + osg::Matrixd modelViewMatrix; + + typedef std::vector Vertices; + Vertices corners; + + typedef std::vector Indices; + typedef std::vector Faces; + Faces faces; + + typedef std::vector Edges; + Edges edges; + + osg::Vec3d eye; + osg::Vec3d centerNearPlane; + osg::Vec3d centerFarPlane; + osg::Vec3d center; + osg::Vec3d frustumCenterLine; + }; + + // forward declare + class ViewDependentData; + + struct OSGSHADOW_EXPORT LightData : public osg::Referenced + { + LightData(ViewDependentData* vdd); + + virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); + + ViewDependentData* _viewDependentData; + + osg::ref_ptr lightMatrix; + osg::ref_ptr light; + + osg::Vec4d lightPos; + osg::Vec3d lightPos3; + osg::Vec3d lightDir; + bool directionalLight; + + typedef std::vector ActiveTextureUnits; + ActiveTextureUnits textureUnits; + }; + + typedef std::list< osg::ref_ptr > LightDataList; + + struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + { + ShadowData(ViewDependentData* vdd); + + virtual void releaseGLObjects(osg::State* = 0) const; + + ViewDependentData* _viewDependentData; + + unsigned int _textureUnit; + osg::ref_ptr _texture; + osg::ref_ptr _texgen; + osg::ref_ptr _camera; + }; + + typedef std::list< osg::ref_ptr > ShadowDataList; + + + class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + { + public: + ViewDependentData(ViewDependentShadowMap* vdsm); + + const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } + + LightDataList& getLightDataList() { return _lightDataList; } + + ShadowDataList& getShadowDataList() { return _shadowDataList; } + + osg::StateSet* getStateSet() { return _stateset.get(); } + + virtual void releaseGLObjects(osg::State* = 0) const; + + protected: + virtual ~ViewDependentData() {} + + ViewDependentShadowMap* _viewDependentShadowMap; + + osg::ref_ptr _stateset; + + LightDataList _lightDataList; + ShadowDataList _shadowDataList; + }; + + virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); + + ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); + + + + virtual void createShaders(); + + virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; + + virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); + + virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera); + + virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); + + virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; + + virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; + + virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; + +protected: + virtual ~ViewDependentShadowMap(); + + typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; + mutable OpenThreads::Mutex _viewDependentDataMapMutex; + ViewDependentDataMap _viewDependentDataMap; + + osg::ref_ptr _shadowRecievingPlaceholderStateSet; + + osg::ref_ptr _shadowCastingStateSet; + osg::ref_ptr _polygonOffset; + osg::ref_ptr _fallbackBaseTexture; + osg::ref_ptr _fallbackShadowMapTexture; + + typedef std::vector< osg::ref_ptr > Uniforms; + mutable OpenThreads::Mutex _accessUniformsAndProgramMutex; + Uniforms _uniforms; + osg::ref_ptr _program; +}; + +} + +#endif diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp new file mode 100644 index 000000000..f72f2ce15 --- /dev/null +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -0,0 +1,2430 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include +#include +#include +#include +#include + +#include + +using namespace osgShadow; + +////////////////////////////////////////////////////////////////// +// fragment shader +// +#if 0 +static const char fragmentShaderSource_withBaseTexture[] = + "uniform sampler2D baseTexture; \n" + "uniform sampler2DShadow shadowTexture; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" + " vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy ); \n" + " color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture, gl_TexCoord[1] ).r ); \n" + " gl_FragColor = color; \n" + "} \n"; +#else +static const char fragmentShaderSource_withBaseTexture[] = + "uniform sampler2D baseTexture; \n" + "uniform int baseTextureUnit; \n" + "uniform sampler2DShadow shadowTexture0; \n" + "uniform int shadowTextureUnit0; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" + " vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n" + " color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r ); \n" + " gl_FragColor = color; \n" + "} \n"; + +static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] = + "uniform sampler2D baseTexture; \n" + "uniform int baseTextureUnit; \n" + "uniform sampler2DShadow shadowTexture0; \n" + "uniform int shadowTextureUnit0; \n" + "uniform sampler2DShadow shadowTexture1; \n" + "uniform int shadowTextureUnit1; \n" + " \n" + "void main(void) \n" + "{ \n" + " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" + " vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n" + " float shadow0 = shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r; \n" + " float shadow1 = shadow2DProj( shadowTexture1, gl_TexCoord[shadowTextureUnit1] ).r; \n" + " color *= mix( colorAmbientEmissive, gl_Color, shadow0*shadow1 ); \n" + " gl_FragColor = color; \n" + "} \n"; +#endif + +template +class RenderLeafTraverser : public T +{ +public: + + RenderLeafTraverser() + { + } + + void traverse(const osgUtil::RenderStage* rs) + { + traverse(static_cast(rs)); + } + + void traverse(const osgUtil::RenderBin* renderBin) + { + const osgUtil::RenderBin::RenderBinList& rbl = renderBin->getRenderBinList(); + for(osgUtil::RenderBin::RenderBinList::const_iterator itr = rbl.begin(); + itr != rbl.end(); + ++itr) + { + traverse(itr->second.get()); + } + + const osgUtil::RenderBin::RenderLeafList& rll = renderBin->getRenderLeafList(); + for(osgUtil::RenderBin::RenderLeafList::const_iterator itr = rll.begin(); + itr != rll.end(); + ++itr) + { + handle(*itr); + } + + const osgUtil::RenderBin::StateGraphList& rgl = renderBin->getStateGraphList(); + for(osgUtil::RenderBin::StateGraphList::const_iterator itr = rgl.begin(); + itr != rgl.end(); + ++itr) + { + traverse(*itr); + } + + } + + void traverse(const osgUtil::StateGraph* stateGraph) + { + const osgUtil::StateGraph::ChildList& cl = stateGraph->_children; + for(osgUtil::StateGraph::ChildList::const_iterator itr = cl.begin(); + itr != cl.end(); + ++itr) + { + traverse(itr->second.get()); + } + + const osgUtil::StateGraph::LeafList& ll = stateGraph->_leaves; + for(osgUtil::StateGraph::LeafList::const_iterator itr = ll.begin(); + itr != ll.end(); + ++itr) + { + handle(itr->get()); + } + } + + inline void handle(const osgUtil::RenderLeaf* renderLeaf) + { + this->operator()(renderLeaf); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// VDSMCameraCullCallback +// +class VDSMCameraCullCallback : public osg::NodeCallback +{ + public: + + VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); + + virtual void operator()(osg::Node*, osg::NodeVisitor* nv); + + osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); } + osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); } + + protected: + + ViewDependentShadowMap* _vdsm; + osg::ref_ptr _projectionMatrix; + osg::ref_ptr _renderStage; + osg::Polytope _polytope; +}; + +VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope): + _vdsm(vdsm), + _polytope(polytope) +{ +} + +void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + osgUtil::CullVisitor* cv = nv->asCullVisitor(); + osg::Camera* camera = node->asCamera(); + OSG_INFO<<"VDSMCameraCullCallback::operator()(osg::Node* "<getProjectionCullingStack().back(); + + cs.setFrustum(_polytope); + + cv->pushCullingSet(); + } +#endif + if (_vdsm->getShadowedScene()) + { + _vdsm->getShadowedScene()->osg::Group::traverse(*nv); + } +#if 1 + if (!_polytope.empty()) + { + OSG_INFO<<"Popping custom Polytope"<popCullingSet(); + } +#endif + + _renderStage = cv->getCurrentRenderBin()->getStage(); + + OSG_INFO<<"VDSM second : _renderStage = "<<_renderStage<getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + // make sure that the near plane is computed correctly. + cv->computeNearPlane(); + + osg::Matrixd projection = *(cv->getProjectionMatrix()); + + OSG_INFO<<"RTT Projection matrix "<setProjectionMatrix(projection); + + _projectionMatrix = cv->getProjectionMatrix(); + } +} + + +class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack +{ +public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) + { + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix),osg::Transform::ABSOLUTE_RF); + } + + void apply(osg::Node& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); + } + + void apply(osg::Billboard&) + { + OSG_INFO<<"Warning Billboards not yet supported"< matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix,this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); + + traverse(transform); + + popModelViewMatrix(); + } + + // pop the culling mode. + popCurrentMask(); + + } + + void apply(osg::Camera&) + { + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; + } + + void updateBound(const osg::BoundingBox& bb) + { + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); + } + + void update(const osg::Vec3& v) + { + if (v.z()<-1.0f) + { + //OSG_NOTICE<<"discarding("<1.0f) x=1.0f; + float y = v.y(); + if (y<-1.0f) y=-1.0f; + if (y>1.0f) y=1.0f; + _bb.expandBy(osg::Vec3(x,y,v.z())); + } + + osg::BoundingBox _bb; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// LightData +// +ViewDependentShadowMap::LightData::LightData(ViewDependentShadowMap::ViewDependentData* vdd): + _viewDependentData(vdd), + directionalLight(false) +{ +} + +void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) +{ + lightMatrix = lm; + light = l; + + lightPos = light->getPosition(); + directionalLight = (light->getPosition().w()== 0.0); + if (directionalLight) + { + lightPos3.set(0.0, 0.0, 0.0); // directional light has no destinct position + lightDir.set(-lightPos.x(), -lightPos.y(), -lightPos.z()); + lightDir.normalize(); + OSG_INFO<<" Directional light, lightPos="<setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT); + + //_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + _camera->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f)); + + _camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + + // switch off small feature culling as this can cull out geometry that will still be large enough once perspective correction takes effect. + _camera->setCullingMode(_camera->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING); + + // set viewport + _camera->setViewport(0,0,textureSize.x(),textureSize.y()); + + + if (debug) + { + // clear just the depth buffer + _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // render after the main camera + _camera->setRenderOrder(osg::Camera::POST_RENDER); + + // attach the texture and use it as the color buffer. + //_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); + _camera->attach(osg::Camera::COLOR_BUFFER, _texture.get()); + } + else + { + // clear the depth and colour bufferson each clear. + _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // set the camera to render before the main camera. + _camera->setRenderOrder(osg::Camera::PRE_RENDER); + + // tell the camera to use OpenGL frame buffer object where supported. + _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); + + // attach the texture and use it as the color buffer. + _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); + //_camera->attach(osg::Camera::COLOR_BUFFER, _texture.get()); + } +} + +void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) const +{ + OSG_INFO<<"ViewDependentShadowMap::ShadowData::releaseGLObjects"<releaseGLObjects(state); + _camera->releaseGLObjects(state); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// Frustum +// +ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar): + corners(8), + faces(6), + edges(12) +{ + projectionMatrix = *(cv->getProjectionMatrix()); + modelViewMatrix = *(cv->getModelViewMatrix()); + + OSG_INFO<<"Projection matrix "<getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) + { + osg::Matrix::value_type zNear = osg::maximum(cv->getCalculatedNearPlane(),minZNear); + osg::Matrix::value_type zFar = osg::minimum(cv->getCalculatedFarPlane(),maxZFar); + + cv->clampProjectionMatrix(projectionMatrix, zNear, zFar); + + OSG_INFO<<"zNear = "<releaseGLObjects(state); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +// ViewDependentShadowMap +// +ViewDependentShadowMap::ViewDependentShadowMap(): + ShadowTechnique() +{ + _shadowRecievingPlaceholderStateSet = new osg::StateSet; +} + +ViewDependentShadowMap::ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop): + ShadowTechnique(vdsm,copyop) +{ + _shadowRecievingPlaceholderStateSet = new osg::StateSet; +} + +ViewDependentShadowMap::~ViewDependentShadowMap() +{ +} + + +void ViewDependentShadowMap::init() +{ + if (!_shadowedScene) return; + + OSG_INFO<<"ViewDependentShadowMap::init()"< lock(_viewDependentDataMapMutex); + ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv); + if (itr!=_viewDependentDataMap.end()) return itr->second.get(); + + osg::ref_ptr vdd = createViewDependentData(cv); + _viewDependentDataMap[cv] = vdd; + return vdd.release(); +} + +void ViewDependentShadowMap::update(osg::NodeVisitor& nv) +{ + OSG_INFO<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<osg::Group::traverse(nv); +} + +void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv) +{ + OSG_INFO<osg::Group::traverse(cv); + return; + } + + ViewDependentData* vdd = getViewDependentData(&cv); + + if (!vdd) + { + OSG_INFO<<"Warning, now ViewDependentData created, unable to create shadows."<osg::Group::traverse(cv); + return; + } + + ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + OSG_INFO<<"cv->getProjectionMatrix()="<<*cv.getProjectionMatrix()<getMaximumShadowMapDistance(),maxZFar); + if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); + + //OSG_NOTICE<<"maxZFar "<getLightDataList(); + for(LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = **itr; + + // 3.1 compute light space polytope + // + osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); + + // if polytope is empty then no rendering. + if (polytope.empty()) + { + OSG_NOTICE<<"Polytope empty no shadow to render"<1 &&*/ _shadowedScene->getCastsShadowTraversalMask()!=0xffffffff) + { + // osg::ElapsedTime timer; + + osg::ref_ptr viewport = new osg::Viewport(0,0,2048,2048); + ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); + clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); + + osg::Matrixd invertModelView; + invertModelView.invert(viewMatrix); + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); + cs.setFrustum(local_polytope); + clsb.pushCullingSet(); + + _shadowedScene->accept(clsb); + + // OSG_NOTICE<<"Extents of LightSpace "< camera = sd->_camera; + + camera->setProjectionMatrix(projectionMatrix); + camera->setViewMatrix(viewMatrix); + + if (settings->getDebugDraw()) + { + camera->getViewport()->x() = pos_x; + pos_x += static_cast(camera->getViewport()->width()) + 40; + } + + // transform polytope in model coords into light spaces eye coords. + osg::Matrixd invertModelView; + invertModelView.invert(camera->getViewMatrix()); + + osg::Polytope local_polytope(polytope); + local_polytope.transformProvidingInverse(invertModelView); + + + if (numShadowMapsPerLight>1) + { + // compute the start and end range in non-dimensional coords +#if 0 + double r_start = (sm_i==0) ? -1.0 : (double(sm_i)/double(numShadowMapsPerLight)*2.0-1.0); + double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : (double(sm_i+1)/double(numShadowMapsPerLight)*2.0-1.0); +#endif + + // hardwired for 2 splits + double r_start = (sm_i==0) ? -1.0 : splitPoint; + double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : splitPoint; + + // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap + // to prevent a seam showing through between the shadowmaps + if (sm_i+10) + { + // not the first shadowmap so insert a polytope to clip the scene from before r_start + + // plane in clip space coords + osg::Plane plane(0.0,1.0,0.0,-r_start); + + // transform into eye coords + plane.transformProvidingInverse(projectionMatrix); + local_polytope.getPlaneList().push_back(plane); + + //OSG_NOTICE<<"Adding r_start plane "<0) + { + decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); + } + + // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<getLightDataList(); + + LightDataList previous_ldl; + previous_ldl.swap(pll); + + //MR testing giving a specific light + osgUtil::RenderStage * rs = cv->getCurrentRenderBin()->getStage(); + + OSG_INFO<<"selectActiveLights osgUtil::RenderStage="<getModelViewMatrix()); + + osgUtil::PositionalStateContainer::AttrMatrixList& aml = + rs->getPositionalStateContainer()->getAttrMatrixList(); + + + const ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + for(osgUtil::PositionalStateContainer::AttrMatrixList::reverse_iterator itr = aml.rbegin(); + itr != aml.rend(); + ++itr) + { + const osg::Light* light = dynamic_cast(itr->first.get()); + if (light && light->getLightNum() >= 0) + { + // is LightNum matched to that defined in settings + if (settings && settings->getLightNum()>=0 && light->getLightNum()!=settings->getLightNum()) continue; + + LightDataList::iterator pll_itr = pll.begin(); + for(; pll_itr != pll.end(); ++pll_itr) + { + if ((*pll_itr)->light->getLightNum()==light->getLightNum()) break; + } + + if (pll_itr==pll.end()) + { + OSG_INFO<<"Light num "<getLightNum()<setLightData(itr->second.get(), light, modelViewMatrix); + pll.push_back(ld); + } + else + { + OSG_INFO<<"Light num "<getLightNum()<<" already used, ignore light"< lock(_accessUniformsAndProgramMutex); + + _shadowCastingStateSet = new osg::StateSet; + + ShadowSettings* settings = getShadowedScene()->getShadowSettings(); + + if (!settings->getDebugDraw()) + { + // note soft (attribute only no mode override) setting. When this works ? + // 1. for objects prepared for backface culling + // because they usually also set CullFace and CullMode on in their state + // For them we override CullFace but CullMode remains set by them + // 2. For one faced, trees, and similar objects which cannot use + // backface nor front face so they usually use CullMode off set here. + // In this case we will draw them in their entirety. + + _shadowCastingStateSet->setAttribute( new osg::CullFace( osg::CullFace::FRONT ), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); + + // make sure GL_CULL_FACE is off by default + // we assume that if object has cull face attribute set to back + // it will also set cull face mode ON so no need for override + _shadowCastingStateSet->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); + } + +#if 1 + float factor = 1.1; + float units = 4.0; +#else + float factor = -1.1; + float units = -4.0; +#endif + _polygonOffset = new osg::PolygonOffset(factor, units); + _shadowCastingStateSet->setAttribute(_polygonOffset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + _shadowCastingStateSet->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + + + _uniforms.clear(); + osg::ref_ptr baseTextureSampler = new osg::Uniform("baseTexture",(int)_baseTextureUnit); + _uniforms.push_back(baseTextureSampler.get()); + + osg::ref_ptr baseTextureUnit = new osg::Uniform("baseTextureUnit",(int)_baseTextureUnit); + _uniforms.push_back(baseTextureUnit.get()); + + for(unsigned int sm_i=0; sm_igetNumShadowMapsPerLight(); ++sm_i) + { + { + std::stringstream sstr; + sstr<<"shadowTexture"< shadowTextureSampler = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); + _uniforms.push_back(shadowTextureSampler.get()); + } + + { + std::stringstream sstr; + sstr<<"shadowTextureUnit"< shadowTextureUnit = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); + _uniforms.push_back(shadowTextureUnit.get()); + } + } + + switch(settings->getShaderHint()) + { + case(ShadowSettings::NO_SHADERS): + { + OSG_INFO<<"No shaders provided by, user must supply own shaders"< fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); + if (settings->getNumShadowMapsPerLight()==2) + { + _program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture_twoShadowMaps)); + } + else + { + _program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture)); + } + + break; + } + } + + { + osg::ref_ptr image = new osg::Image; + image->allocateImage( 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE ); + *(osg::Vec4ub*)image->data() = osg::Vec4ub( 0xFF, 0xFF, 0xFF, 0xFF ); + + _fallbackBaseTexture = new osg::Texture2D(image.get()); + _fallbackBaseTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT); + _fallbackBaseTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT); + _fallbackBaseTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); + _fallbackBaseTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); + + _fallbackShadowMapTexture = new osg::Texture2D(image.get()); + _fallbackShadowMapTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT); + _fallbackShadowMapTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT); + _fallbackShadowMapTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST); + _fallbackShadowMapTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); + + } +} + +osg::Polytope ViewDependentShadowMap::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) +{ + OSG_INFO<<"computeLightViewFrustumPolytope()"<getShadowSettings(); + + double dotProduct_v = positionedLight.lightDir * frustum.frustumCenterLine; + double gamma_v = acos(dotProduct_v); + if (gamma_vgetPerspectiveShadowMapCutOffAngle()) || gamma_v>osg::DegreesToRadians(180.0-settings->getPerspectiveShadowMapCutOffAngle())) + { + OSG_INFO<<"View direction and Light direction below tolerance"<=0.0 && d1>=0.0) + { + // OSG_NOTICE<<" Edge completely inside"<first; + osg::Vec3d& v1 = itr->second; + osg::Vec3d intersection = v0 - (v1-v0)*(d0/(d1-d0)); + intersections.push_back(intersection); + // OSG_NOTICE<<" Edge across clip plane, v0="<=side_y.length2()) ? side_x : side_y; + side.normalize(); + + osg::Vec3d up = side ^ normal; + up.normalize(); + + osg::Vec3d center; + for(Vertices::iterator itr = intersections.begin(); + itr != intersections.end(); + ++itr) + { + center += *itr; + } + + center /= double(intersections.size()); + + typedef std::map VertexMap; + VertexMap vertexMap; + for(Vertices::iterator itr = intersections.begin(); + itr != intersections.end(); + ++itr) + { + osg::Vec3d dv = (*itr-center); + double h = dv * side; + double v = dv * up; + double angle = atan2(h,v); + // OSG_NOTICE<<"angle = "<_modelview.get()!=previous_modelview) + { + previous_modelview = renderLeaf->_modelview.get(); + if (previous_modelview) + { + light_mvp.mult(*renderLeaf->_modelview, light_p); + } + else + { + // no modelview matrix (such as when LightPointNode is in the scene graph) so assume + // that modelview matrix is indentity. + light_mvp = light_p; + } + // OSG_INFO<<"Computing new light_mvp "<_drawable->getBoundingBox(); + if (bb.valid()) + { + // OSG_NOTICE<<"checked extents of "<_drawable->getName()<max_z) { max_z=ls.z(); /* OSG_NOTICE<<" + ";*/ } + + // OSG_NOTICE<<" bb.z() in ls = "<getShadowSettings(); + + //frustum.projectionMatrix; + //frustum.modelViewMatrix; + + osg::Matrixd light_p = camera->getProjectionMatrix(); + osg::Matrixd light_v = camera->getViewMatrix(); + osg::Matrixd light_vp = light_v * light_p; + osg::Vec3d lightdir(0.0,0.0,-1.0); + + // check whether this light space projection is perspective or orthographic. + bool orthographicLightSpaceProjection = light_p(0,3)==0.0 && light_p(1,3)==0.0 && light_p(2,3)==0.0; + + if (!orthographicLightSpaceProjection) + { + OSG_INFO<<"perspective light space projection not yet supported."<setProjectionMatrix(light_p); + } + +#endif + + osg::Vec3d eye_v = frustum.eye * light_v; + //osg::Vec3d centerNearPlane_v = frustum.centerNearPlane * light_v; + osg::Vec3d center_v = frustum.center * light_v; + osg::Vec3d viewdir_v = center_v-eye_v; viewdir_v.normalize(); + + double dotProduct_v = lightdir * viewdir_v; + double gamma_v = acos(dotProduct_v); + if (gamma_vgetPerspectiveShadowMapCutOffAngle()) || gamma_v>osg::DegreesToRadians(180-settings->getPerspectiveShadowMapCutOffAngle())) + { + // OSG_NOTICE<<"Light and view vectors near parallel - use standard shadow map."<getTraversalMask(); + + cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getReceivesShadowTraversalMask() ); + + _shadowedScene->osg::Group::traverse(*cv); + + cv->setTraversalMask( traversalMask ); + + return; +} + +void ViewDependentShadowMap::cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const +{ + OSG_INFO<<"cullShadowCastingScene()"<getTraversalMask(); + + cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getCastsShadowTraversalMask() ); + + if (camera) camera->accept(*cv); + + cv->setTraversalMask( traversalMask ); + + return; +} + +osg::StateSet* ViewDependentShadowMap::selectStateSetForRenderingShadow(ViewDependentData& vdd) const +{ + OSG_INFO<<" selectStateSetForRenderingShadow() "< stateset = vdd.getStateSet(); + + OpenThreads::ScopedLock lock(_accessUniformsAndProgramMutex); + + vdd.getStateSet()->clear(); + + vdd.getStateSet()->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); + + for(Uniforms::const_iterator itr=_uniforms.begin(); + itr!=_uniforms.end(); + ++itr) + { + OSG_INFO<<"addUniform("<<(*itr)->getName()<<")"<addUniform(itr->get()); + } + + if (_program.valid()) + { + stateset->setAttribute(_program.get()); + } + + LightDataList& pll = vdd.getLightDataList(); + for(LightDataList::iterator itr = pll.begin(); + itr != pll.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + LightData& pl = (**itr); + + // if no texture units have been activated for this light then no shadow state required. + if (pl.textureUnits.empty()) continue; + + for(LightData::ActiveTextureUnits::iterator atu_itr = pl.textureUnits.begin(); + atu_itr != pl.textureUnits.end(); + ++atu_itr) + { + OSG_INFO<<" Need to assign state for "<<*atu_itr<getShadowSettings(); + unsigned int shadowMapModeValue = settings->getUseOverrideForShadowMapTexture() ? + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE : + osg::StateAttribute::ON; + + + ShadowDataList& sdl = vdd.getShadowDataList(); + for(ShadowDataList::iterator itr = sdl.begin(); + itr != sdl.end(); + ++itr) + { + // 3. create per light/per shadow map division of lightspace/frustum + // create a list of light/shadow map data structures + + ShadowData& sd = (**itr); + + OSG_INFO<<" ShadowData for "<setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), shadowMapModeValue); + + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); + stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); + } + + return vdd.getStateSet(); +} + +void ViewDependentShadowMap::resizeGLObjectBuffers(unsigned int /*maxSize*/) +{ + // the way that ViewDependentData is mapped shouldn't +} + +void ViewDependentShadowMap::releaseGLObjects(osg::State* state) const +{ + OpenThreads::ScopedLock lock(_viewDependentDataMapMutex); + for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin(); + itr != _viewDependentDataMap.end(); + ++itr) + { + ViewDependentData* vdd = itr->second.get(); + if (vdd) + { + vdd->releaseGLObjects(state); + } + } +} From 74672485556ef5760a4c271b2f663b6a5679bc5a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:14:29 +0000 Subject: [PATCH 063/168] Undo a modification from the upstream shadow technique which breaks compatibiltiy with OSG 3.4 --- components/sceneutil/mwshadowtechnique.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index f72f2ce15..876943c88 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -168,7 +168,7 @@ VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) { - osgUtil::CullVisitor* cv = nv->asCullVisitor(); + osgUtil::CullVisitor* cv = dynamic_cast(nv); osg::Camera* camera = node->asCamera(); OSG_INFO<<"VDSMCameraCullCallback::operator()(osg::Node* "< Date: Sat, 24 Feb 2018 00:15:54 +0000 Subject: [PATCH 064/168] Add a notice clarifying the source of the shadow technique files. --- components/sceneutil/mwshadowtechnique.cpp | 5 + components/sceneutil/mwshadowtechnique.hpp | 201 +++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 components/sceneutil/mwshadowtechnique.hpp diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 876943c88..e68e23484 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1,3 +1,8 @@ +/* This file is based on OpenSceneGraph's src/osgShadow/ViewDependentShadowMap.cpp. + * Where applicable, any changes made are covered by OpenMW's GPL 3 license, not the OSGPL. + * The original copyright notice is listed below. + */ + /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield * * This library is open source and may be redistributed and/or modified under diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp new file mode 100644 index 000000000..4352d811a --- /dev/null +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -0,0 +1,201 @@ +/* This file is based on OpenSceneGraph's include/osgShadow/ViewDependentShadowMap. + * Where applicable, any changes made are covered by OpenMW's GPL 3 license, not the OSGPL. + * The original copyright notice is listed below. + */ + +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield +* +* This library is open source and may be redistributed and/or modified under +* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or +* (at your option) any later version. The full license is in LICENSE file +* included with this distribution, and on the openscenegraph.org website. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP +#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 + +#include +#include +#include +#include +#include + +#include + +namespace osgShadow { + + /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ + class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique + { + public: + ViewDependentShadowMap(); + + ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + META_Object(osgShadow, ViewDependentShadowMap); + + /** initialize the ShadowedScene and local cached data structures.*/ + virtual void init(); + + /** run the update traversal of the ShadowedScene and update any loca chached data structures.*/ + virtual void update(osg::NodeVisitor& nv); + + /** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/ + virtual void cull(osgUtil::CullVisitor& cv); + + /** Resize any per context GLObject buffers to specified size. */ + virtual void resizeGLObjectBuffers(unsigned int maxSize); + + /** If State is non-zero, this function releases any associated OpenGL objects for + * the specified graphics context. Otherwise, releases OpenGL objects + * for all graphics contexts. */ + virtual void releaseGLObjects(osg::State* = 0) const; + + /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ + virtual void cleanSceneGraph(); + + + struct OSGSHADOW_EXPORT Frustum + { + Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); + + osg::Matrixd projectionMatrix; + osg::Matrixd modelViewMatrix; + + typedef std::vector Vertices; + Vertices corners; + + typedef std::vector Indices; + typedef std::vector Faces; + Faces faces; + + typedef std::vector Edges; + Edges edges; + + osg::Vec3d eye; + osg::Vec3d centerNearPlane; + osg::Vec3d centerFarPlane; + osg::Vec3d center; + osg::Vec3d frustumCenterLine; + }; + + // forward declare + class ViewDependentData; + + struct OSGSHADOW_EXPORT LightData : public osg::Referenced + { + LightData(ViewDependentData* vdd); + + virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); + + ViewDependentData* _viewDependentData; + + osg::ref_ptr lightMatrix; + osg::ref_ptr light; + + osg::Vec4d lightPos; + osg::Vec3d lightPos3; + osg::Vec3d lightDir; + bool directionalLight; + + typedef std::vector ActiveTextureUnits; + ActiveTextureUnits textureUnits; + }; + + typedef std::list< osg::ref_ptr > LightDataList; + + struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + { + ShadowData(ViewDependentData* vdd); + + virtual void releaseGLObjects(osg::State* = 0) const; + + ViewDependentData* _viewDependentData; + + unsigned int _textureUnit; + osg::ref_ptr _texture; + osg::ref_ptr _texgen; + osg::ref_ptr _camera; + }; + + typedef std::list< osg::ref_ptr > ShadowDataList; + + + class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + { + public: + ViewDependentData(ViewDependentShadowMap* vdsm); + + const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } + + LightDataList& getLightDataList() { return _lightDataList; } + + ShadowDataList& getShadowDataList() { return _shadowDataList; } + + osg::StateSet* getStateSet() { return _stateset.get(); } + + virtual void releaseGLObjects(osg::State* = 0) const; + + protected: + virtual ~ViewDependentData() {} + + ViewDependentShadowMap* _viewDependentShadowMap; + + osg::ref_ptr _stateset; + + LightDataList _lightDataList; + ShadowDataList _shadowDataList; + }; + + virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); + + ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); + + + + virtual void createShaders(); + + virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; + + virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); + + virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera); + + virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); + + virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; + + virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; + + virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; + + protected: + virtual ~ViewDependentShadowMap(); + + typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; + mutable OpenThreads::Mutex _viewDependentDataMapMutex; + ViewDependentDataMap _viewDependentDataMap; + + osg::ref_ptr _shadowRecievingPlaceholderStateSet; + + osg::ref_ptr _shadowCastingStateSet; + osg::ref_ptr _polygonOffset; + osg::ref_ptr _fallbackBaseTexture; + osg::ref_ptr _fallbackShadowMapTexture; + + typedef std::vector< osg::ref_ptr > Uniforms; + mutable OpenThreads::Mutex _accessUniformsAndProgramMutex; + Uniforms _uniforms; + osg::ref_ptr _program; + }; + +} + +#endif From 11e59d3c11183e997afc8dcd641c77f7d46666ce Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:52:46 +0000 Subject: [PATCH 065/168] Move to the correct namespace. --- components/sceneutil/mwshadowtechnique.cpp | 4 +++- components/sceneutil/mwshadowtechnique.hpp | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e68e23484..a7ec6a2d7 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -16,7 +16,8 @@ * OpenSceneGraph Public License for more details. */ -#include +#include "mwshadowtechnique.hpp" + #include #include #include @@ -25,6 +26,7 @@ #include using namespace osgShadow; +using namespace SceneUtil; ////////////////////////////////////////////////////////////////// // fragment shader diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 4352d811a..d9df99371 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -16,8 +16,8 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP -#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 +#ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H +#define COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H 1 #include #include @@ -27,10 +27,10 @@ #include -namespace osgShadow { +namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ - class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique + class OSGSHADOW_EXPORT ViewDependentShadowMap : public osgShadow::ShadowTechnique { public: ViewDependentShadowMap(); From c815366044eb21078f2a810de06ea761d1d96d23 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:55:24 +0000 Subject: [PATCH 066/168] Move to the correct namespace part 2 --- components/sceneutil/mwshadowtechnique.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index d9df99371..1d213bc0f 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -37,7 +37,7 @@ namespace SceneUtil { ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); - META_Object(osgShadow, ViewDependentShadowMap); + META_Object(SceneUtil, ViewDependentShadowMap); /** initialize the ShadowedScene and local cached data structures.*/ virtual void init(); From 7bd4c5e4b32f426d16758da2a0340b594b97f502 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 24 Feb 2018 00:57:58 +0000 Subject: [PATCH 067/168] Change class name --- components/sceneutil/mwshadowtechnique.cpp | 76 +++++++++++----------- components/sceneutil/mwshadowtechnique.hpp | 16 ++--- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index a7ec6a2d7..71cfef255 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -152,7 +152,7 @@ class VDSMCameraCullCallback : public osg::NodeCallback { public: - VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); + VDSMCameraCullCallback(MWShadowTechnique* vdsm, osg::Polytope& polytope); virtual void operator()(osg::Node*, osg::NodeVisitor* nv); @@ -161,13 +161,13 @@ class VDSMCameraCullCallback : public osg::NodeCallback protected: - ViewDependentShadowMap* _vdsm; + MWShadowTechnique* _vdsm; osg::ref_ptr _projectionMatrix; osg::ref_ptr _renderStage; osg::Polytope _polytope; }; -VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope): +VDSMCameraCullCallback::VDSMCameraCullCallback(MWShadowTechnique* vdsm, osg::Polytope& polytope): _vdsm(vdsm), _polytope(polytope) { @@ -375,13 +375,13 @@ public: // // LightData // -ViewDependentShadowMap::LightData::LightData(ViewDependentShadowMap::ViewDependentData* vdd): +MWShadowTechnique::LightData::LightData(MWShadowTechnique::ViewDependentData* vdd): _viewDependentData(vdd), directionalLight(false) { } -void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) +void MWShadowTechnique::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix) { lightMatrix = lm; light = l; @@ -426,7 +426,7 @@ void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const o // // ShadowData // -ViewDependentShadowMap::ShadowData::ShadowData(ViewDependentShadowMap::ViewDependentData* vdd): +MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData* vdd): _viewDependentData(vdd), _textureUnit(0) { @@ -511,9 +511,9 @@ ViewDependentShadowMap::ShadowData::ShadowData(ViewDependentShadowMap::ViewDepen } } -void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) const +void MWShadowTechnique::ShadowData::releaseGLObjects(osg::State* state) const { - OSG_INFO<<"ViewDependentShadowMap::ShadowData::releaseGLObjects"<releaseGLObjects(state); _camera->releaseGLObjects(state); } @@ -522,7 +522,7 @@ void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) con // // Frustum // -ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar): +MWShadowTechnique::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar): corners(8), faces(6), edges(12) @@ -651,14 +651,14 @@ ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNe // // ViewDependentData // -ViewDependentShadowMap::ViewDependentData::ViewDependentData(ViewDependentShadowMap* vdsm): +MWShadowTechnique::ViewDependentData::ViewDependentData(MWShadowTechnique* vdsm): _viewDependentShadowMap(vdsm) { OSG_INFO<<"ViewDependentData::ViewDependentData()"< lock(_viewDependentDataMapMutex); ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv); @@ -721,15 +721,15 @@ ViewDependentShadowMap::ViewDependentData* ViewDependentShadowMap::getViewDepend return vdd.release(); } -void ViewDependentShadowMap::update(osg::NodeVisitor& nv) +void MWShadowTechnique::update(osg::NodeVisitor& nv) { - OSG_INFO<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<osg::Group::traverse(nv); } -void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv) +void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) { - OSG_INFO<getShadowSettings(); @@ -2286,7 +2286,7 @@ bool ViewDependentShadowMap::adjustPerspectiveShadowMapCameraSettings(osgUtil::R return true; } -bool ViewDependentShadowMap::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen) +bool MWShadowTechnique::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen) { OSG_INFO<<"assignTexGenSettings() textureUnit="< lock(_viewDependentDataMapMutex); for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin(); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 1d213bc0f..efbf2ed5c 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -30,14 +30,14 @@ namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ - class OSGSHADOW_EXPORT ViewDependentShadowMap : public osgShadow::ShadowTechnique + class OSGSHADOW_EXPORT MWShadowTechnique : public osgShadow::ShadowTechnique { public: - ViewDependentShadowMap(); + MWShadowTechnique(); - ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + MWShadowTechnique(const MWShadowTechnique& vdsm, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); - META_Object(SceneUtil, ViewDependentShadowMap); + META_Object(SceneUtil, MWShadowTechnique); /** initialize the ShadowedScene and local cached data structures.*/ virtual void init(); @@ -129,9 +129,9 @@ namespace SceneUtil { class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced { public: - ViewDependentData(ViewDependentShadowMap* vdsm); + ViewDependentData(MWShadowTechnique* vdsm); - const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } + const MWShadowTechnique* getViewDependentShadowMap() const { return _viewDependentShadowMap; } LightDataList& getLightDataList() { return _lightDataList; } @@ -144,7 +144,7 @@ namespace SceneUtil { protected: virtual ~ViewDependentData() {} - ViewDependentShadowMap* _viewDependentShadowMap; + MWShadowTechnique* _viewDependentShadowMap; osg::ref_ptr _stateset; @@ -177,7 +177,7 @@ namespace SceneUtil { virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; protected: - virtual ~ViewDependentShadowMap(); + virtual ~MWShadowTechnique(); typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; mutable OpenThreads::Mutex _viewDependentDataMapMutex; From ce02c83089990a1bf826c1ef3233667df970530f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:27:47 +0000 Subject: [PATCH 068/168] Copy debug shader source into new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 71cfef255..5217b4832 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -77,6 +77,45 @@ static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] = "} \n"; #endif +std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; +std::string debugFragmentShaderSource = + "uniform sampler2D texture; \n" + " \n" + "void main(void) \n" + "{ \n" +#if 1 + " float f = texture2D(texture, gl_TexCoord[0].xy).r; \n" + " \n" + " f = 256.0 * f; \n" + " float fC = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fS = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fH = floor( f ) / 256.0; \n" + " \n" + " fS *= 0.5; \n" + " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" + " \n" + " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" + " abs( fC - 0.333333 ), \n" + " abs( fC - 0.666667 ) ); \n" + " \n" + " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" + " \n" + " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" + " fMax = 1.0 / fMax; \n" + " \n" + " vec3 color = fMax * rgb; \n" + " \n" + " gl_FragColor = vec4( fS + fH * color, 1 ); \n" +#else + " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" +#endif + "} \n"; + + template class RenderLeafTraverser : public T { From 02d0ee3485dc35590099bfd76ec57a74c12ece24 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:29:31 +0000 Subject: [PATCH 069/168] Rename old shadow class to shadow manager --- apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +-- apps/openmw/mwrender/sky.cpp | 2 +- components/sceneutil/shadow.cpp | 34 +++++++++++------------ components/sceneutil/shadow.hpp | 4 +-- components/terrain/quadtreeworld.cpp | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index e329d9ebc..63fe32dfe 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -151,7 +151,7 @@ namespace MWRender defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); - SceneUtil::MWShadow::disableShadowsForStateSet(stateset); + SceneUtil::ShadowManager::disableShadowsForStateSet(stateset); // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d4f55f18b..97e9c817a 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -202,7 +202,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - SceneUtil::MWShadow::disableShadowsForStateSet(stateset); + SceneUtil::ShadowManager::disableShadowsForStateSet(stateset); camera->addChild(lightSource); camera->setStateSet(stateset); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8b3812b1..a59ba8c1a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -211,9 +211,9 @@ namespace MWRender shadowCastingTraversalMask |= Mask_Player; if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - SceneUtil::MWShadow::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); + SceneUtil::ShadowManager::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); - SceneUtil::MWShadow* tech = new SceneUtil::MWShadow(); + SceneUtil::ShadowManager* tech = new SceneUtil::ShadowManager(); shadowedScene->setShadowTechnique(tech); shadowedScene->addChild(sceneRoot); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 79f5f00bb..3e81a7610 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1124,7 +1124,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Assign empty program to specify we don't want shaders // The shaders generated by the SceneManager can't handle everything we need skyroot->getOrCreateStateSet()->setAttributeAndModes(new osg::Program(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::PROTECTED|osg::StateAttribute::ON); - SceneUtil::MWShadow::disableShadowsForStateSet(skyroot->getOrCreateStateSet()); + SceneUtil::ShadowManager::disableShadowsForStateSet(skyroot->getOrCreateStateSet()); skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index cc3eb0be6..8c729e3cc 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -51,7 +51,7 @@ namespace SceneUtil #endif "} \n"; - void MWShadow::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) + void ShadowManager::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) { if (!Settings::Manager::getBool("enable shadows", "Shadows")) return; @@ -72,7 +72,7 @@ namespace SceneUtil settings->setTextureSize(osg::Vec2s(mapres, mapres)); } - void MWShadow::disableShadowsForStateSet(osg::ref_ptr stateset) + void ShadowManager::disableShadowsForStateSet(osg::ref_ptr stateset) { int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; @@ -87,7 +87,7 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - MWShadow::MWShadow() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), + ShadowManager::ShadowManager() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), debugHud(Settings::Manager::getBool("enable debug hud", "Shadows")), @@ -227,7 +227,7 @@ namespace SceneUtil } } - MWShadow::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + ShadowManager::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); @@ -237,7 +237,7 @@ namespace SceneUtil pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Node& node) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Node& node) { if (isCulled(node)) return; @@ -250,7 +250,7 @@ namespace SceneUtil popCurrentMask(); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Geode& node) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Geode& node) { if (isCulled(node)) return; @@ -269,7 +269,7 @@ namespace SceneUtil popCurrentMask(); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) { if (isCulled(drawable)) return; @@ -282,7 +282,7 @@ namespace SceneUtil popCurrentMask(); } - void MWShadow::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) + void ShadowManager::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) { // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. @@ -290,19 +290,19 @@ namespace SceneUtil update(osg::Vec3(1.0, 1.0, 0.0)); } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Billboard&) { OSG_INFO << "Warning Billboards not yet supported" << std::endl; return; } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Projection&) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Projection&) { // projection nodes won't affect a shadow map so their subgraphs should be ignored return; } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Transform& transform) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Transform& transform) { if (isCulled(transform)) return; @@ -326,13 +326,13 @@ namespace SceneUtil } - void MWShadow::ComputeLightSpaceBounds::apply(osg::Camera&) + void ShadowManager::ComputeLightSpaceBounds::apply(osg::Camera&) { // camera nodes won't affect a shadow map so their subgraphs should be ignored return; } - void MWShadow::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) + void ShadowManager::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) { if (!bb.valid()) return; @@ -348,7 +348,7 @@ namespace SceneUtil update(bb.corner(7) * matrix); } - void MWShadow::ComputeLightSpaceBounds::update(const osg::Vec3& v) + void ShadowManager::ComputeLightSpaceBounds::update(const osg::Vec3& v) { if (v.z()<-1.0f) { @@ -364,7 +364,7 @@ namespace SceneUtil _bb.expandBy(osg::Vec3(x, y, v.z())); } - void MWShadow::cull(osgUtil::CullVisitor& cv) + void ShadowManager::cull(osgUtil::CullVisitor& cv) { if (!enableShadows) { @@ -851,7 +851,7 @@ namespace SceneUtil // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< settings, int castsShadowMask); static void disableShadowsForStateSet(osg::ref_ptr stateSet); - MWShadow(); + ShadowManager(); virtual void cull(osgUtil::CullVisitor& cv) override; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 76baa2f45..85c43ce1d 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -347,7 +347,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) { - SceneUtil::MWShadow::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); + SceneUtil::ShadowManager::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); if (shadowBoundsVisitor) shadowBoundsVisitor->apply(*this); return; From 06b2ce6646df4d7c6a22fe691f2ca06deb5643a8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:34:14 +0000 Subject: [PATCH 070/168] Fix alignment issues caused by renaming classes --- components/sceneutil/mwshadowtechnique.cpp | 2 +- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 5217b4832..e8543c8b4 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -200,7 +200,7 @@ class VDSMCameraCullCallback : public osg::NodeCallback protected: - MWShadowTechnique* _vdsm; + MWShadowTechnique* _vdsm; osg::ref_ptr _projectionMatrix; osg::ref_ptr _renderStage; osg::Polytope _polytope; diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index efbf2ed5c..e7465ff39 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -144,7 +144,7 @@ namespace SceneUtil { protected: virtual ~ViewDependentData() {} - MWShadowTechnique* _viewDependentShadowMap; + MWShadowTechnique* _viewDependentShadowMap; osg::ref_ptr _stateset; From 4c31b38f773b8252262f29961d51c1d856eadad7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 14:58:12 +0000 Subject: [PATCH 071/168] Move CLSB changes to new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 179 +++++++++++---------- components/sceneutil/mwshadowtechnique.hpp | 27 ++++ 2 files changed, 117 insertions(+), 89 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e8543c8b4..522172f42 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -293,122 +293,123 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) } } - -class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack +MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { -public: - ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix): - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) - { - setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); + setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); - pushViewport(viewport); - pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); - pushModelViewMatrix(new osg::RefMatrix(viewMatrix),osg::Transform::ABSOLUTE_RF); - } + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); +} - void apply(osg::Node& node) - { - if (isCulled(node)) return; +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Node& node) +{ + if (isCulled(node)) return; - // push the culling mode. - pushCurrentMask(); + // push the culling mode. + pushCurrentMask(); - traverse(node); + traverse(node); - // pop the culling mode. - popCurrentMask(); - } + // pop the culling mode. + popCurrentMask(); +} - void apply(osg::Drawable& drawable) - { - if (isCulled(drawable)) return; +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) +{ + if (isCulled(drawable)) return; - // push the culling mode. - pushCurrentMask(); + // push the culling mode. + pushCurrentMask(); - updateBound(drawable.getBoundingBox()); + updateBound(drawable.getBoundingBox()); - // pop the culling mode. - popCurrentMask(); - } + // pop the culling mode. + popCurrentMask(); +} - void apply(osg::Billboard&) - { - OSG_INFO<<"Warning Billboards not yet supported"< matrix = new osg::RefMatrix(*getModelViewMatrix()); - transform.computeLocalToWorldMatrix(*matrix,this); - pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Transform& transform) +{ + if (isCulled(transform)) return; - traverse(transform); + // push the culling mode. + pushCurrentMask(); - popModelViewMatrix(); - } + // absolute transforms won't affect a shadow map so their subgraphs should be ignored. + if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) + { + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - // pop the culling mode. - popCurrentMask(); + traverse(transform); + popModelViewMatrix(); } - void apply(osg::Camera&) - { - // camera nodes won't affect a shadow map so their subgraphs should be ignored - return; - } + // pop the culling mode. + popCurrentMask(); - void updateBound(const osg::BoundingBox& bb) - { - if (!bb.valid()) return; +} - const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Camera&) +{ + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; +} - update(bb.corner(0) * matrix); - update(bb.corner(1) * matrix); - update(bb.corner(2) * matrix); - update(bb.corner(3) * matrix); - update(bb.corner(4) * matrix); - update(bb.corner(5) * matrix); - update(bb.corner(6) * matrix); - update(bb.corner(7) * matrix); - } +void MWShadowTechnique::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) +{ + if (!bb.valid()) return; + + const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); + + update(bb.corner(0) * matrix); + update(bb.corner(1) * matrix); + update(bb.corner(2) * matrix); + update(bb.corner(3) * matrix); + update(bb.corner(4) * matrix); + update(bb.corner(5) * matrix); + update(bb.corner(6) * matrix); + update(bb.corner(7) * matrix); +} - void update(const osg::Vec3& v) +void MWShadowTechnique::ComputeLightSpaceBounds::update(const osg::Vec3& v) +{ + if (v.z()<-1.0f) { - if (v.z()<-1.0f) - { - //OSG_NOTICE<<"discarding("<1.0f) x=1.0f; - float y = v.y(); - if (y<-1.0f) y=-1.0f; - if (y>1.0f) y=1.0f; - _bb.expandBy(osg::Vec3(x,y,v.z())); + //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; + float y = v.y(); + if (y<-1.0f) y = -1.0f; + if (y>1.0f) y = 1.0f; + _bb.expandBy(osg::Vec3(x, y, v.z())); +} /////////////////////////////////////////////////////////////////////////////////////////////// // diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index e7465ff39..7cf7db155 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -27,6 +27,8 @@ #include +#include + namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ @@ -59,6 +61,31 @@ namespace SceneUtil { /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ virtual void cleanSceneGraph(); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack + { + public: + ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + + void apply(osg::Node& node); + + void apply(osg::Drawable& drawable); + + void apply(Terrain::QuadTreeWorld& quadTreeWorld); + + void apply(osg::Billboard&); + + void apply(osg::Projection&); + + void apply(osg::Transform& transform); + + void apply(osg::Camera&); + + void updateBound(const osg::BoundingBox& bb); + + void update(const osg::Vec3& v); + + osg::BoundingBox _bb; + }; struct OSGSHADOW_EXPORT Frustum { From 0f1e770c53d3216bfa7a562852263fb14155713e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 15:51:22 +0000 Subject: [PATCH 072/168] Transfer changes to cull to new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 94 ++++++++++++++++++++-- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 522172f42..1b390e33b 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -769,6 +769,12 @@ void MWShadowTechnique::update(osg::NodeVisitor& nv) void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) { + /* TODO: if (!enableShadows) + { + _shadowedScene->osg::Group::traverse(cv); + return; + }*/ + OSG_INFO<(cv.getCalculatedNearPlane(), minZNear); + reducedFar = osg::minimum(cv.getCalculatedFarPlane(), maxZFar); + } + else + { + reducedNear = minZNear; + reducedFar = maxZFar; + } + // return compute near far mode back to it's original settings cv.setComputeNearFarMode(cachedNearFarMode); @@ -868,11 +886,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) previous_sdl.swap(sdl); unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight(); - if (numShadowMapsPerLight>2) - { - OSG_NOTICE<<"numShadowMapsPerLight of "<getLightDataList(); for(LightDataList::iterator itr = pll.begin(); @@ -943,6 +956,20 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double yMid = (clsb._bb.yMin()+clsb._bb.yMax())*0.5f; double yRange = (clsb._bb.yMax()-clsb._bb.yMin()); + osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); + double minZ = DBL_MAX; + double maxZ = -DBL_MAX; + for (unsigned int i = 0; i < 8; i++) + { + osg::Vec3 corner = clsb._bb.corner(i); + corner = corner * cornerConverter; + + maxZ = osg::maximum(maxZ, -corner.z()); + minZ = osg::minimum(minZ, -corner.z()); + } + reducedNear = osg::maximum(reducedNear, minZ); + reducedFar = osg::minimum(reducedFar, maxZ); + // OSG_NOTICE<<" xMid="< Date: Mon, 26 Feb 2018 16:25:44 +0000 Subject: [PATCH 073/168] Make shadows disableable. --- components/sceneutil/mwshadowtechnique.cpp | 14 ++++++++++++-- components/sceneutil/mwshadowtechnique.hpp | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 1b390e33b..23ff2e7a9 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -745,6 +745,16 @@ void MWShadowTechnique::cleanSceneGraph() OSG_INFO<<"MWShadowTechnique::cleanSceneGraph()"<osg::Group::traverse(cv); return; - }*/ + } OSG_INFO< _program; + + bool _enableShadows; }; } From 5d719e9d5fa721847b227ad75685f173490319cc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:20:01 +0000 Subject: [PATCH 074/168] Add the debug HUD to the new shadow technique --- components/sceneutil/mwshadowtechnique.cpp | 71 +++++++++++++++++----- components/sceneutil/mwshadowtechnique.hpp | 21 +++++++ 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 23ff2e7a9..e99d9d692 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -1043,21 +1043,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) previous_sdl.erase(previous_sdl.begin()); } - /* TODO: if (debugHud) - { - osg::ref_ptr texture = sd->_texture; - osg::ref_ptr stateSet = debugGeometry[sm_i]->getOrCreateStateSet(); - stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); - - unsigned int traversalMask = cv.getTraversalMask(); - cv.setTraversalMask(debugGeometry[sm_i]->getNodeMask()); - cv.pushStateSet(stateSet); - debugCameras[sm_i]->accept(cv); - cv.popStateSet(); - cv.setTraversalMask(traversalMask); - - cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); - }*/ + if (_debugHud) + _debugHud->draw(sd->_texture, sm_i, cv); osg::ref_ptr camera = sd->_camera; @@ -2566,4 +2553,56 @@ void MWShadowTechnique::releaseGLObjects(osg::State* state) const vdd->releaseGLObjects(state); } } + if (_debugHud) + _debugHud->releaseGLObjects(state); +} + +SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) +{ + osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); + mDebugProgram->addShader(vertexShader); + osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); + mDebugProgram->addShader(fragmentShader); + + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + { + mDebugCameras.push_back(new osg::Camera); + mDebugCameras[i]->setViewport(200 * i, 0, 200, 200); + mDebugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); + mDebugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + mDebugGeometry[i]->setCullingActive(false); + mDebugCameras[i]->addChild(mDebugGeometry[i]); + osg::ref_ptr stateSet = mDebugGeometry[i]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(mDebugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); + } +} + +void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv) +{ + osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); + stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); + + // Some of these calls may be superfluous. + unsigned int traversalMask = cv.getTraversalMask(); + cv.setTraversalMask(mDebugGeometry[shadowMapNumber]->getNodeMask()); + cv.pushStateSet(stateSet); + mDebugCameras[shadowMapNumber]->accept(cv); + cv.popStateSet(); + cv.setTraversalMask(traversalMask); + + // cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); +} + +void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) const +{ + for (auto const& camera : mDebugCameras) + camera->releaseGLObjects(state); + mDebugProgram->releaseGLObjects(state); + for (auto const& node : mDebugGeometry) + node->releaseGLObjects(state); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 4b83e6bb7..7494b02be 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -227,6 +227,27 @@ namespace SceneUtil { osg::ref_ptr _program; bool _enableShadows; + + // TODO: actually construct this + class DebugHUD : public osg::Referenced + { + public: + DebugHUD(int numberOfShadowMapsPerLight); + + void draw(); + + virtual void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv); + + virtual void releaseGLObjects(osg::State* state = 0) const; + protected: + static const int sDebugTextureUnit; + + std::vector> mDebugCameras; + osg::ref_ptr mDebugProgram; + std::vector> mDebugGeometry; + }; + + osg::ref_ptr _debugHud; }; } From 7b52091a82ab8d23d3673c305344c2351f8bdae9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:36:43 +0000 Subject: [PATCH 075/168] Make the debug hud enableable --- components/sceneutil/mwshadowtechnique.cpp | 10 ++++++++++ components/sceneutil/mwshadowtechnique.hpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e99d9d692..dc64204a3 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -755,6 +755,16 @@ void MWShadowTechnique::enableShadows() _enableShadows = false; } +void SceneUtil::MWShadowTechnique::enableDebugHUD() +{ + _debugHud = new DebugHUD(getShadowedScene()->getShadowSettings()->getNumShadowMapsPerLight()); +} + +void SceneUtil::MWShadowTechnique::disableDebugHUD() +{ + _debugHud = nullptr; +} + MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) { return new ViewDependentData(this); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 7494b02be..cd5a71f92 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -65,6 +65,10 @@ namespace SceneUtil { virtual void disableShadows(); + virtual void enableDebugHUD(); + + virtual void disableDebugHUD(); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: From 478367bef328109e57f4fa169673488a8f18a79c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:50:54 +0000 Subject: [PATCH 076/168] Ensure the debug HUD won't crash if settings are changed at runtime. --- components/sceneutil/mwshadowtechnique.cpp | 39 +++++++++++++--------- components/sceneutil/mwshadowtechnique.hpp | 2 ++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index dc64204a3..01e65bc36 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2575,25 +2575,15 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) mDebugProgram->addShader(fragmentShader); for (int i = 0; i < numberOfShadowMapsPerLight; ++i) - { - mDebugCameras.push_back(new osg::Camera); - mDebugCameras[i]->setViewport(200 * i, 0, 200, 200); - mDebugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); - mDebugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - - mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); - mDebugGeometry[i]->setCullingActive(false); - mDebugCameras[i]->addChild(mDebugGeometry[i]); - osg::ref_ptr stateSet = mDebugGeometry[i]->getOrCreateStateSet(); - stateSet->setAttributeAndModes(mDebugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); - } + addAnotherShadowMap(); } void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv) { + // It might be possible to change shadow settings at runtime + if (shadowMapNumber > mDebugCameras.size()) + addAnotherShadowMap(); + osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); @@ -2616,3 +2606,22 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) for (auto const& node : mDebugGeometry) node->releaseGLObjects(state); } + +void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() +{ + unsigned int shadowMapNumber = mDebugCameras.size(); + + mDebugCameras.push_back(new osg::Camera); + mDebugCameras[shadowMapNumber]->setViewport(200 * shadowMapNumber, 0, 200, 200); + mDebugCameras[shadowMapNumber]->setRenderOrder(osg::Camera::POST_RENDER); + mDebugCameras[shadowMapNumber]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + + mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); + mDebugGeometry[shadowMapNumber]->setCullingActive(false); + mDebugCameras[shadowMapNumber]->addChild(mDebugGeometry[shadowMapNumber]); + osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); + stateSet->setAttributeAndModes(mDebugProgram, osg::StateAttribute::ON); + osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); + //textureUniform->setType(osg::Uniform::SAMPLER_2D); + stateSet->addUniform(textureUniform.get()); +} diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index cd5a71f92..199babf6f 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -244,6 +244,8 @@ namespace SceneUtil { virtual void releaseGLObjects(osg::State* state = 0) const; protected: + virtual void addAnotherShadowMap(); + static const int sDebugTextureUnit; std::vector> mDebugCameras; From 639a4f5e8c87fd08ffb397f66cdb57f4ecce8abd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 20:52:19 +0000 Subject: [PATCH 077/168] Remove TODO left in by accident. Also, become 100 commits ahead of upstream. --- components/sceneutil/mwshadowtechnique.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 199babf6f..b1dcbfd31 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -232,7 +232,6 @@ namespace SceneUtil { bool _enableShadows; - // TODO: actually construct this class DebugHUD : public osg::Referenced { public: From 99db93510ce3e185cb43bc6bd86a79c63bc7de7b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 21:09:29 +0000 Subject: [PATCH 078/168] Undo minor cockup where the same file appeared twice --- components/sceneutil/mwshadowtechnique | 196 ------------------------- 1 file changed, 196 deletions(-) delete mode 100644 components/sceneutil/mwshadowtechnique diff --git a/components/sceneutil/mwshadowtechnique b/components/sceneutil/mwshadowtechnique deleted file mode 100644 index 63b80fed1..000000000 --- a/components/sceneutil/mwshadowtechnique +++ /dev/null @@ -1,196 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * OpenSceneGraph Public License for more details. -*/ - -#ifndef OSGSHADOW_VIEWDEPENDENTSHADOWMAP -#define OSGSHADOW_VIEWDEPENDENTSHADOWMAP 1 - -#include -#include -#include -#include -#include - -#include - -namespace osgShadow { - -/** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ -class OSGSHADOW_EXPORT ViewDependentShadowMap : public ShadowTechnique -{ - public : - ViewDependentShadowMap(); - - ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); - - META_Object(osgShadow, ViewDependentShadowMap); - - /** initialize the ShadowedScene and local cached data structures.*/ - virtual void init(); - - /** run the update traversal of the ShadowedScene and update any loca chached data structures.*/ - virtual void update(osg::NodeVisitor& nv); - - /** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/ - virtual void cull(osgUtil::CullVisitor& cv); - - /** Resize any per context GLObject buffers to specified size. */ - virtual void resizeGLObjectBuffers(unsigned int maxSize); - - /** If State is non-zero, this function releases any associated OpenGL objects for - * the specified graphics context. Otherwise, releases OpenGL objects - * for all graphics contexts. */ - virtual void releaseGLObjects(osg::State* = 0) const; - - /** Clean scene graph from any shadow technique specific nodes, state and drawables.*/ - virtual void cleanSceneGraph(); - - - struct OSGSHADOW_EXPORT Frustum - { - Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); - - osg::Matrixd projectionMatrix; - osg::Matrixd modelViewMatrix; - - typedef std::vector Vertices; - Vertices corners; - - typedef std::vector Indices; - typedef std::vector Faces; - Faces faces; - - typedef std::vector Edges; - Edges edges; - - osg::Vec3d eye; - osg::Vec3d centerNearPlane; - osg::Vec3d centerFarPlane; - osg::Vec3d center; - osg::Vec3d frustumCenterLine; - }; - - // forward declare - class ViewDependentData; - - struct OSGSHADOW_EXPORT LightData : public osg::Referenced - { - LightData(ViewDependentData* vdd); - - virtual void setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix); - - ViewDependentData* _viewDependentData; - - osg::ref_ptr lightMatrix; - osg::ref_ptr light; - - osg::Vec4d lightPos; - osg::Vec3d lightPos3; - osg::Vec3d lightDir; - bool directionalLight; - - typedef std::vector ActiveTextureUnits; - ActiveTextureUnits textureUnits; - }; - - typedef std::list< osg::ref_ptr > LightDataList; - - struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced - { - ShadowData(ViewDependentData* vdd); - - virtual void releaseGLObjects(osg::State* = 0) const; - - ViewDependentData* _viewDependentData; - - unsigned int _textureUnit; - osg::ref_ptr _texture; - osg::ref_ptr _texgen; - osg::ref_ptr _camera; - }; - - typedef std::list< osg::ref_ptr > ShadowDataList; - - - class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced - { - public: - ViewDependentData(ViewDependentShadowMap* vdsm); - - const ViewDependentShadowMap* getViewDependentShadowMap() const { return _viewDependentShadowMap; } - - LightDataList& getLightDataList() { return _lightDataList; } - - ShadowDataList& getShadowDataList() { return _shadowDataList; } - - osg::StateSet* getStateSet() { return _stateset.get(); } - - virtual void releaseGLObjects(osg::State* = 0) const; - - protected: - virtual ~ViewDependentData() {} - - ViewDependentShadowMap* _viewDependentShadowMap; - - osg::ref_ptr _stateset; - - LightDataList _lightDataList; - ShadowDataList _shadowDataList; - }; - - virtual ViewDependentData* createViewDependentData(osgUtil::CullVisitor* cv); - - ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv); - - - - virtual void createShaders(); - - virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; - - virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight); - - virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); - - virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera); - - virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); - - virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; - - virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; - - virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd) const; - -protected: - virtual ~ViewDependentShadowMap(); - - typedef std::map< osgUtil::CullVisitor*, osg::ref_ptr > ViewDependentDataMap; - mutable OpenThreads::Mutex _viewDependentDataMapMutex; - ViewDependentDataMap _viewDependentDataMap; - - osg::ref_ptr _shadowRecievingPlaceholderStateSet; - - osg::ref_ptr _shadowCastingStateSet; - osg::ref_ptr _polygonOffset; - osg::ref_ptr _fallbackBaseTexture; - osg::ref_ptr _fallbackShadowMapTexture; - - typedef std::vector< osg::ref_ptr > Uniforms; - mutable OpenThreads::Mutex _accessUniformsAndProgramMutex; - Uniforms _uniforms; - osg::ref_ptr _program; -}; - -} - -#endif From 97b607fc663afc964db8b6e69cd74516a495636c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 21:10:06 +0000 Subject: [PATCH 079/168] Make whitespace match upstream OSG --- components/sceneutil/mwshadowtechnique.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index b1dcbfd31..797266287 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -4,16 +4,16 @@ */ /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield -* -* This library is open source and may be redistributed and/or modified under -* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or -* (at your option) any later version. The full license is in LICENSE file -* included with this distribution, and on the openscenegraph.org website. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* OpenSceneGraph Public License for more details. + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. */ #ifndef COMPONENTS_SCENEUTIL_MWSHADOWTECHNIQUE_H From e233dae1cd2cf87e03ac219c4c9572b5453580e7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 22:27:09 +0000 Subject: [PATCH 080/168] Hook up the new shadow technique --- apps/openmw/mwrender/renderingmanager.cpp | 12 +- apps/openmw/mwrender/renderingmanager.hpp | 2 + components/sceneutil/mwshadowtechnique.cpp | 8 +- components/sceneutil/mwshadowtechnique.hpp | 12 +- components/sceneutil/shadow.cpp | 817 +-------------------- components/sceneutil/shadow.hpp | 52 +- components/terrain/quadtreeworld.cpp | 4 +- 7 files changed, 46 insertions(+), 861 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a59ba8c1a..920c7278c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -202,8 +202,6 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - osg::ref_ptr shadowedScene (new osgShadow::ShadowedScene); - int shadowCastingTraversalMask = Mask_Scene; if (Settings::Manager::getBool("actor shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Actor; @@ -211,15 +209,11 @@ namespace MWRender shadowCastingTraversalMask |= Mask_Player; if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - SceneUtil::ShadowManager::setupShadowSettings(shadowedScene->getShadowSettings(), shadowCastingTraversalMask); - SceneUtil::ShadowManager* tech = new SceneUtil::ShadowManager(); - shadowedScene->setShadowTechnique(tech); - - shadowedScene->addChild(sceneRoot); - mRootNode->addChild(shadowedScene); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode)); + mShadowManager->setupShadowSettings(shadowCastingTraversalMask); - Shader::ShaderManager::DefineMap shadowDefines = tech->getShadowDefines(); + Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0087e43d..d322bfaf4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -50,6 +50,7 @@ namespace Fallback namespace SceneUtil { + class ShadowManager; class WorkQueue; class UnrefQueue; } @@ -234,6 +235,7 @@ namespace MWRender TerrainStorage* mTerrainStorage; std::unique_ptr mSky; std::unique_ptr mEffectManager; + std::unique_ptr mShadowManager; osg::ref_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; std::unique_ptr mCamera; diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 01e65bc36..123030b25 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -713,7 +713,9 @@ void MWShadowTechnique::ViewDependentData::releaseGLObjects(osg::State* state) c // MWShadowTechnique // MWShadowTechnique::MWShadowTechnique(): - ShadowTechnique() + ShadowTechnique(), + _enableShadows(false), + _debugHud(nullptr) { _shadowRecievingPlaceholderStateSet = new osg::StateSet; } @@ -750,7 +752,7 @@ void MWShadowTechnique::enableShadows() _enableShadows = true; } -void MWShadowTechnique::enableShadows() +void MWShadowTechnique::disableShadows() { _enableShadows = false; } @@ -2567,7 +2569,7 @@ void MWShadowTechnique::releaseGLObjects(osg::State* state) const _debugHud->releaseGLObjects(state); } -SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) +SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) : mDebugProgram(new osg::Program) { osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); mDebugProgram->addShader(vertexShader); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 797266287..41f1d7c32 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -32,7 +32,7 @@ namespace SceneUtil { /** ViewDependentShadowMap provides an base implementation of view dependent shadow mapping techniques.*/ - class OSGSHADOW_EXPORT MWShadowTechnique : public osgShadow::ShadowTechnique + class MWShadowTechnique : public osgShadow::ShadowTechnique { public: MWShadowTechnique(); @@ -95,7 +95,7 @@ namespace SceneUtil { osg::BoundingBox _bb; }; - struct OSGSHADOW_EXPORT Frustum + struct Frustum { Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar); @@ -122,7 +122,7 @@ namespace SceneUtil { // forward declare class ViewDependentData; - struct OSGSHADOW_EXPORT LightData : public osg::Referenced + struct LightData : public osg::Referenced { LightData(ViewDependentData* vdd); @@ -144,7 +144,7 @@ namespace SceneUtil { typedef std::list< osg::ref_ptr > LightDataList; - struct OSGSHADOW_EXPORT ShadowData : public osg::Referenced + struct ShadowData : public osg::Referenced { ShadowData(ViewDependentData* vdd); @@ -161,7 +161,7 @@ namespace SceneUtil { typedef std::list< osg::ref_ptr > ShadowDataList; - class OSGSHADOW_EXPORT ViewDependentData : public osg::Referenced + class ViewDependentData : public osg::Referenced { public: ViewDependentData(MWShadowTechnique* vdsm); @@ -245,7 +245,7 @@ namespace SceneUtil { protected: virtual void addAnotherShadowMap(); - static const int sDebugTextureUnit; + static const int sDebugTextureUnit = 0; std::vector> mDebugCameras; osg::ref_ptr mDebugProgram; diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 8c729e3cc..8c58cb603 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -13,48 +13,17 @@ namespace SceneUtil { using namespace osgShadow; - std::string debugVertexShaderSource = "void main(void){gl_Position = gl_Vertex; gl_TexCoord[0]=gl_MultiTexCoord0;}"; - std::string debugFragmentShaderSource = - "uniform sampler2D texture; \n" - " \n" - "void main(void) \n" - "{ \n" -#if 1 - " float f = texture2D( texture, gl_TexCoord[0].xy ).r; \n" - " \n" - " f = 256.0 * f; \n" - " float fC = floor( f ) / 256.0; \n" - " \n" - " f = 256.0 * fract( f ); \n" - " float fS = floor( f ) / 256.0; \n" - " \n" - " f = 256.0 * fract( f ); \n" - " float fH = floor( f ) / 256.0; \n" - " \n" - " fS *= 0.5; \n" - " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" - " \n" - " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" - " abs( fC - 0.333333 ), \n" - " abs( fC - 0.666667 ) ); \n" - " \n" - " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" - " \n" - " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" - " fMax = 1.0 / fMax; \n" - " \n" - " vec3 color = fMax * rgb; \n" - " \n" - " gl_FragColor = vec4( fS + fH * color, 1 ); \n" -#else - " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" -#endif - "} \n"; - - void ShadowManager::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) + void ShadowManager::setupShadowSettings(int castsShadowMask) { if (!Settings::Manager::getBool("enable shadows", "Shadows")) + { + mShadowTechnique->disableShadows(); return; + } + else + mShadowTechnique->enableShadows(); + + osg::ref_ptr settings = mShadowedScene->getShadowSettings(); settings->setLightNum(0); settings->setCastsShadowTraversalMask(castsShadowMask); @@ -70,6 +39,11 @@ namespace SceneUtil int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); settings->setTextureSize(osg::Vec2s(mapres, mapres)); + + if (Settings::Manager::getBool("enable debug hud", "Shadows")) + mShadowTechnique->enableDebugHUD(); + else + mShadowTechnique->disableDebugHUD(); } void ShadowManager::disableShadowsForStateSet(osg::ref_ptr stateset) @@ -87,768 +61,15 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager() : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), - debugHud(Settings::Manager::getBool("enable debug hud", "Shadows")), - debugProgram(new osg::Program), debugTextureUnit(0) - { - if (debugHud) - { - osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); - debugProgram->addShader(vertexShader); - osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); - debugProgram->addShader(fragmentShader); - - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) - { - std::cout << i << std::endl; - - debugCameras.push_back(new osg::Camera); - debugCameras[i]->setViewport(200 * i, 0, 200, 200); - debugCameras[i]->setRenderOrder(osg::Camera::POST_RENDER); - debugCameras[i]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); - - debugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); - debugGeometry[i]->setCullingActive(false); - debugCameras[i]->addChild(debugGeometry[i]); - osg::ref_ptr stateSet = debugGeometry[i]->getOrCreateStateSet(); - stateSet->setAttributeAndModes(debugProgram, osg::StateAttribute::ON); - osg::ref_ptr textureUniform = new osg::Uniform("texture", debugTextureUnit); - //textureUniform->setType(osg::Uniform::SAMPLER_2D); - stateSet->addUniform(textureUniform.get()); - } - } - } - - class VDSMCameraCullCallback : public osg::NodeCallback - { - public: - - VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope); - - virtual void operator()(osg::Node*, osg::NodeVisitor* nv); - - osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); } - osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); } - - protected: - - ViewDependentShadowMap* _vdsm; - osg::ref_ptr _projectionMatrix; - osg::ref_ptr _renderStage; - osg::Polytope _polytope; - }; - - VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope) : - _vdsm(vdsm), - _polytope(polytope) - { - } - - void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = dynamic_cast(nv); - osg::Camera* camera = dynamic_cast(node); - OSG_INFO << "VDSMCameraCullCallback::operator()(osg::Node* " << camera << ", osg::NodeVisitor* " << cv << ")" << std::endl; - -#if 1 - if (!_polytope.empty()) - { - OSG_INFO << "Pushing custom Polytope" << std::endl; - - osg::CullingSet& cs = cv->getProjectionCullingStack().back(); - - cs.setFrustum(_polytope); - - cv->pushCullingSet(); - } -#endif - if (_vdsm->getShadowedScene()) - { - _vdsm->getShadowedScene()->osg::Group::traverse(*nv); - } -#if 1 - if (!_polytope.empty()) - { - OSG_INFO << "Popping custom Polytope" << std::endl; - cv->popCullingSet(); - } -#endif - - _renderStage = cv->getCurrentRenderBin()->getStage(); - - OSG_INFO << "VDSM second : _renderStage = " << _renderStage << std::endl; - - if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - // make sure that the near plane is computed correctly. - cv->computeNearPlane(); - - osg::Matrixd projection = *(cv->getProjectionMatrix()); - - OSG_INFO << "RTT Projection matrix " << projection << std::endl; - - osg::Matrix::value_type left, right, bottom, top, zNear, zFar; - osg::Matrix::value_type epsilon = 1e-6; - if (fabs(projection(0, 3))setProjectionMatrix(projection); - - _projectionMatrix = cv->getProjectionMatrix(); - } - } - - ShadowManager::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) - { - setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING); - - pushViewport(viewport); - pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); - pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Node& node) - { - if (isCulled(node)) return; - - // push the culling mode. - pushCurrentMask(); - - traverse(node); - - // pop the culling mode. - popCurrentMask(); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Geode& node) - { - if (isCulled(node)) return; - - // push the culling mode. - pushCurrentMask(); - - for (unsigned int i = 0; igetBoundingBox()); - } - } - - // pop the culling mode. - popCurrentMask(); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) + mShadowedScene(new osgShadow::ShadowedScene), + mShadowTechnique(new MWShadowTechnique) { - if (isCulled(drawable)) return; - - // push the culling mode. - pushCurrentMask(); - - updateBound(drawable.getBoundingBox()); - - // pop the culling mode. - popCurrentMask(); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(Terrain::QuadTreeWorld & quadTreeWorld) - { - // For now, just expand the bounds fully as terrain will fill them up and possible ways to detect which terrain definitely won't cast shadows aren't implemented. - - update(osg::Vec3(-1.0, -1.0, 0.0)); - update(osg::Vec3(1.0, 1.0, 0.0)); - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Billboard&) - { - OSG_INFO << "Warning Billboards not yet supported" << std::endl; - return; - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Projection&) - { - // projection nodes won't affect a shadow map so their subgraphs should be ignored - return; - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Transform& transform) - { - if (isCulled(transform)) return; - - // push the culling mode. - pushCurrentMask(); - - // absolute transforms won't affect a shadow map so their subgraphs should be ignored. - if (transform.getReferenceFrame() == osg::Transform::RELATIVE_RF) - { - osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); - transform.computeLocalToWorldMatrix(*matrix, this); - pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - - traverse(transform); - - popModelViewMatrix(); - } - - // pop the culling mode. - popCurrentMask(); - - } - - void ShadowManager::ComputeLightSpaceBounds::apply(osg::Camera&) - { - // camera nodes won't affect a shadow map so their subgraphs should be ignored - return; - } - - void ShadowManager::ComputeLightSpaceBounds::updateBound(const osg::BoundingBox& bb) - { - if (!bb.valid()) return; - - const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); - - update(bb.corner(0) * matrix); - update(bb.corner(1) * matrix); - update(bb.corner(2) * matrix); - update(bb.corner(3) * matrix); - update(bb.corner(4) * matrix); - update(bb.corner(5) * matrix); - update(bb.corner(6) * matrix); - update(bb.corner(7) * matrix); - } - - void ShadowManager::ComputeLightSpaceBounds::update(const osg::Vec3& v) - { - if (v.z()<-1.0f) - { - //OSG_NOTICE<<"discarding("<1.0f) x = 1.0f; - float y = v.y(); - if (y<-1.0f) y = -1.0f; - if (y>1.0f) y = 1.0f; - _bb.expandBy(osg::Vec3(x, y, v.z())); - } - - void ShadowManager::cull(osgUtil::CullVisitor& cv) - { - if (!enableShadows) - { - _shadowedScene->osg::Group::traverse(cv); - return; - } - - OSG_INFO << std::endl << std::endl << "ViewDependentShadowMap::cull(osg::CullVisitor&" << &cv << ")" << std::endl; - - if (!_shadowCastingStateSet) - { - OSG_INFO << "Warning, init() has not yet been called so ShadowCastingStateSet has not been setup yet, unable to create shadows." << std::endl; - _shadowedScene->osg::Group::traverse(cv); - return; - } - - ViewDependentData* vdd = getViewDependentData(&cv); - - if (!vdd) - { - OSG_INFO << "Warning, now ViewDependentData created, unable to create shadows." << std::endl; - _shadowedScene->osg::Group::traverse(cv); - return; - } - - ShadowSettings* settings = getShadowedScene()->getShadowSettings(); - - OSG_INFO << "cv->getProjectionMatrix()=" << *cv.getProjectionMatrix() << std::endl; - - osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode(); - - osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix(); - - // check whether this main views projection is perspective or orthographic - bool orthographicViewFrustum = viewProjectionMatrix(0, 3) == 0.0 && - viewProjectionMatrix(1, 3) == 0.0 && - viewProjectionMatrix(2, 3) == 0.0; - - double minZNear = 0.0; - double maxZFar = DBL_MAX; - - if (cachedNearFarMode == osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - double left, right, top, bottom; - if (orthographicViewFrustum) - { - viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar); - } - else - { - viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar); - } - OSG_INFO << "minZNear=" << minZNear << ", maxZFar=" << maxZFar << std::endl; - } - - // set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible - if (settings->getComputeNearFarModeOverride() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride()); - } - - // 1. Traverse main scene graph - cv.pushStateSet(_shadowRecievingPlaceholderStateSet.get()); - - osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); - - cullShadowReceivingScene(&cv); - - cv.popStateSet(); - - if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) - { - OSG_INFO << "Just done main subgraph traversak" << std::endl; - // make sure that the near plane is computed correctly so that any projection matrix computations - // are all done correctly. - cv.computeNearPlane(); - } - - // clamp the minZNear and maxZFar to those provided by ShadowSettings - maxZFar = osg::minimum(settings->getMaximumShadowMapDistance(), maxZFar); - if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio(); - - //OSG_NOTICE<<"maxZFar "<(cv.getCalculatedNearPlane(), minZNear); - reducedFar = osg::minimum(cv.getCalculatedFarPlane(), maxZFar); - } - else - { - reducedNear = minZNear; - reducedFar = maxZFar; - } - - // return compute near far mode back to it's original settings - cv.setComputeNearFarMode(cachedNearFarMode); - - OSG_INFO << "frustum.eye=" << frustum.eye << ", frustum.centerNearPlane, " << frustum.centerNearPlane << " distance = " << (frustum.eye - frustum.centerNearPlane).length() << std::endl; - - - // 2. select active light sources - // create a list of light sources + their matrices to place them - selectActiveLights(&cv, vdd); - - - unsigned int pos_x = 0; - unsigned int textureUnit = settings->getBaseShadowTextureUnit(); - unsigned int numValidShadows = 0; - - ShadowDataList& sdl = vdd->getShadowDataList(); - ShadowDataList previous_sdl; - previous_sdl.swap(sdl); - - unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight(); - /*if (numShadowMapsPerLight>2) - { - OSG_NOTICE << "numShadowMapsPerLight of " << numShadowMapsPerLight << " is greater than maximum supported, falling back to 2." << std::endl; - numShadowMapsPerLight = 2; - }*/ - - LightDataList& pll = vdd->getLightDataList(); - for (LightDataList::iterator itr = pll.begin(); - itr != pll.end(); - ++itr) - { - // 3. create per light/per shadow map division of lightspace/frustum - // create a list of light/shadow map data structures - - LightData& pl = **itr; - - // 3.1 compute light space polytope - // - osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); - - // if polytope is empty then no rendering. - if (polytope.empty()) - { - OSG_NOTICE << "Polytope empty no shadow to render" << std::endl; - continue; - } - - // 3.2 compute RTT camera view+projection matrix settings - // - osg::Matrixd projectionMatrix; - osg::Matrixd viewMatrix; - if (!computeShadowCameraSettings(frustum, pl, projectionMatrix, viewMatrix)) - { - OSG_NOTICE << "No valid Camera settings, no shadow to render" << std::endl; - continue; - } - - // if we are using multiple shadow maps and CastShadowTraversalMask is being used - // traverse the scene to compute the extents of the objects - if (/*numShadowMapsPerLight>1 &&*/ _shadowedScene->getCastsShadowTraversalMask() != 0xffffffff) - { - // osg::ElapsedTime timer; - - osg::ref_ptr viewport = new osg::Viewport(0, 0, 2048, 2048); - ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); - clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); - - osg::Matrixd invertModelView; - invertModelView.invert(viewMatrix); - osg::Polytope local_polytope(polytope); - local_polytope.transformProvidingInverse(invertModelView); - - osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); - cs.setFrustum(local_polytope); - clsb.pushCullingSet(); - - _shadowedScene->accept(clsb); - - // OSG_NOTICE<<"Extents of LightSpace "<(maxZ, -corner.z()); - minZ = osg::minimum(minZ, -corner.z()); - } - reducedNear = osg::maximum(reducedNear, minZ); - reducedFar = osg::minimum(reducedFar, maxZ); - - // OSG_NOTICE<<" xMid="< texture = sd->_texture; - osg::ref_ptr stateSet = debugGeometry[sm_i]->getOrCreateStateSet(); - stateSet->setTextureAttributeAndModes(debugTextureUnit, texture, osg::StateAttribute::ON); - - unsigned int traversalMask = cv.getTraversalMask(); - cv.setTraversalMask(debugGeometry[sm_i]->getNodeMask()); - cv.pushStateSet(stateSet); - debugCameras[sm_i]->accept(cv); - cv.popStateSet(); - cv.setTraversalMask(traversalMask); - - cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); - } - - osg::ref_ptr camera = sd->_camera; - - camera->setProjectionMatrix(projectionMatrix); - camera->setViewMatrix(viewMatrix); - - if (settings->getDebugDraw()) - { - camera->getViewport()->x() = pos_x; - pos_x += static_cast(camera->getViewport()->width()) + 40; - } - - // transform polytope in model coords into light spaces eye coords. - osg::Matrixd invertModelView; - invertModelView.invert(camera->getViewMatrix()); - - osg::Polytope local_polytope(polytope); - local_polytope.transformProvidingInverse(invertModelView); - - - if (numShadowMapsPerLight>1) - { - // compute the start and end range in non-dimensional coords -#if 0 - double r_start = (sm_i == 0) ? -1.0 : (double(sm_i) / double(numShadowMapsPerLight)*2.0 - 1.0); - double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : (double(sm_i + 1) / double(numShadowMapsPerLight)*2.0 - 1.0); -#elif 0 - - // hardwired for 2 splits - double r_start = (sm_i == 0) ? -1.0 : splitPoint; - double r_end = (sm_i + 1 == numShadowMapsPerLight) ? 1.0 : splitPoint; -#elif 0 - double r_start, r_end; - // Split such that each shadow map covers a quarter of the area of the one after it - if (sm_i == 0) - r_start = -1.0; - else - { - r_start = (1 - pow(4.0, sm_i)) / (1 - pow(4.0, numShadowMapsPerLight)); - r_start *= 2.0; - //r_start += double(sm_i) / double(numShadowMapsPerLight); - r_start -= 1.0; - } - - if (sm_i + 1 == numShadowMapsPerLight) - r_end = 1.0; - else - { - r_end = (1 - pow(4.0, sm_i + 1)) / (1 - pow(4.0, numShadowMapsPerLight)); - r_end *= 2.0; - //r_end += double(sm_i + 1) / double(numShadowMapsPerLight); - r_end -= 1.0; - } -#else - double r_start, r_end; - - // split system based on the original Parallel Split Shadow Maps paper. - double n = reducedNear; - double f = reducedFar; - double i = double(sm_i); - double m = double(numShadowMapsPerLight); - double ratio = Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"); - double deltaBias = Settings::Manager::getFloat("split point bias", "Shadows"); - if (sm_i == 0) - r_start = -1.0; - else - { - // compute the split point in main camera view - double ciLog = n * pow(f / n, i / m); - double ciUniform = n + (f - n) * i / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; - - // work out where this is in light space - osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; - osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; - r_start = lightSpacePos.y(); - } - - if (sm_i + 1 == numShadowMapsPerLight) - r_end = 1.0; - else - { - // compute the split point in main camera view - double ciLog = n * pow(f / n, (i + 1) / m); - double ciUniform = n + (f - n) * (i + 1) / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; - - // work out where this is in light space - osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; - osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; - r_end = lightSpacePos.y(); - } -#endif - - // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap - // to prevent a seam showing through between the shadowmaps - if (sm_i + 10) - { - // not the first shadowmap so insert a polytope to clip the scene from before r_start - - // plane in clip space coords - osg::Plane plane(0.0, 1.0, 0.0, -r_start); - - // transform into eye coords - plane.transformProvidingInverse(projectionMatrix); - local_polytope.getPlaneList().push_back(plane); - - //OSG_NOTICE<<"Adding r_start plane "<0) - { - decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd)); - } - - // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<setShadowTechnique(mShadowTechnique); + mShadowedScene->addChild(sceneRoot); + rootNode->addChild(mShadowedScene); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index cfe1a4f3f..5ac271185 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -2,69 +2,35 @@ #define COMPONENTS_SCENEUTIL_SHADOW_H #include -#include #include #include +#include "mwshadowtechnique.hpp" + namespace SceneUtil { - class ShadowManager : public osgShadow::ViewDependentShadowMap + class ShadowManager { public: - static void setupShadowSettings(osg::ref_ptr settings, int castsShadowMask); - static void disableShadowsForStateSet(osg::ref_ptr stateSet); - ShadowManager(); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode); - virtual void cull(osgUtil::CullVisitor& cv) override; + virtual void setupShadowSettings(int castsShadowMask); virtual Shader::ShaderManager::DefineMap getShadowDefines(); virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); - - class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack - { - public: - ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); - - void apply(osg::Node& node); - - void apply(osg::Geode& node); - - void apply(osg::Drawable& drawable); - - void apply(Terrain::QuadTreeWorld& quadTreeWorld); - - void apply(osg::Billboard&); - - void apply(osg::Projection&); - - void apply(osg::Transform& transform); - - void apply(osg::Camera&); - - void updateBound(const osg::BoundingBox& bb); - - void update(const osg::Vec3& v); - - osg::BoundingBox _bb; - }; protected: - const int debugTextureUnit; - - std::vector> debugCameras; - - osg::ref_ptr debugProgram; - - std::vector> debugGeometry; - const int numberOfShadowMapsPerLight; const bool enableShadows; - const bool debugHud; const int baseShadowTextureUnit; + + osg::ref_ptr mShadowedScene; + + osg::ref_ptr mShadowTechnique; }; } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 85c43ce1d..651b2cd24 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include "quadtreenode.hpp" #include "storage.hpp" @@ -347,7 +347,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) { - SceneUtil::ShadowManager::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); + SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); if (shadowBoundsVisitor) shadowBoundsVisitor->apply(*this); return; From 882b63cba97913f1b3f1897d4f3da8e485c65ca3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 23:00:46 +0000 Subject: [PATCH 081/168] Make split point control parameters configurable with the new shadow technique. --- components/sceneutil/mwshadowtechnique.cpp | 16 ++++++++++++---- components/sceneutil/mwshadowtechnique.hpp | 7 +++++++ components/sceneutil/shadow.cpp | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 123030b25..fbf0fc9d2 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -767,6 +767,16 @@ void SceneUtil::MWShadowTechnique::disableDebugHUD() _debugHud = nullptr; } +void SceneUtil::MWShadowTechnique::setSplitPointUniformLogarithmicRatio(double ratio) +{ + _splitPointUniformLogRatio = ratio; +} + +void SceneUtil::MWShadowTechnique::setSplitPointDeltaBias(double bias) +{ + _splitPointDeltaBias = bias; +} + MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) { return new ViewDependentData(this); @@ -1096,8 +1106,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double f = reducedFar; double i = double(sm_i); double m = double(numShadowMapsPerLight); - double ratio = 0.5; // TODO: Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"); - double deltaBias = 0.0; // TODO: Settings::Manager::getFloat("split point bias", "Shadows"); if (sm_i == 0) r_start = -1.0; else @@ -1105,7 +1113,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // compute the split point in main camera view double ciLog = n * pow(f / n, i / m); double ciUniform = n + (f - n) * i / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; + double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; @@ -1120,7 +1128,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // compute the split point in main camera view double ciLog = n * pow(f / n, (i + 1) / m); double ciUniform = n + (f - n) * (i + 1) / m; - double ci = ratio * ciLog + (1.0 - ratio) * ciUniform + deltaBias; + double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 41f1d7c32..1fad0eee5 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -69,6 +69,10 @@ namespace SceneUtil { virtual void disableDebugHUD(); + virtual void setSplitPointUniformLogarithmicRatio(double ratio); + + virtual void setSplitPointDeltaBias(double bias); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: @@ -232,6 +236,9 @@ namespace SceneUtil { bool _enableShadows; + double _splitPointUniformLogRatio = 0.5; + double _splitPointDeltaBias = 0.0; + class DebugHUD : public osg::Referenced { public: diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 8c58cb603..99cb71beb 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -40,6 +40,9 @@ namespace SceneUtil int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); settings->setTextureSize(osg::Vec2s(mapres, mapres)); + mShadowTechnique->setSplitPointUniformLogarithmicRatio(Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows")); + mShadowTechnique->setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); + if (Settings::Manager::getBool("enable debug hud", "Shadows")) mShadowTechnique->enableDebugHUD(); else From 35eb71052e8d6cb530f4380a2e57711369a328b8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Feb 2018 23:52:46 +0000 Subject: [PATCH 082/168] Tidy up the shadow manager --- components/sceneutil/shadow.cpp | 38 ++++++++++++++++----------------- components/sceneutil/shadow.hpp | 7 ++---- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 99cb71beb..9d25b5764 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -15,30 +15,30 @@ namespace SceneUtil void ShadowManager::setupShadowSettings(int castsShadowMask) { - if (!Settings::Manager::getBool("enable shadows", "Shadows")) + mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows"); + + if (!mEnableShadows) { mShadowTechnique->disableShadows(); return; } - else - mShadowTechnique->enableShadows(); - - osg::ref_ptr settings = mShadowedScene->getShadowSettings(); + + mShadowTechnique->enableShadows(); - settings->setLightNum(0); - settings->setCastsShadowTraversalMask(castsShadowMask); - settings->setReceivesShadowTraversalMask(~0u); + mShadowSettings->setLightNum(0); + mShadowSettings->setCastsShadowTraversalMask(castsShadowMask); + mShadowSettings->setReceivesShadowTraversalMask(~0u); int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); - settings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); - settings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); + mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); + mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); - settings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows")); + mShadowSettings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows")); if (Settings::Manager::getBool("compute tight scene bounds", "Shadows")) - settings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES); int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows"); - settings->setTextureSize(osg::Vec2s(mapres, mapres)); + mShadowSettings->setTextureSize(osg::Vec2s(mapres, mapres)); mShadowTechnique->setSplitPointUniformLogarithmicRatio(Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows")); mShadowTechnique->setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); @@ -64,25 +64,25 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : enableShadows(Settings::Manager::getBool("enable shadows", "Shadows")), - numberOfShadowMapsPerLight(Settings::Manager::getInt("number of shadow maps", "Shadows")), - baseShadowTextureUnit(8 - numberOfShadowMapsPerLight), - mShadowedScene(new osgShadow::ShadowedScene), + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : mShadowedScene(new osgShadow::ShadowedScene), mShadowTechnique(new MWShadowTechnique) { mShadowedScene->setShadowTechnique(mShadowTechnique); + mShadowedScene->addChild(sceneRoot); rootNode->addChild(mShadowedScene); + + mShadowSettings = mShadowedScene->getShadowSettings(); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() { - if (!enableShadows) + if (!mEnableShadows) return getShadowsDisabledDefines(); Shader::ShaderManager::DefineMap definesWithShadows; definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + for (int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 5ac271185..2936941ff 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -23,13 +23,10 @@ namespace SceneUtil virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); protected: - const int numberOfShadowMapsPerLight; - const bool enableShadows; - - const int baseShadowTextureUnit; + bool mEnableShadows; osg::ref_ptr mShadowedScene; - + osg::ref_ptr mShadowSettings; osg::ref_ptr mShadowTechnique; }; } From f9cf1ac94b7f436aaedf77f0898b8fdba4ca3e5b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 00:13:51 +0000 Subject: [PATCH 083/168] Separate indoor and outdoor shadow casting masks. --- apps/openmw/mwrender/renderingmanager.cpp | 9 ++++++--- components/sceneutil/shadow.cpp | 20 ++++++++++++++++---- components/sceneutil/shadow.hpp | 11 +++++++++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 920c7278c..5971de966 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -202,7 +202,7 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - int shadowCastingTraversalMask = Mask_Scene; + int shadowCastingTraversalMask = 0; if (Settings::Manager::getBool("actor shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Actor; if (Settings::Manager::getBool("player shadows", "Shadows")) @@ -210,8 +210,7 @@ namespace MWRender if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode)); - mShadowManager->setupShadowSettings(shadowCastingTraversalMask); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Scene | shadowCastingTraversalMask, shadowCastingTraversalMask)); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); @@ -462,6 +461,10 @@ namespace MWRender void RenderingManager::setSkyEnabled(bool enabled) { mSky->setEnabled(enabled); + if (enabled) + mShadowManager->enableOutdoorMode(); + else + mShadowManager->enableIndoorMode(); } bool RenderingManager::toggleRenderMode(RenderMode mode) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 9d25b5764..00e6b93a9 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -13,7 +13,7 @@ namespace SceneUtil { using namespace osgShadow; - void ShadowManager::setupShadowSettings(int castsShadowMask) + void ShadowManager::setupShadowSettings() { mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows"); @@ -26,7 +26,6 @@ namespace SceneUtil mShadowTechnique->enableShadows(); mShadowSettings->setLightNum(0); - mShadowSettings->setCastsShadowTraversalMask(castsShadowMask); mShadowSettings->setReceivesShadowTraversalMask(~0u); int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); @@ -64,8 +63,10 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode) : mShadowedScene(new osgShadow::ShadowedScene), - mShadowTechnique(new MWShadowTechnique) + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask) : mShadowedScene(new osgShadow::ShadowedScene), + mShadowTechnique(new MWShadowTechnique), + mOutdoorShadowCastingMask(outdoorShadowCastingMask), + mIndoorShadowCastingMask(indoorShadowCastingMask) { mShadowedScene->setShadowTechnique(mShadowTechnique); @@ -73,6 +74,9 @@ namespace SceneUtil rootNode->addChild(mShadowedScene); mShadowSettings = mShadowedScene->getShadowSettings(); + setupShadowSettings(); + + enableOutdoorMode(); } Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines() @@ -98,4 +102,12 @@ namespace SceneUtil return definesWithShadows; } + void ShadowManager::enableIndoorMode() + { + mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); + } + void ShadowManager::enableOutdoorMode() + { + mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); + } } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 2936941ff..61a564a2a 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -15,16 +15,23 @@ namespace SceneUtil public: static void disableShadowsForStateSet(osg::ref_ptr stateSet); - ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask); - virtual void setupShadowSettings(int castsShadowMask); + virtual void setupShadowSettings(); virtual Shader::ShaderManager::DefineMap getShadowDefines(); virtual Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); + + virtual void enableIndoorMode(); + + virtual void enableOutdoorMode(); protected: bool mEnableShadows; + unsigned int mOutdoorShadowCastingMask; + unsigned int mIndoorShadowCastingMask; + osg::ref_ptr mShadowedScene; osg::ref_ptr mShadowSettings; osg::ref_ptr mShadowTechnique; From 66a114d6ecb32a5112c3a3a2f1516954e41b3f4b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 14:15:06 +0000 Subject: [PATCH 084/168] Fix a couple of warnings --- components/sceneutil/shadow.cpp | 2 +- components/sceneutil/shadow.hpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 00e6b93a9..9b2054479 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -86,7 +86,7 @@ namespace SceneUtil Shader::ShaderManager::DefineMap definesWithShadows; definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - for (int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) + for (unsigned int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 61a564a2a..6a3fccea6 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -17,6 +17,8 @@ namespace SceneUtil ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask); + virtual ~ShadowManager() = default; + virtual void setupShadowSettings(); virtual Shader::ShaderManager::DefineMap getShadowDefines(); From 3fe8dc63090c6d5ea8f4ef435495cc90d014010b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 16:05:11 +0000 Subject: [PATCH 085/168] Remove leftover import --- apps/openmw/mwrender/renderingmanager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5aa9da425..773363051 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,8 +13,6 @@ #include #include -#include - #include #include From 451d0de4631029fd53733ef0f2412ad0f35f959a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 16:18:42 +0000 Subject: [PATCH 086/168] Remove dependency on osgAnimation that somehow snuck in --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4513d6996..c2d4304e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX osgShadow) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS From bc4b4c66e432914ffa8cbf8ce78b0952f1c2717e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 27 Feb 2018 16:54:48 +0000 Subject: [PATCH 087/168] (Hopefully) add include which G++ requires even though VC++ doesn't. --- components/sceneutil/shadow.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 6a3fccea6..9444591c9 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -2,6 +2,7 @@ #define COMPONENTS_SCENEUTIL_SHADOW_H #include +#include #include #include From fc4190279820e0bbd4c7d075eefab7acab8862e3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 14:37:11 +0000 Subject: [PATCH 088/168] Replace a dynamic cast with string comarison --- components/sceneutil/mwshadowtechnique.cpp | 2 ++ components/terrain/quadtreeworld.cpp | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index fbf0fc9d2..80e2c1d38 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -301,6 +301,8 @@ MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewpor pushViewport(viewport); pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + + setName("SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds,AcceptedByComponentsTerrainQuadTreeWorld"); } void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Node& node) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 651b2cd24..e1beaee02 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -347,9 +347,16 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) { - SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds* shadowBoundsVisitor = dynamic_cast(&nv); - if (shadowBoundsVisitor) - shadowBoundsVisitor->apply(*this); + if (nv.getName().find("AcceptedByComponentsTerrainQuadTreeWorld") != std::string::npos) + { + if (nv.getName().find("SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds") != std::string::npos) + { + SceneUtil::MWShadowTechnique::ComputeLightSpaceBounds* clsb = static_cast(&nv); + clsb->apply(*this); + } + else + nv.apply(*mRootNode); + } return; } From 6f582f5411abb761d89a7a946fd76bd625800f9d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 17:30:53 +0000 Subject: [PATCH 089/168] Make indoor shadows do something meaningful. --- apps/openmw/mwrender/objects.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwrender/vismask.hpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index f0a3d2e38..28b7732c3 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -73,6 +73,7 @@ void Objects::insertBegin(const MWWorld::Ptr& ptr) void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool animated, bool allowLight) { insertBegin(ptr); + ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object); osg::ref_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight)); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 773363051..aabfa91a7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -200,7 +200,7 @@ namespace MWRender mSceneRoot = sceneRoot; sceneRoot->setStartLight(1); - int shadowCastingTraversalMask = 0; + int shadowCastingTraversalMask = Mask_Scene; if (Settings::Manager::getBool("actor shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Actor; if (Settings::Manager::getBool("player shadows", "Shadows")) @@ -208,7 +208,7 @@ namespace MWRender if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Scene | shadowCastingTraversalMask, shadowCastingTraversalMask)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Object | shadowCastingTraversalMask, shadowCastingTraversalMask)); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index d52c7c232..53026150b 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -33,6 +33,7 @@ namespace MWRender Mask_SimpleWater = (1<<7), Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), + Mask_Object = (1<<18), // TODO: get Scrawl or Zini to decide if we want this to be (1<<10) and to shift all of the other masks by one. // child of Sky Mask_Sun = (1<<10), From cfad38b8690adc68a587ad8888b55b42bda039c6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 17:32:45 +0000 Subject: [PATCH 090/168] Make masks consecutive and ordered. --- apps/openmw/mwrender/vismask.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 53026150b..1d94b4bf9 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -33,26 +33,26 @@ namespace MWRender Mask_SimpleWater = (1<<7), Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), - Mask_Object = (1<<18), // TODO: get Scrawl or Zini to decide if we want this to be (1<<10) and to shift all of the other masks by one. + Mask_Object = (1<<10), // child of Sky - Mask_Sun = (1<<10), - Mask_WeatherParticles = (1<<11), + Mask_Sun = (1<<11), + Mask_WeatherParticles = (1<<12), // top level masks - Mask_Scene = (1<<12), - Mask_GUI = (1<<13), + Mask_Scene = (1<<13), + Mask_GUI = (1<<14), // Set on a ParticleSystem Drawable - Mask_ParticleSystem = (1<<14), + Mask_ParticleSystem = (1<<15), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<15), + Mask_RenderToTexture = (1<<16), - Mask_PreCompile = (1<<16), + Mask_PreCompile = (1<<17), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<17) + Mask_Lighting = (1<<18) }; } From 94c7cf414f858f5818f97dbf681f7d540adee5ff Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 18:28:32 +0000 Subject: [PATCH 091/168] Update documentation to clarify the effects of using shadows without shaders. --- docs/source/reference/modding/settings/shaders.rst | 1 + docs/source/reference/modding/settings/shadows.rst | 4 ++++ files/settings-default.cfg | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/shaders.rst b/docs/source/reference/modding/settings/shaders.rst index 17d092917..dbce11464 100644 --- a/docs/source/reference/modding/settings/shaders.rst +++ b/docs/source/reference/modding/settings/shaders.rst @@ -1,6 +1,7 @@ Shader Settings ############### +.. _force-shaders-label: force shaders ------------- diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index a0e902d7b..fe471df1e 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -13,6 +13,10 @@ enable shadows Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. +When used in fixed-function mode, shadowed regions will appear completely black. +To prevent this, enable :ref:`force-shaders-label`. +A keen developer may be able to implement something better using the advice of `this post`_, but it may be more difficult than it seems. + number of shadow maps --------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e2632f9e5..ae3d6eefc 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -474,7 +474,7 @@ companion w = 0.38 companion h = 0.63 [Shadows] -# Enable or disable shadows. +# Enable or disable shadows. Bear in mind that when used without "[Shaders]/force shaders" set to true (i.e. objects and terrain are rendered in fixed-function mode) shadowed areas will be completely black. As such, it is recommended to use this feature in conjunction with shaders. enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 From 4acd9228ee2a86bacf2f22e09d4a2e5dc1709301 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 1 Mar 2018 18:30:17 +0000 Subject: [PATCH 092/168] fix RST error --- docs/source/reference/modding/settings/shadows.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index fe471df1e..8e3b79c00 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -15,7 +15,7 @@ Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. When used in fixed-function mode, shadowed regions will appear completely black. To prevent this, enable :ref:`force-shaders-label`. -A keen developer may be able to implement something better using the advice of `this post`_, but it may be more difficult than it seems. +A keen developer may be able to implement something better using the advice of `this post `_, but it may be more difficult than it seems. number of shadow maps From d6a7aec971c2ba0b041c58cc6e0497180b5e84d6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 01:54:21 +0000 Subject: [PATCH 093/168] Make RenderingManager::configureAmbient do what it was intended to. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aabfa91a7..680f4ebd0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -416,7 +416,7 @@ namespace MWRender osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); mSunLight->setDiffuse(diffuse); mSunLight->setSpecular(diffuse); - mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); + mSunLight->setPosition(osg::Vec4f(-1.f, 1.f, 1.f, 0.f)); } void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular) From 3bed2a7b010bee4f53d81ae733a8f2b2492be8a7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 02:01:03 +0000 Subject: [PATCH 094/168] Fix some copiler warnings (hopefully) --- components/sceneutil/shadow.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 9444591c9..682904650 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -32,12 +32,12 @@ namespace SceneUtil protected: bool mEnableShadows; - unsigned int mOutdoorShadowCastingMask; - unsigned int mIndoorShadowCastingMask; - osg::ref_ptr mShadowedScene; osg::ref_ptr mShadowSettings; osg::ref_ptr mShadowTechnique; + + unsigned int mOutdoorShadowCastingMask; + unsigned int mIndoorShadowCastingMask; }; } From b553b58de5d5b1bb0c5cdffc35dac2b1e3fe2cd9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 02:03:16 +0000 Subject: [PATCH 095/168] Fix another compiler warning --- components/sceneutil/mwshadowtechnique.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 80e2c1d38..11089a49c 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1015,6 +1015,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } +#if 0 double splitPoint = 0.0; if (numShadowMapsPerLight>1) @@ -1049,6 +1050,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) OSG_INFO<<" n="< Date: Sat, 3 Mar 2018 15:06:05 +0000 Subject: [PATCH 097/168] Apply Scrawl's fix for the local map --- apps/openmw/mwrender/localmap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 97e9c817a..70d7a1dbe 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -171,7 +171,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene|Mask_SimpleWater|Mask_Terrain); + camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -372,7 +372,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene|Mask_Terrain); + computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); From e46bf28e5fc028d6268c0fa255ab5a0e36adc5f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 15:13:36 +0000 Subject: [PATCH 098/168] Add object shadows setting --- apps/openmw/mwrender/renderingmanager.cpp | 6 +++++- files/settings-default.cfg | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 680f4ebd0..33ce9346b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -207,8 +207,12 @@ namespace MWRender shadowCastingTraversalMask |= Mask_Player; if (Settings::Manager::getBool("terrain shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Terrain; + + int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; + if (Settings::Manager::getBool("object shadows", "Shadows")) + shadowCastingTraversalMask |= Mask_Object; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, Mask_Object | shadowCastingTraversalMask, shadowCastingTraversalMask)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask)); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ae3d6eefc..ee102af52 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -496,4 +496,5 @@ actor shadows = false player shadows = false # Allow terrain to cast shadows. Potentially decreases performance. terrain shadows = false -# Note: Right now, there is no setting allowing toggling of shadows for statics +# Allow world objects to cast shadows. Potentially decreases performance. +object shadows = false From 6d29375d5e23e0ba1ea6dc3569d4ccd1919f908c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Mar 2018 15:50:36 +0000 Subject: [PATCH 099/168] Turning on shadows will now force shaders on --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- docs/source/reference/modding/settings/shadows.rst | 5 ++--- files/settings-default.cfg | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 33ce9346b..bc414401f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -186,7 +186,7 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); - resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders")); + resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows")); // Shadows have problems with fixed-function mode resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 8e3b79c00..4dac6a88b 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -13,9 +13,8 @@ enable shadows Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. -When used in fixed-function mode, shadowed regions will appear completely black. -To prevent this, enable :ref:`force-shaders-label`. -A keen developer may be able to implement something better using the advice of `this post `_, but it may be more difficult than it seems. +Bear in mind that this will force OpenMW to use shaders as if :ref:`force-shaders-label` was enabled. +A keen developer may be able to implement compatibility with fixed-function mode using the advice of `this post `_, but it may be more difficult than it seems. number of shadow maps diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ee102af52..c0283b378 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -474,7 +474,7 @@ companion w = 0.38 companion h = 0.63 [Shadows] -# Enable or disable shadows. Bear in mind that when used without "[Shaders]/force shaders" set to true (i.e. objects and terrain are rendered in fixed-function mode) shadowed areas will be completely black. As such, it is recommended to use this feature in conjunction with shaders. +# Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 From 4547151863db04c1a6b1d795fbffc577516c3b56 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 5 May 2018 00:08:00 +0100 Subject: [PATCH 100/168] Add the view frustum to the debug HUD (in the most annoying way possible) --- components/sceneutil/mwshadowtechnique.cpp | 37 ++++++++++++++++++++++ components/sceneutil/mwshadowtechnique.hpp | 2 ++ 2 files changed, 39 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 904c51669..b84e797c1 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -762,11 +762,43 @@ void MWShadowTechnique::disableShadows() void SceneUtil::MWShadowTechnique::enableDebugHUD() { _debugHud = new DebugHUD(getShadowedScene()->getShadowSettings()->getNumShadowMapsPerLight()); + _frustumGeometry = new osg::Geometry(); + _frustumGeometry->setCullingActive(false); + + osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); + _frustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(4); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(7); + frustumDrawElements->push_back(4); + + frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); + _frustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(7); + + // Ensure this doesn't contribute to bounds calculation. + _frustumGeometry->setComputeBoundingBoxCallback(new osg::Drawable::ComputeBoundingBoxCallback()); + _frustumGeometry->setComputeBoundingSphereCallback(new osg::Node::ComputeBoundingSphereCallback()); + + getShadowedScene()->addChild(_frustumGeometry); } void SceneUtil::MWShadowTechnique::disableDebugHUD() { _debugHud = nullptr; + getShadowedScene()->removeChild(_frustumGeometry); + _frustumGeometry = nullptr; } void SceneUtil::MWShadowTechnique::setSplitPointUniformLogarithmicRatio(double ratio) @@ -887,6 +919,11 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) //OSG_NOTICE<<"maxZFar "< frustumCorners = new osg::Vec3dArray(8, &frustum.corners[0]); + _frustumGeometry->setVertexArray(frustumCorners); + } double reducedNear, reducedFar; if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 1fad0eee5..7f5aeb85d 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -260,6 +260,8 @@ namespace SceneUtil { }; osg::ref_ptr _debugHud; + + osg::ref_ptr _frustumGeometry; }; } From 166e7df7781826e72c4e110df7a84fa07d7c0567 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 11 May 2018 19:08:42 +0100 Subject: [PATCH 101/168] Improve debug HUD frustum --- components/sceneutil/mwshadowtechnique.cpp | 139 +++++++++++++++------ components/sceneutil/mwshadowtechnique.hpp | 9 +- 2 files changed, 105 insertions(+), 43 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index b84e797c1..db0788318 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -115,6 +115,44 @@ std::string debugFragmentShaderSource = #endif "} \n"; +std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z;}"; +std::string debugFrustumFragmentShaderSource = + "varying float depth; \n" + " \n" + "void main(void) \n" + "{ \n" +#if 1 + " float f = depth; \n" + " \n" + " f = 256.0 * f; \n" + " float fC = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fS = floor( f ) / 256.0; \n" + " \n" + " f = 256.0 * fract( f ); \n" + " float fH = floor( f ) / 256.0; \n" + " \n" + " fS *= 0.5; \n" + " fH = ( fH * 0.34 + 0.66 ) * ( 1.0 - fS ); \n" + " \n" + " vec3 rgb = vec3( ( fC > 0.5 ? ( 1.0 - fC ) : fC ), \n" + " abs( fC - 0.333333 ), \n" + " abs( fC - 0.666667 ) ); \n" + " \n" + " rgb = min( vec3( 1.0, 1.0, 1.0 ), 3.0 * rgb ); \n" + " \n" + " float fMax = max( max( rgb.r, rgb.g ), rgb.b ); \n" + " fMax = 1.0 / fMax; \n" + " \n" + " vec3 color = fMax * rgb; \n" + " \n" + " gl_FragColor = vec4( fS + fH * color, 1 ); \n" +#else + " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" +#endif + "} \n"; + template class RenderLeafTraverser : public T @@ -762,43 +800,14 @@ void MWShadowTechnique::disableShadows() void SceneUtil::MWShadowTechnique::enableDebugHUD() { _debugHud = new DebugHUD(getShadowedScene()->getShadowSettings()->getNumShadowMapsPerLight()); - _frustumGeometry = new osg::Geometry(); - _frustumGeometry->setCullingActive(false); - - osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); - _frustumGeometry->addPrimitiveSet(frustumDrawElements); - frustumDrawElements->push_back(0); - frustumDrawElements->push_back(1); - frustumDrawElements->push_back(2); - frustumDrawElements->push_back(3); - frustumDrawElements->push_back(0); - frustumDrawElements->push_back(4); - frustumDrawElements->push_back(5); - frustumDrawElements->push_back(6); - frustumDrawElements->push_back(7); - frustumDrawElements->push_back(4); - - frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); - _frustumGeometry->addPrimitiveSet(frustumDrawElements); - frustumDrawElements->push_back(1); - frustumDrawElements->push_back(5); - frustumDrawElements->push_back(2); - frustumDrawElements->push_back(6); - frustumDrawElements->push_back(3); - frustumDrawElements->push_back(7); - - // Ensure this doesn't contribute to bounds calculation. - _frustumGeometry->setComputeBoundingBoxCallback(new osg::Drawable::ComputeBoundingBoxCallback()); - _frustumGeometry->setComputeBoundingSphereCallback(new osg::Node::ComputeBoundingSphereCallback()); + - getShadowedScene()->addChild(_frustumGeometry); + } void SceneUtil::MWShadowTechnique::disableDebugHUD() { _debugHud = nullptr; - getShadowedScene()->removeChild(_frustumGeometry); - _frustumGeometry = nullptr; } void SceneUtil::MWShadowTechnique::setSplitPointUniformLogarithmicRatio(double ratio) @@ -919,11 +928,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) //OSG_NOTICE<<"maxZFar "< frustumCorners = new osg::Vec3dArray(8, &frustum.corners[0]); - _frustumGeometry->setVertexArray(frustumCorners); - } + if (_debugHud) + _debugHud->setFrustumVertices(new osg::Vec3dArray(8, &frustum.corners[0])); double reducedNear, reducedFar; if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) @@ -1106,9 +1112,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) previous_sdl.erase(previous_sdl.begin()); } - if (_debugHud) - _debugHud->draw(sd->_texture, sm_i, cv); - osg::ref_ptr camera = sd->_camera; camera->setProjectionMatrix(projectionMatrix); @@ -1273,6 +1276,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // increment counters. ++textureUnit; ++numValidShadows ; + + if (_debugHud) + _debugHud->draw(sd->_texture, sm_i, camera->getViewMatrix() * camera->getProjectionMatrix(), cv); } } @@ -2625,15 +2631,51 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); mDebugProgram->addShader(fragmentShader); + mFrustumGeometry = new osg::Geometry(); + mFrustumGeometry->setCullingActive(false); + + osg::ref_ptr frustumProgram = new osg::Program; + vertexShader = new osg::Shader(osg::Shader::VERTEX, debugFrustumVertexShaderSource); + frustumProgram->addShader(vertexShader); + fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFrustumFragmentShaderSource); + frustumProgram->addShader(fragmentShader); + + mFrustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); + //mFrustumGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); + mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(0); + frustumDrawElements->push_back(4); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(7); + frustumDrawElements->push_back(4); + + frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); + mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + frustumDrawElements->push_back(1); + frustumDrawElements->push_back(5); + frustumDrawElements->push_back(2); + frustumDrawElements->push_back(6); + frustumDrawElements->push_back(3); + frustumDrawElements->push_back(7); + for (int i = 0; i < numberOfShadowMapsPerLight; ++i) addAnotherShadowMap(); } -void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv) +void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr texture, unsigned int shadowMapNumber, const osg::Matrixd &matrix, osgUtil::CullVisitor& cv) { // It might be possible to change shadow settings at runtime if (shadowMapNumber > mDebugCameras.size()) addAnotherShadowMap(); + + mFrustumUniforms[shadowMapNumber]->set(matrix); osg::ref_ptr stateSet = mDebugGeometry[shadowMapNumber]->getOrCreateStateSet(); stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); @@ -2656,6 +2698,14 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) mDebugProgram->releaseGLObjects(state); for (auto const& node : mDebugGeometry) node->releaseGLObjects(state); + for (auto const& node : mFrustumTransforms) + node->releaseGLObjects(state); + mFrustumGeometry->releaseGLObjects(state); +} + +void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) +{ + mFrustumGeometry->setVertexArray(vertices); } void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() @@ -2666,6 +2716,7 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() mDebugCameras[shadowMapNumber]->setViewport(200 * shadowMapNumber, 0, 200, 200); mDebugCameras[shadowMapNumber]->setRenderOrder(osg::Camera::POST_RENDER); mDebugCameras[shadowMapNumber]->setClearColor(osg::Vec4(1.0, 1.0, 0.0, 1.0)); + mDebugCameras[shadowMapNumber]->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); mDebugGeometry.push_back(osg::createTexturedQuadGeometry(osg::Vec3(-1, -1, 0), osg::Vec3(2, 0, 0), osg::Vec3(0, 2, 0))); mDebugGeometry[shadowMapNumber]->setCullingActive(false); @@ -2675,4 +2726,12 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() osg::ref_ptr textureUniform = new osg::Uniform("texture", sDebugTextureUnit); //textureUniform->setType(osg::Uniform::SAMPLER_2D); stateSet->addUniform(textureUniform.get()); + + mFrustumTransforms.push_back(new osg::Group); + mFrustumTransforms[shadowMapNumber]->addChild(mFrustumGeometry); + mFrustumTransforms[shadowMapNumber]->setCullingActive(false); + mDebugCameras[shadowMapNumber]->addChild(mFrustumTransforms[shadowMapNumber]); + + mFrustumUniforms.push_back(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "transform")); + mFrustumTransforms[shadowMapNumber]->getOrCreateStateSet()->addUniform(mFrustumUniforms[shadowMapNumber]); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 7f5aeb85d..eb5b650a0 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -246,9 +246,11 @@ namespace SceneUtil { void draw(); - virtual void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, osgUtil::CullVisitor& cv); + virtual void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, const osg::Matrixd &matrix, osgUtil::CullVisitor& cv); virtual void releaseGLObjects(osg::State* state = 0) const; + + virtual void setFrustumVertices(osg::ref_ptr vertices); protected: virtual void addAnotherShadowMap(); @@ -257,11 +259,12 @@ namespace SceneUtil { std::vector> mDebugCameras; osg::ref_ptr mDebugProgram; std::vector> mDebugGeometry; + std::vector> mFrustumTransforms; + std::vector> mFrustumUniforms; + osg::ref_ptr mFrustumGeometry; }; osg::ref_ptr _debugHud; - - osg::ref_ptr _frustumGeometry; }; } From 1b30d47d7f79fdcba463241df0c683f7b44fad69 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 13 May 2018 12:56:40 +0100 Subject: [PATCH 102/168] Add a hacky temporary version of cascading shadow maps --- components/sceneutil/mwshadowtechnique.cpp | 29 +++++++++++++++------- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index db0788318..d2c4c3a8f 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -149,7 +149,7 @@ std::string debugFrustumFragmentShaderSource = " \n" " gl_FragColor = vec4( fS + fH * color, 1 ); \n" #else - " gl_FragColor = texture2D(texture, gl_TexCoord[0].xy); \n" + " gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0); \n" #endif "} \n"; @@ -1130,7 +1130,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) osg::Polytope local_polytope(polytope); local_polytope.transformProvidingInverse(invertModelView); - + double cascaseNear = reducedNear; + double cascadeFar = reducedFar; if (numShadowMapsPerLight>1) { // compute the start and end range in non-dimensional coords @@ -1158,6 +1159,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double ciLog = n * pow(f / n, i / m); double ciUniform = n + (f - n) * i / m; double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; + cascaseNear = ci; // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; @@ -1173,7 +1175,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) double ciLog = n * pow(f / n, (i + 1) / m); double ciUniform = n + (f - n) * (i + 1) / m; double ci = _splitPointUniformLogRatio * ciLog + (1.0 - _splitPointUniformLogRatio) * ciUniform + _splitPointDeltaBias; - + cascadeFar = ci; + // work out where this is in light space osg::Vec3d worldSpacePos = frustum.eye + frustum.frustumCenterLine * ci; osg::Vec3d lightSpacePos = worldSpacePos * viewMatrix * projectionMatrix; @@ -1185,7 +1188,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (sm_i+10) + if (false)//(sm_i>0) { // not the first shadowmap so insert a polytope to clip the scene from before r_start @@ -1200,7 +1203,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } - if (sm_i+1setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) + mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED); + else + mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT); + if (Settings::Manager::getBool("enable debug hud", "Shadows")) mShadowTechnique->enableDebugHUD(); else diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3cc2b138e..1ffc745e8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -512,6 +512,8 @@ companion h = 0.63 enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 1 +# If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. +allow shadow map overlap = true # Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. split point uniform logarithmic ratio = 0.5 # Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. From 84284a60a74de83e15e00af8a9d64f3ba12f65af Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 17 May 2018 17:35:55 +0100 Subject: [PATCH 106/168] Make CSM shader changes controllable by the setting. --- components/sceneutil/shadow.cpp | 7 +++++++ files/shaders/objects_fragment.glsl | 30 +++++++++++++++++------------ files/shaders/terrain_fragment.glsl | 30 +++++++++++++++++------------ files/shaders/water_fragment.glsl | 30 +++++++++++++++++------------ 4 files changed, 61 insertions(+), 36 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 363e0ac3f..374faee8c 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -96,6 +96,11 @@ namespace SceneUtil // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) + definesWithShadows["shadowMapsOverlap"] = "1"; + else + definesWithShadows["shadowMapsOverlap"] = "0"; + return definesWithShadows; } @@ -105,6 +110,8 @@ namespace SceneUtil definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); definesWithShadows["shadow_texture_unit_list"] = ""; + definesWithShadows["shadowMapsOverlap"] = "0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 7ba3d1de0..5eb98899a 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -124,20 +124,26 @@ void main() float shadowing = 1.0; #if SHADOWS - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } } - } - @endforeach + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach + #endif #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 68ab1bbdd..ae9f5a7ba 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -76,20 +76,26 @@ void main() float shadowing = 1.0; #if SHADOWS - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } } - } - @endforeach + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach + #endif #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index e953b2611..7aa7ca0b0 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -168,20 +168,26 @@ void main(void) #if SHADOWS float shadowing = 1.0; - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } } - } - @endforeach + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach + #endif float shadow = shadowing; #else // NOT SHADOWS From 9f0a49c303c32bca1cde7c60a1f4f13b229239a6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 17 May 2018 20:27:10 +0100 Subject: [PATCH 107/168] Disable CSM when disabled in the settings. --- components/sceneutil/mwshadowtechnique.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 2cf10f4d7..763067592 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1254,7 +1254,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (!orthographicViewFrustum && settings->getShadowMapProjectionHint()==ShadowSettings::PERSPECTIVE_SHADOW_MAP) { - adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), cascaseNear, cascadeFar); + if (settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED) + adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), cascaseNear, cascadeFar); + else + adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), reducedNear, reducedFar); if (vdsmCallback->getProjectionMatrix()) { vdsmCallback->getProjectionMatrix()->set(camera->getProjectionMatrix()); From 2c30bc1b4f612a979f9ba164b78d67a971d61898 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 18 May 2018 22:39:57 +0100 Subject: [PATCH 108/168] Accidentally fix the one remaing case where shadows look awful while refactoring some stuff. --- components/sceneutil/mwshadowtechnique.cpp | 59 ++++++++++++++++++++++ components/sceneutil/mwshadowtechnique.hpp | 2 + 2 files changed, 61 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 763067592..70352541f 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1239,6 +1239,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } } + if (settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED) + cropShadowCameraToMainFrustum(frustum, camera, cascaseNear, cascadeFar); + else + cropShadowCameraToMainFrustum(frustum, camera, reducedNear, reducedFar); osg::ref_ptr vdsmCallback = new VDSMCameraCullCallback(this, local_polytope); camera->setCullCallback(vdsmCallback.get()); @@ -2159,6 +2163,61 @@ struct RenderLeafBounds double min_z, max_z; }; +bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Camera* camera, double viewNear, double viewFar) +{ + osg::Matrixd light_p = camera->getProjectionMatrix(); + osg::Matrixd light_v = camera->getViewMatrix(); + osg::Matrixd light_vp = light_v * light_p; + + ConvexHull convexHull; + convexHull.setToFrustum(frustum); + + osg::Vec3d nearPoint = frustum.eye + frustum.frustumCenterLine * viewNear; + osg::Vec3d farPoint = frustum.eye + frustum.frustumCenterLine * viewFar; + + double nearDist = -frustum.frustumCenterLine * nearPoint; + double farDist = frustum.frustumCenterLine * farPoint; + + convexHull.clip(osg::Plane(frustum.frustumCenterLine, nearDist)); + convexHull.clip(osg::Plane(-frustum.frustumCenterLine, farDist)); + + convexHull.transform(light_vp); + + double xMin = -1.0, xMax = 1.0; + double yMin = -1.0, yMax = 1.0; + double zMin = -1.0, zMax = 1.0; + + if (convexHull.valid()) + { + xMin = osg::maximum(-1.0, convexHull.min(0)); + xMax = osg::minimum(1.0, convexHull.max(0)); + yMin = osg::maximum(-1.0, convexHull.min(1)); + yMax = osg::minimum(1.0, convexHull.max(1)); + } + else + return false; + + // we always want the lightspace to include the computed near plane. + zMin = -1.0; + if (xMin != -1.0 || yMin != -1.0 || zMin != -1.0 || + xMax != 1.0 || yMax != 1.0 || zMax != 1.0) + { + osg::Matrix m; + m.makeTranslate(osg::Vec3d(-0.5*(xMax + xMin), + -0.5*(yMax + yMin), + -0.5*(zMax + zMin))); + + m.postMultScale(osg::Vec3d(2.0 / (xMax - xMin), + 2.0 / (yMax - yMin), + 2.0 / (zMax - zMin))); + + light_p.postMult(m); + camera->setProjectionMatrix(light_p); + } + + return true; +} + bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& /*positionedLight*/, osg::Camera* camera, double viewNear, double viewFar) { const ShadowSettings* settings = getShadowedScene()->getShadowSettings(); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index f11aec0bb..ce5c0b674 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -205,6 +205,8 @@ namespace SceneUtil { virtual bool computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix); + virtual bool cropShadowCameraToMainFrustum(Frustum& frustum, osg::Camera* camera, double viewNear, double viewFar); + virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera, double viewNear, double viewFar); virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); From feac7bd88e8086f20a4dc1f67dd273d0bd6e2eb9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 20 May 2018 00:17:06 +0100 Subject: [PATCH 109/168] Use 3 shadow maps by default as 1 sucks. --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 1ffc745e8..5c404a78f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -511,7 +511,7 @@ companion h = 0.63 # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. -number of shadow maps = 1 +number of shadow maps = 3 # If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. allow shadow map overlap = true # Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. From 86ce33f437717449f03636953cccfb98a78e1e99 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 21 May 2018 16:00:51 +0100 Subject: [PATCH 110/168] Update documentation --- .../reference/modding/settings/shadows.rst | 18 ++++++++++++++++-- files/settings-default.cfg | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 4dac6a88b..f9ebd1f63 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -22,12 +22,23 @@ number of shadow maps :Type: integer :Range: 1 to 8, but higher values may conflict with other texture effects -:Default: 1 +:Default: 3 Control how many shadow maps to use - more of these means each shadow map texel covers less area, producing better-looking shadows, but may decrease performance. Using too many shadow maps will lead to them overriding texture slots used for other effects, producing unpleasant artefacts. A value of three is recommended in most cases, but other values may produce better results or performance. +allow shadow map overlap +------------------------ + +:Type: boolean +:Range: True/False +:Default: True + +If true, allow shadow maps to overlap. +Counter-intuitively, will produce much better results when the light is behind the camera. +When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. + enable debug hud ---------------- @@ -97,8 +108,9 @@ Note: Right now, there is no setting allowing toggling of shadows for statics Expert settings *************** -You probably shouldn't be changing these if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. +You probably shouldn't be changing these yourself if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. If you have, then you may get better results tuning these for your specific view distance. +Copying values from another user who's done careful tuning is the recommended way of arriving at an optimal value for these settings. split point uniform logarithmic ratio ------------------------------------- @@ -108,6 +120,8 @@ split point uniform logarithmic ratio :Default: 0.5 Controls the ratio of :math:`C_i^{log}` versus :math:`C_i^{uniform}` used to form the Practical Split Scheme as described in the linked paper. +When using a larger-than-default viewing distance and distant terrain, and you have `allow shadow map overlap`_ enabled, larger values will prevent nearby shadows losing quality. +It is therefore recommended that this isn't left at the default when the viewing distance is changed. split point bias ---------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 5c404a78f..c8d68c14c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -514,7 +514,7 @@ enable shadows = false number of shadow maps = 3 # If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. allow shadow map overlap = true -# Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you probably don't want to change this, especially not without reading the associated papers first. +# Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you might not want to change this, especially not without reading the associated papers first. When "allow shadow map overlap" is combined with a higher-than-default viewing distance, values closer to 1.0 will prevent nearby shadows losing a lot of quality. split point uniform logarithmic ratio = 0.5 # Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. split point bias = 0.0 From 9093ab59f63b27fefda32c785c00bf3b46654791 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 21 May 2018 23:57:38 +0100 Subject: [PATCH 111/168] Restore water object refractions and reflections. --- apps/openmw/mwrender/water.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 6e1fef716..0b4a8e062 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -221,7 +221,7 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("RefractionCamera"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -312,7 +312,7 @@ public: bool reflectActors = Settings::Manager::getBool("reflect actors", "Water"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); From 50fdd0be994f09cd8a696f44651aeba775031a64 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 29 May 2018 00:52:43 +0100 Subject: [PATCH 112/168] Resolve computed near plane issues with extremely high viewing distances. --- components/sceneutil/mwshadowtechnique.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 70352541f..378881d8d 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -927,6 +927,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) //OSG_NOTICE<<"maxZFar "<setFrustumVertices(new osg::Vec3dArray(8, &frustum.corners[0])); @@ -2252,7 +2255,7 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render double nearDist = frustum.frustumCenterLine.x() * nearPoint.x() + frustum.frustumCenterLine.y() * nearPoint.y() + frustum.frustumCenterLine.z() * nearPoint.z(); double farDist = -frustum.frustumCenterLine.x() * farPoint.x() - frustum.frustumCenterLine.y() * farPoint.y() - frustum.frustumCenterLine.z() * farPoint.z(); - + convexHull.clip(osg::Plane(frustum.frustumCenterLine, -nearDist)); convexHull.clip(osg::Plane(-frustum.frustumCenterLine, -farDist)); From f5b144ef774364d0571d5d58c4ca65b0eaa475bb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 12 Jun 2018 17:04:56 +0100 Subject: [PATCH 113/168] Improve bounds calculation for shadow casters outside of the viewing frustum --- components/sceneutil/mwshadowtechnique.cpp | 166 +++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 378881d8d..0bb8a26c9 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1787,6 +1787,168 @@ struct ConvexHull _edges.push_back( Edge(frustum.corners[3],frustum.corners[7]) ); } + struct ConvexHull2D + { + // Implementation based on https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#C++ + typedef osg::Vec3d Point; + + static double cross(const Point &O, const Point &A, const Point &B) + { + return (A.x() - O.x())*(B.y() - O.y()) - (A.y() - O.y())*(B.x() - O.x()); + } + + // Calculates the 2D convex hull and returns it as a vector containing the points in CCW order with the first and last point being the same. + static std::vector convexHull(std::set &P) + { + size_t n = P.size(), k = 0; + if (n <= 3) + return std::vector(P.cbegin(), P.cend()); + + std::vector H(2 * n); + + // Points are already sorted in a std::set + + // Build lower hull + for (auto pItr = P.cbegin(); pItr != P.cend(); ++pItr) + { + while (k >= 2 && cross(H[k - 2], H[k - 1], *pItr) <= 0) + k--; + H[k++] = *pItr; + } + + // Build upper hull + size_t t = k + 1; + for (auto pItr = std::next(P.crbegin()); pItr != P.crend(); ++pItr) + { + while (k >= t && cross(H[k - 2], H[k - 1], *pItr) <= 0) + k--; + H[k++] = *pItr; + } + + H.resize(k - 1); + return H; + } + }; + + bool shouldBeDeleted(osg::Vec3d vertex, std::set &extremeVertices) + { + // A vertex should be deleted if there is no route -Z-wards to an extreme vertex + // equivalent to all -Z-wards vertices being deletable. + if (extremeVertices.find(vertex) != extremeVertices.end()) + return false; + for (Edge edge : _edges) + { + osg::Vec3d otherEnd; + if (edge.first == vertex) + otherEnd = edge.second; + else if (edge.second == vertex) + otherEnd = edge.first; + else + continue; + + if (otherEnd.z() >= vertex.z()) + continue; + + if (!shouldBeDeleted(otherEnd, extremeVertices)) + return false; + } + + return true; + } + + void extendTowardsNegativeZ() + { + typedef std::set VertexSet; + + // Collect the set of vertices + VertexSet vertices; + for (Edge edge : _edges) + { + vertices.insert(edge.first); + vertices.insert(edge.second); + } + + if (vertices.size() == 0) + return; + + // Get the vertices contributing to the 2D convex hull + Vertices extremeVertices = ConvexHull2D::convexHull(vertices); + VertexSet extremeVerticesSet(extremeVertices.cbegin(), extremeVertices.cend()); + + // Add their extrusions to the final edge collection + Edges finalEdges; + // Add edges towards -Z + for (auto vertex : extremeVertices) + finalEdges.push_back(Edge(vertex, osg::Vec3d(vertex.x(), vertex.y(), -DBL_MAX))); + // Add edge loop to 'seal' the hull + for (auto itr = extremeVertices.cbegin(); itr != extremeVertices.cend() - 1; ++itr) + finalEdges.push_back(Edge(osg::Vec3d(itr->x(), itr->y(), -DBL_MAX), osg::Vec3d((itr + 1)->x(), (itr + 1)->y(), -DBL_MAX))); + // The convex hull algorithm we are using places a point at both ends of the vector, so we don't need to add the last edge separately. + // finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX))); + + // Collect the first layer of unneeded vertices and remove the edges connecting them to the rest of the mesh + VertexSet deletedVertices; + for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */ ) + { + if (extremeVerticesSet.find(edgeItr->first) != extremeVerticesSet.end()) + { + if (extremeVerticesSet.find(edgeItr->second) == extremeVerticesSet.end()) + { + if (edgeItr->first.z() >= edgeItr->second.z()) + { + // If we can travel along edges towards -Z and reach an extreme vertex, the current edge must be kept + if (shouldBeDeleted(edgeItr->second, extremeVerticesSet)) + { + deletedVertices.insert(edgeItr->second); + edgeItr = _edges.erase(edgeItr); + continue; + } + } + } + } + else if (extremeVerticesSet.find(edgeItr->second) != extremeVerticesSet.end()) + { + if (edgeItr->second.z() >= edgeItr->first.z()) + { + if (shouldBeDeleted(edgeItr->first, extremeVerticesSet)) + { + deletedVertices.insert(edgeItr->first); + edgeItr = _edges.erase(edgeItr); + continue; + } + } + } + ++edgeItr; + } + + // Remove all edges connected to removed vertices + bool modifiedSomething = true; + while (modifiedSomething) + { + modifiedSomething = false; + for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */) + { + if (deletedVertices.find(edgeItr->first) != deletedVertices.end()) + { + deletedVertices.insert(edgeItr->second); + edgeItr = _edges.erase(edgeItr); + modifiedSomething = true; + continue; + } + else if (deletedVertices.find(edgeItr->second) != deletedVertices.end()) + { + deletedVertices.insert(edgeItr->first); + edgeItr = _edges.erase(edgeItr); + modifiedSomething = true; + continue; + } + ++edgeItr; + } + } + + _edges.splice(_edges.end(), finalEdges); + } + void transform(const osg::Matrixd& m) { for(Edges::iterator itr = _edges.begin(); @@ -2186,6 +2348,8 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam convexHull.transform(light_vp); + convexHull.extendTowardsNegativeZ(); + double xMin = -1.0, xMax = 1.0; double yMin = -1.0, yMax = 1.0; double zMin = -1.0, zMax = 1.0; @@ -2269,6 +2433,8 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render convexHull.transform(light_vp); + convexHull.extendTowardsNegativeZ(); + #if 0 convexHull.output(osg::notify(osg::NOTICE)); From ed68db5ef9edba4417a9db79f598c3bf0474b9dc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 19 Jun 2018 23:48:59 +0100 Subject: [PATCH 114/168] Fix issue where the camera frustum cropping wouldn't consider where casters might cast shadows, just where they actually were. --- components/sceneutil/mwshadowtechnique.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 0bb8a26c9..56be0b8a0 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1039,6 +1039,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) osg::Matrixd cornerConverter = osg::Matrixd::inverse(projectionMatrix) * osg::Matrixd::inverse(viewMatrix) * *cv.getModelViewMatrix(); double minZ = DBL_MAX; double maxZ = -DBL_MAX; + clsb._bb._max[2] = 1.0; for (unsigned int i = 0; i < 8; i++) { osg::Vec3 corner = clsb._bb.corner(i); From b25b356081d080cdd76bc296f369b59c73856fd3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 22 Jun 2018 01:02:01 +0100 Subject: [PATCH 115/168] Sort out shader indentation --- files/shaders/lighting.glsl | 6 +-- files/shaders/objects_fragment.glsl | 50 +++++++++++----------- files/shaders/objects_vertex.glsl | 20 ++++----- files/shaders/terrain_fragment.glsl | 50 +++++++++++----------- files/shaders/terrain_vertex.glsl | 20 ++++----- files/shaders/water_fragment.glsl | 64 ++++++++++++++--------------- files/shaders/water_vertex.glsl | 32 +++++++-------- 7 files changed, 121 insertions(+), 121 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index e67ed295a..d234aaaad 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -3,12 +3,12 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; - float lightDistance; + float lightDistance; lightDir = gl_LightSource[lightIndex].position.xyz - (viewPos.xyz * gl_LightSource[lightIndex].position.w); lightDistance = length(lightDir); lightDir = normalize(lightDir); - float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); + float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); ambientOut = ambient * gl_LightSource[lightIndex].ambient.xyz * illumination; diffuseOut = diffuse.xyz * gl_LightSource[lightIndex].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0) * illumination; @@ -38,7 +38,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow lightResult.xyz += ambientLight + diffuseLight * shadowing; #else shadowDiffuse = diffuseLight; - lightResult.xyz += ambientLight; + lightResult.xyz += ambientLight; #endif for (int i=1; i Date: Fri, 22 Jun 2018 01:05:45 +0100 Subject: [PATCH 116/168] Fix water shader alignment issues noticed while removing tabs. --- files/shaders/water_fragment.glsl | 12 ++++++------ files/shaders/water_vertex.glsl | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index e78909abe..c2628eb7f 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -218,9 +218,9 @@ void main(void) vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + - normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + - rippleAdd); + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + + rippleAdd); normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); @@ -228,9 +228,9 @@ void main(void) // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + - normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + - rippleAdd).xyz; + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + + rippleAdd).xyz; lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index d38460caa..f51baf932 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -18,9 +18,9 @@ void main(void) gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, - 0.0, -0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0); + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); vec4 texcoordProj = ((scalemat) * ( gl_Position)); screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w); From a7e53df278cf93bb98c964f23fc309dacb4471ed Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 24 Jun 2018 23:40:52 +0100 Subject: [PATCH 117/168] Move common shadow code to shared shadow shader headers --- files/shaders/CMakeLists.txt | 2 ++ files/shaders/objects_fragment.glsl | 34 ++------------------------- files/shaders/objects_vertex.glsl | 18 ++------------- files/shaders/shadows_fragment.glsl | 36 +++++++++++++++++++++++++++++ files/shaders/shadows_vertex.glsl | 20 ++++++++++++++++ files/shaders/terrain_fragment.glsl | 34 ++------------------------- files/shaders/terrain_vertex.glsl | 18 ++------------- files/shaders/water_fragment.glsl | 36 ++--------------------------- files/shaders/water_vertex.glsl | 20 ++-------------- 9 files changed, 70 insertions(+), 148 deletions(-) create mode 100644 files/shaders/shadows_fragment.glsl create mode 100644 files/shaders/shadows_vertex.glsl diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 7baca78ef..41763f3e1 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -18,6 +18,8 @@ set(SHADER_FILES parallax.glsl s360_fragment.glsl s360_vertex.glsl + shadows_vertex.glsl + shadows_fragment.glsl ) copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 407541634..fffb9c83b 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; @@ -57,13 +55,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS - +#include "shadows_fragment.glsl" #include "lighting.glsl" #include "parallax.glsl" @@ -122,29 +114,7 @@ void main() gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); #endif - float shadowing = 1.0; -#if SHADOWS - #if @shadowMapsOverlap - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) - { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; - } - } - @endforeach - #else - @foreach shadow_texture_unit_index @shadow_texture_unit_list - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - @endforeach - #endif -#endif // SHADOWS + float shadowing = unshadowedLightRatio(); #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 02960e5b4..3d7f49eee 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -48,12 +46,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform int shadowTextureUnit@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_vertex.glsl" #include "lighting.glsl" @@ -110,12 +103,5 @@ void main(void) passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; -#if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - @endforeach -#endif // SHADOWS + setupShadowCoords(viewPos); } diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl new file mode 100644 index 000000000..cc1b38b59 --- /dev/null +++ b/files/shaders/shadows_fragment.glsl @@ -0,0 +1,36 @@ +#define SHADOWS @shadows_enabled + +#if SHADOWS + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach +#endif // SHADOWS + +float unshadowedLightRatio() +{ + float shadowing = 1.0; +#if SHADOWS + #if @shadowMapsOverlap + bool doneShadows = false; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneShadows) + { + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneShadows = true; + } + } + @endforeach + #else + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); + @endforeach + #endif +#endif // SHADOWS + return shadowing; +} \ No newline at end of file diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl new file mode 100644 index 000000000..bbc1a4036 --- /dev/null +++ b/files/shaders/shadows_vertex.glsl @@ -0,0 +1,20 @@ +#define SHADOWS @shadows_enabled + +#if SHADOWS + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach +#endif // SHADOWS + +void setupShadowCoords(vec4 viewPos) +{ +#if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach +#endif // SHADOWS +} \ No newline at end of file diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 57403f1a4..219b92c99 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - varying vec2 uv; uniform sampler2D diffuseMap; @@ -27,13 +25,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS - +#include "shadows_fragment.glsl" #include "lighting.glsl" #include "parallax.glsl" @@ -74,29 +66,7 @@ void main() gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif - float shadowing = 1.0; -#if SHADOWS - #if @shadowMapsOverlap - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) - { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; - } - } - @endforeach - #else - @foreach shadow_texture_unit_index @shadow_texture_unit_list - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - @endforeach - #endif -#endif // SHADOWS + float shadowing = unshadowedLightRatio(); #if !PER_PIXEL_LIGHTING gl_FragData[0] *= lighting + vec4(shadowDiffuseLighting * shadowing, 0); diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 57af0575c..669eac012 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -1,7 +1,5 @@ #version 120 -#define SHADOWS @shadows_enabled - varying vec2 uv; varying float depth; @@ -16,12 +14,7 @@ centroid varying vec4 passColor; varying vec3 passViewPos; varying vec3 passNormal; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform int shadowTextureUnit@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_vertex.glsl" #include "lighting.glsl" @@ -44,12 +37,5 @@ void main(void) uv = gl_MultiTexCoord0.xy; -#if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - @endforeach -#endif // SHADOWS + setupShadowCoords(viewPos); } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c2628eb7f..a227e1e68 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,7 +1,6 @@ #version 120 #define REFRACTION @refraction_enabled -#define SHADOWS @shadows_enabled // Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) @@ -143,12 +142,7 @@ uniform vec3 nodePosition; uniform float rainIntensity; -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_fragment.glsl" float frustumDepth; @@ -166,33 +160,7 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; -#if SHADOWS - float shadowing = 1.0; - #if @shadowMapsOverlap - bool doneShadows = false; - @foreach shadow_texture_unit_index @shadow_texture_unit_list - if (!doneShadows) - { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) - { - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneShadows = true; - } - } - @endforeach - #else - @foreach shadow_texture_unit_index @shadow_texture_unit_list - shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; - @endforeach - #endif - - float shadow = shadowing; -#else // NOT SHADOWS - float shadow = 1.0; -#endif // SHADOWS + float shadow = unshadowedLightRatio(); vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index f51baf932..b028d90d2 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -4,14 +4,7 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; -#define SHADOWS @shadows_enabled - -#if SHADOWS - @foreach shadow_texture_unit_index @shadow_texture_unit_list - uniform int shadowTextureUnit@shadow_texture_unit_index; - varying vec4 shadowSpaceCoords@shadow_texture_unit_index; - @endforeach -#endif // SHADOWS +#include "shadows_vertex.glsl" void main(void) { @@ -29,14 +22,5 @@ void main(void) depthPassthrough = gl_Position.z; - #if SHADOWS - vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - - @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - @endforeach - #endif // SHADOWS + setupShadowCoords(gl_ModelViewMatrix * gl_Vertex); } From 85aba2e1dab9e1d0fde071e15f1395ea05a5016a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 28 Jun 2018 17:24:36 +0100 Subject: [PATCH 118/168] Add toggleable shadow debug overlay. --- components/sceneutil/shadow.cpp | 7 +++++ .../reference/modding/settings/shadows.rst | 10 +++++++ files/settings-default.cfg | 2 ++ files/shaders/objects_fragment.glsl | 2 ++ files/shaders/shadows_fragment.glsl | 27 +++++++++++++++++++ files/shaders/terrain_fragment.glsl | 2 ++ files/shaders/water_fragment.glsl | 2 ++ 7 files changed, 52 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 374faee8c..6e45bdd22 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -101,6 +101,11 @@ namespace SceneUtil else definesWithShadows["shadowMapsOverlap"] = "0"; + if (Settings::Manager::getBool("enable debug overlay", "Shadows")) + definesWithShadows["useShadowDebugOverlay"] = "1"; + else + definesWithShadows["useShadowDebugOverlay"] = "0"; + return definesWithShadows; } @@ -112,6 +117,8 @@ namespace SceneUtil definesWithShadows["shadowMapsOverlap"] = "0"; + definesWithShadows["useShadowDebugOverlay"] = "0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index f9ebd1f63..271ecac20 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -49,6 +49,16 @@ enable debug hud Enable or disable the debug hud to see what the shadow map(s) contain. This setting is only recommended for developers, bug reporting and advanced users performing fine-tuning of shadow settings. +enable debug overlay +---------------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable or disable the debug overlay to see the area covered by each shadow map. +This setting is only recommended for developers, bug reporting and advanced users performing fine-tuning of shadow settings. + compute tight scene bounds -------------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6cee10e05..277b5dd08 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -530,6 +530,8 @@ split point uniform logarithmic ratio = 0.5 split point bias = 0.0 # Enable the debug hud to see what the shadow map(s) contain. enable debug hud = false +# Enable the debug overlay to see where each shadow map affects. +enable debug overlay = false # Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. compute tight scene bounds = false # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index fffb9c83b..64435f001 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -155,4 +155,6 @@ void main() float fogValue = clamp((depth - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + + applyShadowDebugOverlay(); } diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index cc1b38b59..ce9e958d1 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -33,4 +33,31 @@ float unshadowedLightRatio() #endif #endif // SHADOWS return shadowing; +} + +void applyShadowDebugOverlay() +{ +#if SHADOWS && @useShadowDebugOverlay + bool doneOverlay = false; + float colourIndex = 0.0; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + if (!doneOverlay) + { + vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + { + colourIndex = mod(@shadow_texture_unit_index.0, 3.0); + if (colourIndex < 1.0) + gl_FragData[0].x += 0.1; + else if (colourIndex < 2.0) + gl_FragData[0].y += 0.1; + else + gl_FragData[0].z += 0.1; + + if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + doneOverlay = true; + } + } + @endforeach +#endif // SHADOWS } \ No newline at end of file diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 219b92c99..c946777bb 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -86,4 +86,6 @@ void main() float fogValue = clamp((depth - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); + + applyShadowDebugOverlay(); } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index a227e1e68..0102a6eb9 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -280,4 +280,6 @@ void main(void) #else gl_FragData[0].w = clamp(fresnel*6.0 + specular, 0.0, 1.0); //clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif + + applyShadowDebugOverlay(); } From 02ab3b466ab3ef16e2b6f9fc04db57e025d25ec5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 31 Jul 2018 23:30:15 +0100 Subject: [PATCH 119/168] Use simplified convex hull clipping maths from the other function doing hte same thing --- components/sceneutil/mwshadowtechnique.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 56be0b8a0..31c10faff 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2416,13 +2416,12 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render osg::Vec3d nearPoint = frustum.eye + frustum.frustumCenterLine * viewNear; osg::Vec3d farPoint = frustum.eye + frustum.frustumCenterLine * viewFar; - // TODO: Aren't these just dot products? Also the double negation of farDist is silly. - double nearDist = frustum.frustumCenterLine.x() * nearPoint.x() + frustum.frustumCenterLine.y() * nearPoint.y() + frustum.frustumCenterLine.z() * nearPoint.z(); - double farDist = -frustum.frustumCenterLine.x() * farPoint.x() - frustum.frustumCenterLine.y() * farPoint.y() - frustum.frustumCenterLine.z() * farPoint.z(); - - convexHull.clip(osg::Plane(frustum.frustumCenterLine, -nearDist)); - convexHull.clip(osg::Plane(-frustum.frustumCenterLine, -farDist)); + double nearDist = -frustum.frustumCenterLine * nearPoint; + double farDist = frustum.frustumCenterLine * farPoint; + + convexHull.clip(osg::Plane(frustum.frustumCenterLine, nearDist)); + convexHull.clip(osg::Plane(-frustum.frustumCenterLine, farDist)); #if 0 OSG_NOTICE<<"ws ConvexHull xMin="<getSceneManager()->recreateShaders(mObjectRoot); - - if (mViewMode == VM_FirstPerson) - { - // Shadows made first-person meshes get erroneously culled. This stops that. - DisableCullingVisitor disableCullingVisitor; - mObjectRoot->accept(disableCullingVisitor); - } } From 6286f5a1d4581ab00e392a7af909c83004770b03 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:24:57 +0100 Subject: [PATCH 123/168] Ensure RigGeometry child geometries have sensible bounds without actually computing them. --- components/sceneutil/riggeometry.cpp | 10 ++++++++++ components/sceneutil/riggeometry.hpp | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 7f148cf5e..fdb67d7de 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -41,6 +41,8 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) to.setSupportsDisplayList(false); to.setUseVertexBufferObjects(true); to.setCullingActive(false); // make sure to disable culling since that's handled by this class + to.setComputeBoundingBoxCallback(new CopyBoundingBoxCallback()); + to.setComputeBoundingSphereCallback(new CopyBoundingSphereCallback()); // vertices and normals are modified every frame, so we need to deep copy them. // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO. @@ -273,6 +275,14 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) _boundingSphereComputed = true; for (unsigned int i=0; idirtyBound(); + + for (unsigned int i = 0; i < 2; ++i) + { + osg::Geometry& geom = *mGeometry[i]; + static_cast(geom.getComputeBoundingBoxCallback())->boundingBox = _boundingBox; + static_cast(geom.getComputeBoundingSphereCallback())->boundingSphere = _boundingSphere; + geom.dirtyBound(); + } } } diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 60b3edc9d..0d8dcbddd 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -51,6 +51,20 @@ namespace SceneUtil virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } virtual void accept(osg::PrimitiveFunctor&) const; + struct CopyBoundingBoxCallback : osg::Drawable::ComputeBoundingBoxCallback + { + osg::BoundingBox boundingBox; + + virtual osg::BoundingBox computeBound(const osg::Drawable&) const override { return boundingBox; } + }; + + struct CopyBoundingSphereCallback : osg::Node::ComputeBoundingSphereCallback + { + osg::BoundingSphere boundingSphere; + + virtual osg::BoundingSphere computeBound(const osg::Node&) const override { return boundingSphere; } + }; + private: void cull(osg::NodeVisitor* nv); void updateBounds(osg::NodeVisitor* nv); From 1e48114492a1c69740879f1120d2d8df7947825d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:30:33 +0100 Subject: [PATCH 124/168] Use JDGBOLT's indoor 'sun' direction. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 410157d80..1b17ce4ea 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -453,7 +453,7 @@ namespace MWRender osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); mSunLight->setDiffuse(diffuse); mSunLight->setSpecular(diffuse); - mSunLight->setPosition(osg::Vec4f(-1.f, 1.f, 1.f, 0.f)); + mSunLight->setPosition(osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f)); } void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular) From 1e0f9827410259c5be02563b4cd6efbdc47aea94 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:55:01 +0100 Subject: [PATCH 125/168] Add missing documentation --- docs/source/reference/modding/settings/shadows.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 271ecac20..34d484925 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -111,9 +111,17 @@ terrain shadows Allow terrain to cast shadows. Potentially decreases performance. +object shadows +-------------- + +:Type: boolean +:Range: True/False +:Default: False + +Allow static objects to cast shadows. +Potentially decreases performance. -Note: Right now, there is no setting allowing toggling of shadows for statics Expert settings *************** From 3b3721897d80e4af6cdb5ab1ae30a377add4a8aa Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Aug 2018 23:56:11 +0100 Subject: [PATCH 126/168] Make indoor shadows disableable. --- components/sceneutil/shadow.cpp | 7 ++++++- docs/source/reference/modding/settings/shadows.rst | 9 +++++++++ files/settings-default.cfg | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 6e45bdd22..6c71a9c0f 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -123,10 +123,15 @@ namespace SceneUtil } void ShadowManager::enableIndoorMode() { - mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); + if (Settings::Manager::getBool("enable indoor shadows", "Shadows")) + mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); + else + mShadowTechnique->disableShadows(); } void ShadowManager::enableOutdoorMode() { + if (mEnableShadows) + mShadowTechnique->enableShadows(); mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); } } diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 34d484925..b88df8942 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -121,7 +121,16 @@ object shadows Allow static objects to cast shadows. Potentially decreases performance. +enable indoor shadows +--------------------- + +:Type: boolean +:Range: True/False +:Default: False +Allow shadows indoors. +Due to limitations with Morrowind's data, only actors can cast shadows indoors without the ceiling casting a shadow everywhere. +Some might feel this is distracting as shadows can be cast through other objects, so indoor shadows can be disabled completely. Expert settings *************** diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 41063929e..21af22566 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -549,3 +549,5 @@ player shadows = false terrain shadows = false # Allow world objects to cast shadows. Potentially decreases performance. object shadows = false +# Allow shadows indoors. Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting. +enable indoor shadows = true \ No newline at end of file From 1098bd2467e0287787b8f503df007eaf9a63b2e2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 14 Aug 2018 21:35:23 +0100 Subject: [PATCH 127/168] Optimise lighting.glsl for Mesa users. --- files/shaders/lighting.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index d234aaaad..c70d0a59a 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -35,12 +35,12 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow vec3 diffuseLight, ambientLight; perLight(ambientLight, diffuseLight, 0, viewPos, viewNormal, diffuse, ambient); #if PER_PIXEL_LIGHTING - lightResult.xyz += ambientLight + diffuseLight * shadowing; + lightResult.xyz += diffuseLight * shadowing - diffuseLight; // This light gets added a second time in the loop to fix Mesa users' slowdown, so we need to negate its contribution here. #else shadowDiffuse = diffuseLight; - lightResult.xyz += ambientLight; + lightResult.xyz -= shadowDiffuse; // This light gets added a second time in the loop to fix Mesa users' slowdown, so we need to negate its contribution here. #endif - for (int i=1; i Date: Thu, 16 Aug 2018 23:48:19 +0100 Subject: [PATCH 128/168] Fix ConvexHull::extendTowardsNegativeZ --- components/sceneutil/mwshadowtechnique.cpp | 154 ++++++++++++--------- 1 file changed, 88 insertions(+), 66 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 963aa1c07..64cef25a6 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1831,42 +1831,58 @@ struct ConvexHull } }; - bool shouldBeDeleted(osg::Vec3d vertex, std::set &extremeVertices) + Vertices findInternalEdges(osg::Vec3d mainVertex, Vertices connectedVertices) { - // A vertex should be deleted if there is no route -Z-wards to an extreme vertex - // equivalent to all -Z-wards vertices being deletable. - if (extremeVertices.find(vertex) != extremeVertices.end()) - return false; - for (Edge edge : _edges) + Vertices internalEdgeVertices; + for (auto vertex : connectedVertices) { - osg::Vec3d otherEnd; - if (edge.first == vertex) - otherEnd = edge.second; - else if (edge.second == vertex) - otherEnd = edge.first; - else - continue; - - if (otherEnd.z() >= vertex.z()) - continue; - - if (!shouldBeDeleted(otherEnd, extremeVertices)) - return false; + osg::Matrixd matrix; + osg::Vec3d dir = vertex - mainVertex; + matrix.makeLookAt(mainVertex, vertex, dir.z() == 0 ? osg::Vec3d(0, 0, 1) : osg::Vec3d(1, 0, 0)); + Vertices testVertices; + for (auto testVertex : connectedVertices) + { + if (vertex != testVertex) + testVertices.push_back(testVertex); + } + std::vector bearings; + for (auto testVertex : testVertices) + { + osg::Vec3d transformedVertex = testVertex * matrix; + bearings.push_back(atan2(transformedVertex.y(), transformedVertex.x())); + } + std::sort(bearings.begin(), bearings.end()); + bool keep = false; + for (auto itr = bearings.begin(); itr + 1 != bearings.end(); ++itr) + { + if (*itr + osg::PI < *(itr + 1)) + { + keep = true; + break; + } + } + if (!keep && bearings[0] + osg::PI > bearings.back()) + keep = true; + if (!keep) + internalEdgeVertices.push_back(vertex); } - - return true; + return internalEdgeVertices; } void extendTowardsNegativeZ() { typedef std::set VertexSet; + double lowestPoint = DBL_MAX; + // Collect the set of vertices VertexSet vertices; for (Edge edge : _edges) { vertices.insert(edge.first); vertices.insert(edge.second); + lowestPoint = osg::minimum(lowestPoint, edge.first.z()); + lowestPoint = osg::minimum(lowestPoint, edge.second.z()); } if (vertices.size() == 0) @@ -1884,70 +1900,76 @@ struct ConvexHull // Add edge loop to 'seal' the hull for (auto itr = extremeVertices.cbegin(); itr != extremeVertices.cend() - 1; ++itr) finalEdges.push_back(Edge(osg::Vec3d(itr->x(), itr->y(), -DBL_MAX), osg::Vec3d((itr + 1)->x(), (itr + 1)->y(), -DBL_MAX))); - // The convex hull algorithm we are using places a point at both ends of the vector, so we don't need to add the last edge separately. - // finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX))); + // The convex hull algorithm we are using sometimes places a point at both ends of the vector, so we don't always need to add the last edge separately. + if (extremeVertices.front() != extremeVertices.back()) + finalEdges.push_back(Edge(osg::Vec3d(extremeVertices.front().x(), extremeVertices.front().y(), -DBL_MAX), osg::Vec3d(extremeVertices.back().x(), extremeVertices.back().y(), -DBL_MAX))); - // Collect the first layer of unneeded vertices and remove the edges connecting them to the rest of the mesh - VertexSet deletedVertices; - for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */ ) + // Just in case using -DBL_MAX upsets some of the maths, we pretend we've only extended the volume by a little bit. + lowestPoint -= 1.0; + // Remove internal edges connected to extreme vertices + for (auto vertex : extremeVertices) { - if (extremeVerticesSet.find(edgeItr->first) != extremeVerticesSet.end()) + Vertices connectedVertices; + for (Edge edge : _edges) { - if (extremeVerticesSet.find(edgeItr->second) == extremeVerticesSet.end()) - { - if (edgeItr->first.z() >= edgeItr->second.z()) - { - // If we can travel along edges towards -Z and reach an extreme vertex, the current edge must be kept - if (shouldBeDeleted(edgeItr->second, extremeVerticesSet)) - { - deletedVertices.insert(edgeItr->second); - edgeItr = _edges.erase(edgeItr); - continue; - } - } - } + if (edge.first == vertex) + connectedVertices.push_back(edge.second); + else if (edge.second == vertex) + connectedVertices.push_back(edge.first); } - else if (extremeVerticesSet.find(edgeItr->second) != extremeVerticesSet.end()) + connectedVertices.push_back(osg::Vec3d(vertex.x(), vertex.y(), lowestPoint)); + + Vertices unwantedEdgeEnds = findInternalEdges(vertex, connectedVertices); + for (auto edgeEnd : unwantedEdgeEnds) { - if (edgeItr->second.z() >= edgeItr->first.z()) + for (auto itr = _edges.begin(); itr != _edges.end(); ++itr) { - if (shouldBeDeleted(edgeItr->first, extremeVerticesSet)) + if (*itr == Edge(vertex, edgeEnd)) { - deletedVertices.insert(edgeItr->first); - edgeItr = _edges.erase(edgeItr); - continue; + _edges.erase(itr); + break; + } + else if (*itr == Edge(edgeEnd, vertex)) + { + _edges.erase(itr); + break; } } } - ++edgeItr; } - // Remove all edges connected to removed vertices - bool modifiedSomething = true; - while (modifiedSomething) + // Gather connected vertices + VertexSet unprocessedConnectedVertices(extremeVertices.begin(), extremeVertices.end()); + VertexSet connectedVertices; + while (unprocessedConnectedVertices.size() > 0) { - modifiedSomething = false; - for (auto edgeItr = _edges.begin(); edgeItr != _edges.end(); /* nothing */) + osg::Vec3d vertex = *unprocessedConnectedVertices.begin(); + unprocessedConnectedVertices.erase(unprocessedConnectedVertices.begin()); + connectedVertices.insert(vertex); + for (Edge edge : _edges) { - if (deletedVertices.find(edgeItr->first) != deletedVertices.end()) - { - deletedVertices.insert(edgeItr->second); - edgeItr = _edges.erase(edgeItr); - modifiedSomething = true; + osg::Vec3d otherEnd; + if (edge.first == vertex) + otherEnd = edge.second; + else if (edge.second == vertex) + otherEnd - edge.first; + else continue; - } - else if (deletedVertices.find(edgeItr->second) != deletedVertices.end()) - { - deletedVertices.insert(edgeItr->first); - edgeItr = _edges.erase(edgeItr); - modifiedSomething = true; + + if (connectedVertices.count(otherEnd)) continue; - } - ++edgeItr; + + unprocessedConnectedVertices.insert(otherEnd); } } - _edges.splice(_edges.end(), finalEdges); + for (Edge edge : _edges) + { + if (connectedVertices.count(edge.first) || connectedVertices.count(edge.second)) + finalEdges.push_back(edge); + } + + _edges = finalEdges; } void transform(const osg::Matrixd& m) From dd501f4132dac60c1f95640e564040f8bd2346d5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 17 Aug 2018 17:47:52 +0100 Subject: [PATCH 129/168] Make ConvexHull::clip more resilient against large values. --- components/sceneutil/mwshadowtechnique.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 64cef25a6..c3bf99c96 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2067,6 +2067,14 @@ struct ConvexHull ++itr) { center += *itr; + + center.x() = osg::maximum(center.x(), -DBL_MAX); + center.y() = osg::maximum(center.y(), -DBL_MAX); + center.z() = osg::maximum(center.z(), -DBL_MAX); + + center.x() = osg::minimum(center.x(), DBL_MAX); + center.y() = osg::minimum(center.y(), DBL_MAX); + center.z() = osg::minimum(center.z(), DBL_MAX); } center /= double(intersections.size()); From 3ce96997d154d7272874fcf63ea4ef9421531593 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 18 Aug 2018 00:09:40 +0100 Subject: [PATCH 130/168] Remove sneaky tabs. --- components/shader/shadermanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 94b87504b..2ede0abc2 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -172,7 +172,7 @@ namespace Shader size_t contentEnd = source.find("$endforeach", contentStart); if (contentEnd == std::string::npos) { - Log(Debug::Error) << "Unexpected EOF"; + Log(Debug::Error) << "Unexpected EOF"; return false; } std::string content = source.substr(contentStart, contentEnd - contentStart); @@ -234,7 +234,7 @@ namespace Shader size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); if (iterNameEnd == std::string::npos) { - Log(Debug::Error) << "Unexpected EOF"; + Log(Debug::Error) << "Unexpected EOF"; return false; } forIterators.push_back(source.substr(iterNameStart, iterNameEnd - iterNameStart)); @@ -244,7 +244,7 @@ namespace Shader source.replace(foundPos, 1, "$"); if (forIterators.empty()) { - Log(Debug::Error) << "endforeach without foreach"; + Log(Debug::Error) << "endforeach without foreach"; return false; } else @@ -264,7 +264,7 @@ namespace Shader } else { - Log(Debug::Error) << "Undefined " << define; + Log(Debug::Error) << "Undefined " << define; return false; } } From 15e820825fc6e6d159f4c524fc09a9fc89036e24 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 21 Aug 2018 14:00:29 +0100 Subject: [PATCH 131/168] Fix another convex hull clipping issue and restore z-clipping --- components/sceneutil/mwshadowtechnique.cpp | 34 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index c3bf99c96..b90f67ff6 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -2079,7 +2079,7 @@ struct ConvexHull center /= double(intersections.size()); - typedef std::map VertexMap; + typedef std::map>> VertexMap; VertexMap vertexMap; for(Vertices::iterator itr = intersections.begin(); itr != intersections.end(); @@ -2090,16 +2090,38 @@ struct ConvexHull double v = dv * up; double angle = atan2(h,v); // OSG_NOTICE<<"angle = "<second + std::string("UV")] = std::to_string(texIt->first); } - if (!reqs.mColorMaterial) - defineMap["colorMode"] = "0"; - else - { - switch (reqs.mVertexColorMode) - { - case GL_AMBIENT: - defineMap["colorMode"] = "3"; - break; - default: - case GL_AMBIENT_AND_DIFFUSE: - defineMap["colorMode"] = "2"; - break; - case GL_EMISSION: - defineMap["colorMode"] = "1"; - break; - } - } - defineMap["forcePPL"] = mForcePerPixelLighting ? "1" : "0"; defineMap["clamp"] = mClampLighting ? "1" : "0"; diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index cb0538d9d..eab75acbb 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -81,9 +81,6 @@ namespace Shader bool mShaderRequired; - bool mColorMaterial; - // osg::Material::ColorMode - int mVertexColorMode; bool mMaterialOverridden; bool mNormalHeight; // true if normal map has height info in alpha channel diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index a0f051524..83684b5c9 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -218,7 +218,6 @@ namespace Terrain defineMap["clamp"] = clampLighting ? "1" : "0"; defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; defineMap["blendMap"] = !firstLayer ? "1" : "0"; - defineMap["colorMode"] = "2"; defineMap["specularMap"] = it->mSpecular ? "1" : "0"; defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0"; @@ -231,6 +230,7 @@ namespace Terrain } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); + stateset->addUniform(new osg::Uniform("colorMode", 2)); } else { diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index d234aaaad..ff6ee9419 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -1,5 +1,7 @@ #define MAX_LIGHTS 8 +uniform int colorMode; + void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal, vec4 diffuse, vec3 ambient) { vec3 lightDir; @@ -20,16 +22,23 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, float shadowing vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadowDiffuse) #endif { -#if @colorMode == 3 - vec4 diffuse = gl_FrontMaterial.diffuse; - vec3 ambient = vertexColor.xyz; -#elif @colorMode == 2 - vec4 diffuse = vertexColor; - vec3 ambient = vertexColor.xyz; -#else - vec4 diffuse = gl_FrontMaterial.diffuse; - vec3 ambient = gl_FrontMaterial.ambient.xyz; -#endif + vec4 diffuse; + vec3 ambient; + if (colorMode == 3) + { + diffuse = gl_FrontMaterial.diffuse; + ambient - vertexColor.xyz; + } + else if (colorMode == 2) + { + diffuse = vertexColor; + ambient = vertexColor.xyz; + } + else + { + diffuse = gl_FrontMaterial.diffuse; + ambient = gl_FrontMaterial.ambient.xyz; + } vec4 lightResult = vec4(0.0, 0.0, 0.0, diffuse.a); vec3 diffuseLight, ambientLight; @@ -48,11 +57,10 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow lightResult.xyz += gl_LightModel.ambient.xyz * ambient; -#if @colorMode == 1 - lightResult.xyz += vertexColor.xyz; -#else - lightResult.xyz += gl_FrontMaterial.emission.xyz; -#endif + if (colorMode == 1) + lightResult.xyz += vertexColor.xyz; + else + lightResult.xyz += gl_FrontMaterial.emission.xyz; #if @clamp lightResult = clamp(lightResult, vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0)); From 474770eca87209f813cf11ff64f902b0e7e5cc0e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 16 Oct 2018 21:23:31 +0100 Subject: [PATCH 134/168] Switch shadow map rendering to a specialised, simplified shader. --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- components/nifosg/nifloader.cpp | 1 + components/sceneutil/mwshadowtechnique.cpp | 18 +++++++++++++++ components/sceneutil/mwshadowtechnique.hpp | 4 ++++ components/sceneutil/shadow.cpp | 4 +++- components/sceneutil/shadow.hpp | 2 +- components/shader/shadervisitor.cpp | 7 ++++++ files/shaders/CMakeLists.txt | 2 ++ files/shaders/shadowcasting_fragment.glsl | 17 ++++++++++++++ files/shaders/shadowcasting_vertex.glsl | 27 ++++++++++++++++++++++ 10 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 files/shaders/shadowcasting_fragment.glsl create mode 100644 files/shaders/shadowcasting_vertex.glsl diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a186ed8e9..c3e68aa68 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -239,7 +239,7 @@ namespace MWRender if (Settings::Manager::getBool("object shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Object; - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index eb20b7702..f37f271ed 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1249,6 +1249,7 @@ namespace NifOsg boundTextures.clear(); } + // If this loop is changed such that the base texture isn't guaranteed to end up in texture unit 0, the shadow casting shader will need to be updated accordingly. for (int i=0; itextures[i].inUse) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 36f7dfbb7..8c36c5e71 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -820,6 +820,16 @@ void SceneUtil::MWShadowTechnique::setSplitPointDeltaBias(double bias) _splitPointDeltaBias = bias; } +void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) +{ + // This can't be part of the constructor as OSG mandates that there be a trivial constructor available + + _castingProgram = new osg::Program(); + + _castingProgram->addShader(shaderManager.getShader("shadowcasting_vertex.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::VERTEX)); + _castingProgram->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::FRAGMENT)); +} + MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/) { return new ViewDependentData(this); @@ -1480,6 +1490,14 @@ void MWShadowTechnique::createShaders() _fallbackShadowMapTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST); } + + if (!_castingProgram) + OSG_NOTICE << "Shadow casting shader has not been set up. Remember to call setupCastingShader(Shader::ShaderManager &)" << std::endl; + + _shadowCastingStateSet->setAttributeAndModes(_castingProgram, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied + _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); + _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); } osg::Polytope MWShadowTechnique::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 875edbc1c..558ad49d9 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -27,6 +27,7 @@ #include +#include #include namespace SceneUtil { @@ -73,6 +74,8 @@ namespace SceneUtil { virtual void setSplitPointDeltaBias(double bias); + virtual void setupCastingShader(Shader::ShaderManager &shaderManager); + class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack { public: @@ -265,6 +268,7 @@ namespace SceneUtil { }; osg::ref_ptr _debugHud; + osg::ref_ptr _castingProgram; }; } diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 6c71a9c0f..65754629e 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -68,7 +68,7 @@ namespace SceneUtil stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask) : mShadowedScene(new osgShadow::ShadowedScene), + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene), mShadowTechnique(new MWShadowTechnique), mOutdoorShadowCastingMask(outdoorShadowCastingMask), mIndoorShadowCastingMask(indoorShadowCastingMask) @@ -81,6 +81,8 @@ namespace SceneUtil mShadowSettings = mShadowedScene->getShadowSettings(); setupShadowSettings(); + mShadowTechnique->setupCastingShader(shaderManager); + enableOutdoorMode(); } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 682904650..26e119d88 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -16,7 +16,7 @@ namespace SceneUtil public: static void disableShadowsForStateSet(osg::ref_ptr stateSet); - ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager); virtual ~ShadowManager() = default; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 4556c05a6..457da5c77 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -215,6 +215,13 @@ namespace Shader mRequirements.back().mShaderRequired = true; } } + + if (diffuseMap) + { + if (!writableStateSet) + writableStateSet = getWritableStateSet(node); + writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); + } } const osg::StateSet::AttributeList& attributes = stateset->getAttributeList(); diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 41763f3e1..8012c2bc1 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -20,6 +20,8 @@ set(SHADER_FILES s360_vertex.glsl shadows_vertex.glsl shadows_fragment.glsl + shadowcasting_vertex.glsl + shadowcasting_fragment.glsl ) copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") diff --git a/files/shaders/shadowcasting_fragment.glsl b/files/shaders/shadowcasting_fragment.glsl new file mode 100644 index 000000000..6459467b1 --- /dev/null +++ b/files/shaders/shadowcasting_fragment.glsl @@ -0,0 +1,17 @@ +#version 120 + +uniform sampler2D diffuseMap; +varying vec2 diffuseMapUV; + +varying float alphaPassthrough; + +uniform bool useDiffuseMapForShadowAlpha; + +void main() +{ + gl_FragData[0].rgb = vec3(1.0); + if (useDiffuseMapForShadowAlpha) + gl_FragData[0].a = texture2D(diffuseMap, diffuseMapUV).a * alphaPassthrough; + else + gl_FragData[0].a = alphaPassthrough; +} diff --git a/files/shaders/shadowcasting_vertex.glsl b/files/shaders/shadowcasting_vertex.glsl new file mode 100644 index 000000000..d578e97b7 --- /dev/null +++ b/files/shaders/shadowcasting_vertex.glsl @@ -0,0 +1,27 @@ +#version 120 + +varying vec2 diffuseMapUV; + +varying float alphaPassthrough; + +uniform int colorMode; +uniform bool useDiffuseMapForShadowAlpha; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + + vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); + gl_ClipVertex = viewPos; + + if (useDiffuseMapForShadowAlpha) + diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; + else + diffuseMapUV = vec2(0.0); // Avoid undefined behaviour if running on hardware predating the concept of dynamically uniform expressions + + if (colorMode == 2) + alphaPassthrough = gl_Color.a; + else + // This is uniform, so if it's too low, we might be able to put the position/clip vertex outside the view frustum and skip the fragment shader and rasteriser + alphaPassthrough = gl_FrontMaterial.diffuse.a; +} From 85b97d19d302e55c2f767f5c45bb34527206a328 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 17 Oct 2018 14:02:26 +0100 Subject: [PATCH 135/168] Add alpha threshold for shadow casting. --- files/shaders/shadowcasting_fragment.glsl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/files/shaders/shadowcasting_fragment.glsl b/files/shaders/shadowcasting_fragment.glsl index 6459467b1..00b8f9aa1 100644 --- a/files/shaders/shadowcasting_fragment.glsl +++ b/files/shaders/shadowcasting_fragment.glsl @@ -14,4 +14,8 @@ void main() gl_FragData[0].a = texture2D(diffuseMap, diffuseMapUV).a * alphaPassthrough; else gl_FragData[0].a = alphaPassthrough; + + // Prevent translucent things casting shadow (including the player using an invisibility effect) + if (gl_FragData[0].a < 0.5) + discard; } From a41ce42208350b2fdb7a93efa4db9d0653b882d8 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 18 Oct 2018 16:00:51 +0100 Subject: [PATCH 136/168] Move setting of colorMode to ShaderRequirements in case they're reused --- components/shader/shadervisitor.cpp | 5 ++++- components/shader/shadervisitor.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 457da5c77..fad43a3a1 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -23,6 +23,7 @@ namespace Shader ShaderVisitor::ShaderRequirements::ShaderRequirements() : mShaderRequired(false) + , mColorMode(2) , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) @@ -257,7 +258,7 @@ namespace Shader break; } - writableStateSet->addUniform(new osg::Uniform("colorMode", colorMode)); + mRequirements.back().mColorMode = colorMode; } } } @@ -303,6 +304,8 @@ namespace Shader defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; + writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); + osg::ref_ptr vertexShader (mShaderManager.getShader(mDefaultVsTemplate, defineMap, osg::Shader::VERTEX)); osg::ref_ptr fragmentShader (mShaderManager.getShader(mDefaultFsTemplate, defineMap, osg::Shader::FRAGMENT)); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index eab75acbb..8737baf59 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -81,6 +81,8 @@ namespace Shader bool mShaderRequired; + int mColorMode; + bool mMaterialOverridden; bool mNormalHeight; // true if normal map has height info in alpha channel From b0907f89296019babf4f528ede1d22377987770e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 18 Oct 2018 16:01:36 +0100 Subject: [PATCH 137/168] Add todos in case they're left until after the shadow PR is merged --- components/sceneutil/mwshadowtechnique.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 8c36c5e71..8f42f8fcd 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1498,6 +1498,10 @@ void MWShadowTechnique::createShaders() // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + + // TODO: figure out if there's some way to disable depth sorting for translucent objects as we don't care about blending. + // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader + // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches } osg::Polytope MWShadowTechnique::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight) From e22ab64ebf4a791c2b27228844b22ae771be34b6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 22 Oct 2018 17:35:01 +0100 Subject: [PATCH 138/168] Fix typo in lighting.glsl --- files/shaders/lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index ff6ee9419..5c21b7bee 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -27,7 +27,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor, out vec3 shadow if (colorMode == 3) { diffuse = gl_FrontMaterial.diffuse; - ambient - vertexColor.xyz; + ambient = vertexColor.xyz; } else if (colorMode == 2) { From 1ca7ea23d17760003b3441138cba1907c5ead3c7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 30 Oct 2018 17:07:11 +0000 Subject: [PATCH 139/168] Add extra uniforms to the disabled shadows StateSet so that the shadow texture samplers are bound ot the dummy shadow maps correctly. --- components/sceneutil/shadow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 65754629e..c2c728e12 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -65,7 +65,11 @@ namespace SceneUtil fakeShadowMapTexture->setShadowComparison(true); fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); for (int i = baseShadowTextureUnit; i < baseShadowTextureUnit + numberOfShadowMapsPerLight; ++i) + { stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + stateset->addUniform(new osg::Uniform(("shadowTexture" + std::to_string(i - baseShadowTextureUnit)).c_str(), i)); + stateset->addUniform(new osg::Uniform(("shadowTextureUnit" + std::to_string(i - baseShadowTextureUnit)).c_str(), i)); + } } ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene), From eb44de3e6bf006d24f315a2706908bf49c525f02 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 30 Oct 2018 22:34:53 +0000 Subject: [PATCH 140/168] Disable shadows properly for water reflection/refraction RTT targets, eliminating remaining OpenGL errors. --- apps/openmw/mwrender/water.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9ad7dc8dd..376924d82 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -263,6 +264,8 @@ public: mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture); + + SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet()); } void setScene(osg::Node* scene) @@ -341,6 +344,8 @@ public: mClipCullNode = new ClipCullNode; addChild(mClipCullNode); + + SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet()); } void setWaterLevel(float waterLevel) From ad9dab8593bbe0536c7e92f2bbc250bda99f8e23 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Nov 2018 16:20:56 +0000 Subject: [PATCH 141/168] Switch alpha test from < to <= to fix weird shadows on actors with 50% chameleon --- files/shaders/shadowcasting_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/shadowcasting_fragment.glsl b/files/shaders/shadowcasting_fragment.glsl index 00b8f9aa1..336bfe4a4 100644 --- a/files/shaders/shadowcasting_fragment.glsl +++ b/files/shaders/shadowcasting_fragment.glsl @@ -16,6 +16,6 @@ void main() gl_FragData[0].a = alphaPassthrough; // Prevent translucent things casting shadow (including the player using an invisibility effect) - if (gl_FragData[0].a < 0.5) + if (gl_FragData[0].a <= 0.5) discard; } From 0bafa4399bbd79ece70effbd880872e22a29afeb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 3 Nov 2018 16:56:33 +0000 Subject: [PATCH 142/168] Use distant shadow maps when the current fragment is outside the depth range of the near ones. --- files/shaders/shadows_fragment.glsl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index ce9e958d1..220e00efa 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -16,12 +16,13 @@ float unshadowedLightRatio() @foreach shadow_texture_unit_index @shadow_texture_unit_list if (!doneShadows) { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; + vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; + vec2 shadowXY = shadowXYZ.xy; if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) { shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) + if (all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0)))) doneShadows = true; } } From 660e423e9933d85b897297ee21a344cb9f3e657d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 20 Nov 2018 23:01:04 +0000 Subject: [PATCH 143/168] Correct debug hud frustum colour --- components/sceneutil/mwshadowtechnique.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 8f42f8fcd..598a663d3 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -115,7 +115,7 @@ std::string debugFragmentShaderSource = #endif "} \n"; -std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z;}"; +std::string debugFrustumVertexShaderSource = "varying float depth; uniform mat4 transform; void main(void){gl_Position = transform * gl_Vertex; depth = gl_Position.z / gl_Position.w;}"; std::string debugFrustumFragmentShaderSource = "varying float depth; \n" " \n" From 632b0d8979c56eb79df2fa7db9a2580bc8a0d8a9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 20 Nov 2018 23:02:28 +0000 Subject: [PATCH 144/168] Make shadow maps use their whole depth range for the overlap with the view frustum and rely on depth clamping to ensure objects outside the frustum still cast shadows. --- components/sceneutil/mwshadowtechnique.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 598a663d3..e26cfbe76 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1499,6 +1499,8 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); + // TODO: figure out if there's some way to disable depth sorting for translucent objects as we don't care about blending. // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches @@ -2437,12 +2439,12 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam xMax = osg::minimum(1.0, convexHull.max(0)); yMin = osg::maximum(-1.0, convexHull.min(1)); yMax = osg::minimum(1.0, convexHull.max(1)); + zMin = osg::maximum(-1.0, convexHull.min(2)); + zMax = osg::minimum(1.0, convexHull.max(2)); } else return false; - // we always want the lightspace to include the computed near plane. - zMin = -1.0; if (xMin != -1.0 || yMin != -1.0 || zMin != -1.0 || xMax != 1.0 || yMax != 1.0 || zMax != 1.0) { @@ -2464,11 +2466,14 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam xMax = convexHull.max(0); yMin = convexHull.min(1); yMax = convexHull.max(1); + zMax = convexHull.max(2); planeList.push_back(osg::Plane(0.0, -1.0, 0.0, yMax)); planeList.push_back(osg::Plane(0.0, 1.0, 0.0, -yMin)); planeList.push_back(osg::Plane(-1.0, 0.0, 0.0, xMax)); planeList.push_back(osg::Plane(1.0, 0.0, 0.0, -xMin)); + planeList.push_back(osg::Plane(0.0, 0.0, -1.0, zMax)); + // Don't add a zMin culling plane - we still want those objects, but don't care about their depth buffer value. } return true; From 061fa57335b5df1329204cbb45a516778e694031 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 21 Nov 2018 22:38:50 +0000 Subject: [PATCH 145/168] Switch to better-performing data types for debug hud geometry --- components/sceneutil/mwshadowtechnique.cpp | 13 +++++++++---- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e26cfbe76..fa62ae1fa 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -942,7 +942,12 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) Frustum frustum(&cv, minZNear, maxZFar); if (_debugHud) - _debugHud->setFrustumVertices(new osg::Vec3dArray(8, &frustum.corners[0])); + { + osg::ref_ptr vertexArray = new osg::Vec3Array(8); + for (osg::Vec3d &vertex : frustum.corners) + vertexArray->push_back((osg::Vec3)vertex); + _debugHud->setFrustumVertices(vertexArray); + } double reducedNear, reducedFar; if (cv.getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) @@ -2984,7 +2989,7 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) mFrustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); //mFrustumGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - osg::ref_ptr frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINE_STRIP); + osg::ref_ptr frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP); mFrustumGeometry->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(0); frustumDrawElements->push_back(1); @@ -2997,7 +3002,7 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) frustumDrawElements->push_back(7); frustumDrawElements->push_back(4); - frustumDrawElements = new osg::DrawElementsUByte(osg::PrimitiveSet::LINES); + frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINES); mFrustumGeometry->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(1); frustumDrawElements->push_back(5); @@ -3044,7 +3049,7 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) mFrustumGeometry->releaseGLObjects(state); } -void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) +void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) { mFrustumGeometry->setVertexArray(vertices); } diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 558ad49d9..e1f288495 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -253,7 +253,7 @@ namespace SceneUtil { virtual void releaseGLObjects(osg::State* state = 0) const; - virtual void setFrustumVertices(osg::ref_ptr vertices); + virtual void setFrustumVertices(osg::ref_ptr vertices); protected: virtual void addAnotherShadowMap(); From 7ad4882f0c0ee3aab47bf14abf504bfb364f9bb6 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 21 Nov 2018 23:45:47 +0000 Subject: [PATCH 146/168] Fix debug hud frustum outline disappearence --- components/sceneutil/mwshadowtechnique.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index fa62ae1fa..8f8b9aa96 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -943,7 +943,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) Frustum frustum(&cv, minZNear, maxZFar); if (_debugHud) { - osg::ref_ptr vertexArray = new osg::Vec3Array(8); + osg::ref_ptr vertexArray = new osg::Vec3Array(); for (osg::Vec3d &vertex : frustum.corners) vertexArray->push_back((osg::Vec3)vertex); _debugHud->setFrustumVertices(vertexArray); From aa118329498c681eca55d46f7ed8f082bc268d46 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 29 Nov 2018 01:17:58 +0000 Subject: [PATCH 147/168] Resolve bugs with depth-clamped shadow maps --- components/sceneutil/mwshadowtechnique.cpp | 46 +++++++++++++++++----- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 8f8b9aa96..0161891d3 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -326,9 +326,9 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) OSG_INFO<<"RTT Projection matrix after clamping "<setProjectionMatrix(projection); - - _projectionMatrix = cv->getProjectionMatrix(); } + + _projectionMatrix = cv->getProjectionMatrix(); } MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : @@ -552,9 +552,16 @@ MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData* //_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); _camera->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f)); - _camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES); + // Now we are using Depth Clamping, we want to not cull things on the wrong side of the near plane. + // When the near and far planes are computed, OSG always culls anything on the wrong side of the near plane, even if it's told not to. + // Even if that weren't an issue, the near plane can't go past any shadow receivers or the depth-clamped fragments which ended up on the near plane can't cast shadows on those receivers. + // Unfortunately, this change will make shadows have less depth precision when there are no casters outside the view frustum. + // TODO: Find a better solution. E.g. detect when there are no casters outside the view frustum, write a new cull visitor that does all the wacky things we'd need it to. + _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + // switch off small feature culling as this can cull out geometry that will still be large enough once perspective correction takes effect. _camera->setCullingMode(_camera->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING); @@ -2432,8 +2439,6 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam convexHull.transform(light_vp); - convexHull.extendTowardsNegativeZ(); - double xMin = -1.0, xMax = 1.0; double yMin = -1.0, yMax = 1.0; double zMin = -1.0, zMax = 1.0; @@ -2471,14 +2476,15 @@ bool MWShadowTechnique::cropShadowCameraToMainFrustum(Frustum& frustum, osg::Cam xMax = convexHull.max(0); yMin = convexHull.min(1); yMax = convexHull.max(1); - zMax = convexHull.max(2); + zMin = convexHull.min(2); planeList.push_back(osg::Plane(0.0, -1.0, 0.0, yMax)); planeList.push_back(osg::Plane(0.0, 1.0, 0.0, -yMin)); planeList.push_back(osg::Plane(-1.0, 0.0, 0.0, xMax)); planeList.push_back(osg::Plane(1.0, 0.0, 0.0, -xMin)); - planeList.push_back(osg::Plane(0.0, 0.0, -1.0, zMax)); - // Don't add a zMin culling plane - we still want those objects, but don't care about their depth buffer value. + // In view space, the light is at the most positive value, and we want to cull stuff beyond the minimum value. + planeList.push_back(osg::Plane(0.0, 0.0, 1.0, -zMin)); + // Don't add a zMax culling plane - we still want those objects, but don't care about their depth buffer value. } return true; @@ -2531,6 +2537,8 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render convexHull.transform(light_vp); + ConvexHull convexHullUnextended = convexHull; + convexHull.extendTowardsNegativeZ(); #if 0 @@ -2581,6 +2589,9 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render #if 1 convexHull.clip(osg::Plane(1.0,0.0,0.0,-rli.min_x)); convexHull.clip(osg::Plane(-1.0,0.0,0.0,rli.max_x)); + + convexHullUnextended.clip(osg::Plane(1.0, 0.0, 0.0, -rli.min_x)); + convexHullUnextended.clip(osg::Plane(-1.0, 0.0, 0.0, rli.max_x)); #else convexHull.clip(osg::Plane(1.0,0.0,0.0,widest_x)); convexHull.clip(osg::Plane(-1.0,0.0,0.0,widest_x)); @@ -2588,12 +2599,18 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render #if 1 convexHull.clip(osg::Plane(0.0,1.0,0.0,-rli.min_y)); convexHull.clip(osg::Plane(0.0,-1.0,0.0,rli.max_y)); + + convexHullUnextended.clip(osg::Plane(0.0, 1.0, 0.0, -rli.min_y)); + convexHullUnextended.clip(osg::Plane(0.0, -1.0, 0.0, rli.max_y)); #endif #endif #if 1 convexHull.clip(osg::Plane(0.0,0.0,1.0,-rli.min_z)); convexHull.clip(osg::Plane(0.0,0.0,-1.0,rli.max_z)); + + convexHullUnextended.clip(osg::Plane(0.0, 0.0, 1.0, -rli.min_z)); + convexHullUnextended.clip(osg::Plane(0.0, 0.0, -1.0, rli.max_z)); #elif 0 convexHull.clip(osg::Plane(0.0,0.0,1.0,1.0)); convexHull.clip(osg::Plane(0.0,0.0,-1.0,1.0)); @@ -2656,6 +2673,7 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render 2.0/(zMax-zMin))); convexHull.transform(m); + convexHullUnextended.transform(m); light_p.postMult(m); light_vp = light_v * light_p; @@ -2748,6 +2766,12 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render //min_z_ratio = convexHull.minRatio(virtual_eye,2); //max_z_ratio = convexHull.maxRatio(virtual_eye,2); + if (convexHullUnextended.valid()) + { + min_z_ratio = convexHullUnextended.minRatio(virtual_eye, 2); + max_z_ratio = convexHullUnextended.maxRatio(virtual_eye, 2); + } + #if 0 OSG_NOTICE<<"convexHull min_x_ratio = "<setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows")); + mShadowTechnique->setPolygonOffset(Settings::Manager::getFloat("polygon offset factor", "Shadows"), Settings::Manager::getFloat("polygon offset units", "Shadows")); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED); else diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index b88df8942..8ab9c2539 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -135,10 +135,34 @@ Some might feel this is distracting as shadows can be cast through other objects Expert settings *************** -You probably shouldn't be changing these yourself if you haven't read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. -If you have, then you may get better results tuning these for your specific view distance. +These settings are probably too complicated for regular users to judge what might be good values to set them to. +If you've got a good understanding of how shadow mapping works, or you've got enough time to try a large set of values, you may get better results tuning these yourself. Copying values from another user who's done careful tuning is the recommended way of arriving at an optimal value for these settings. +Understanding what some of these do might be easier for people who've read `this paper on Parallel Split Shadow Maps `_ and understood how they interact with the transformation used with Light Space Perspective Shadow Maps. + +polygon offset factor +--------------------- + +:Type: float +:Range: Theoretically the whole range of 32-bit floating point, but values just above 1.0 are most sensible. +:Default: 1.1 + +Used as the factor parameter for the polygon offset used for shadow map rendering. +Higher values reduce shadow flicker, but risk increasing Peter Panning. +See `the OpenGL documentation for glPolygonOffset `_ for details. + +polygon offset units +--------------------- + +:Type: float +:Range: Theoretically the whole range of 32-bit floating point, but values between 1 and 10 are most sensible. +:Default: 4.0 + +Used as the units parameter for the polygon offset used for shadow map rendering. +Higher values reduce shadow flicker, but risk increasing Peter Panning. +See `the OpenGL documentation for glPolygonOffset `_ for details. + split point uniform logarithmic ratio ------------------------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 5e866dbfb..0ca5ad93d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -662,6 +662,10 @@ compute tight scene bounds = false shadow map resolution = 1024 # Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. Increasing this pushes detail further away. minimum lispsm near far ratio = 0.25 +# Used as the factor parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. +polygon offset factor = 1.1 +# Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. +polygon offset units = 4.0 # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false # Allow the player to cast shadows. Potentially decreases performance. From 0a409c0ab8f448df43a3921afbee5f22483a8168 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 1 Dec 2018 00:26:43 +0000 Subject: [PATCH 149/168] Make shadow map front-face culling configurable --- components/sceneutil/mwshadowtechnique.cpp | 20 +++++++++++++++++-- components/sceneutil/mwshadowtechnique.hpp | 6 ++++++ components/sceneutil/shadow.cpp | 5 +++++ .../reference/modding/settings/shadows.rst | 10 ++++++++++ files/settings-default.cfg | 2 ++ 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index eb7df28d1..5ed5e5a99 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -836,6 +836,22 @@ void SceneUtil::MWShadowTechnique::setPolygonOffset(float factor, float units) } } +void SceneUtil::MWShadowTechnique::enableFrontFaceCulling() +{ + _useFrontFaceCulling = true; + + if (_shadowCastingStateSet) + _shadowCastingStateSet->setAttribute(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); +} + +void SceneUtil::MWShadowTechnique::disableFrontFaceCulling() +{ + _useFrontFaceCulling = false; + + if (_shadowCastingStateSet) + _shadowCastingStateSet->removeAttribute(osg::StateAttribute::CULLFACE); +} + void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) { // This can't be part of the constructor as OSG mandates that there be a trivial constructor available @@ -1422,8 +1438,8 @@ void MWShadowTechnique::createShaders() // backface nor front face so they usually use CullMode off set here. // In this case we will draw them in their entirety. - _shadowCastingStateSet->setAttribute( new osg::CullFace( osg::CullFace::FRONT ), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); + if (_useFrontFaceCulling) + _shadowCastingStateSet->setAttribute(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); // make sure GL_CULL_FACE is off by default // we assume that if object has cull face attribute set to back diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index ccfb6094b..16d44c5e2 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -76,6 +76,10 @@ namespace SceneUtil { virtual void setPolygonOffset(float factor, float units); + virtual void enableFrontFaceCulling(); + + virtual void disableFrontFaceCulling(); + virtual void setupCastingShader(Shader::ShaderManager &shaderManager); class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack @@ -249,6 +253,8 @@ namespace SceneUtil { float _polygonOffsetFactor = 1.1; float _polygonOffsetUnits = 4.0; + bool _useFrontFaceCulling = true; + class DebugHUD : public osg::Referenced { public: diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e9091451d..a6559e9b9 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -44,6 +44,11 @@ namespace SceneUtil mShadowTechnique->setPolygonOffset(Settings::Manager::getFloat("polygon offset factor", "Shadows"), Settings::Manager::getFloat("polygon offset units", "Shadows")); + if (Settings::Manager::getBool("use front face culling", "Shadows")) + mShadowTechnique->enableFrontFaceCulling(); + else + mShadowTechnique->disableFrontFaceCulling(); + if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED); else diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index 8ab9c2539..c8d3250a0 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -163,6 +163,16 @@ Used as the units parameter for the polygon offset used for shadow map rendering Higher values reduce shadow flicker, but risk increasing Peter Panning. See `the OpenGL documentation for glPolygonOffset `_ for details. +use front face culling +---------------------- + +:Type: boolean +:Range: True/False +:Default: True + +Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. +In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. + split point uniform logarithmic ratio ------------------------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0ca5ad93d..df9ea3008 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -666,6 +666,8 @@ minimum lispsm near far ratio = 0.25 polygon offset factor = 1.1 # Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset units = 4.0 +# Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. +use front face culling = true # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false # Allow the player to cast shadows. Potentially decreases performance. From 244bd289cba81d41dbedc6debd60bca7b75ac5b4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 3 Dec 2018 18:56:37 +0000 Subject: [PATCH 150/168] Change default colour mode (as apparently it actually gets used sometimes) --- components/shader/shadervisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index fad43a3a1..3080e1318 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -23,7 +23,7 @@ namespace Shader ShaderVisitor::ShaderRequirements::ShaderRequirements() : mShaderRequired(false) - , mColorMode(2) + , mColorMode(0) , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) From 2d5da1a6fab2aba05ecdd477b36f026d336f2a73 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 8 Dec 2018 20:39:41 +0000 Subject: [PATCH 151/168] Don't exclusively rely on a shadow map if its bounds have been expanded since the cull traversal. --- components/sceneutil/mwshadowtechnique.cpp | 23 +++++++++++++++++ components/sceneutil/shadow.cpp | 8 ++++++ files/shaders/shadows_fragment.glsl | 30 ++++++++++++++++------ files/shaders/shadows_vertex.glsl | 9 +++++++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 5ed5e5a99..ea52ec24a 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1315,6 +1315,29 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (!orthographicViewFrustum && settings->getShadowMapProjectionHint()==ShadowSettings::PERSPECTIVE_SHADOW_MAP) { + { + osg::Matrix validRegionMatrix = cv.getCurrentCamera()->getInverseViewMatrix() * camera->getViewMatrix() * camera->getProjectionMatrix(); + + std::string validRegionUniformName = "validRegionMatrix" + std::to_string(sm_i); + osg::ref_ptr validRegionUniform; + + OpenThreads::ScopedLock lock(_accessUniformsAndProgramMutex); + + for (auto uniform : _uniforms) + { + if (uniform->getName() == validRegionUniformName) + validRegionUniform = uniform; + } + + if (!validRegionUniform) + { + validRegionUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, validRegionUniformName); + _uniforms.push_back(validRegionUniform); + } + + validRegionUniform->set(validRegionMatrix); + } + if (settings->getMultipleShadowMapHint() == ShadowSettings::CASCADED) adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get(), cascaseNear, cascadeFar); else diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index a6559e9b9..d3655dfb5 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -119,6 +119,12 @@ namespace SceneUtil else definesWithShadows["useShadowDebugOverlay"] = "0"; + // switch this to reading settings if it's ever exposed to the user + if (mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP) + definesWithShadows["perspectiveShadowMaps"] = "1"; + else + definesWithShadows["perspectiveShadowMaps"] = "0"; + return definesWithShadows; } @@ -132,6 +138,8 @@ namespace SceneUtil definesWithShadows["useShadowDebugOverlay"] = "0"; + definesWithShadows["perspectiveShadowMaps"] = "0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index 220e00efa..713473458 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -4,6 +4,10 @@ @foreach shadow_texture_unit_index @shadow_texture_unit_list uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + +#if @perspectiveShadowMaps + varying vec4 shadowRegionCoords@shadow_texture_unit_index; +#endif @endforeach #endif // SHADOWS @@ -17,13 +21,18 @@ float unshadowedLightRatio() if (!doneShadows) { vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; - vec2 shadowXY = shadowXYZ.xy; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) +#if @perspectiveShadowMaps + vec3 shadowRegionXYZ = shadowRegionCoords@shadow_texture_unit_index.xyz / shadowRegionCoords@shadow_texture_unit_index.w; +#endif + if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) { shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); - if (all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0)))) - doneShadows = true; + + doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); +#if @perspectiveShadowMaps + doneShadows = doneShadows && all(lessThan(shadowRegionXYZ, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); +#endif } } @endforeach @@ -44,8 +53,11 @@ void applyShadowDebugOverlay() @foreach shadow_texture_unit_index @shadow_texture_unit_list if (!doneOverlay) { - vec2 shadowXY = shadowSpaceCoords@shadow_texture_unit_index.xy / shadowSpaceCoords@shadow_texture_unit_index.w; - if (all(lessThan(shadowXY, vec2(1.0, 1.0))) && all(greaterThan(shadowXY, vec2(0.0, 0.0)))) + vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; +#if @perspectiveShadowMaps + vec3 shadowRegionXYZ = shadowRegionCoords@shadow_texture_unit_index.xyz / shadowRegionCoords@shadow_texture_unit_index.w; +#endif + if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) { colourIndex = mod(@shadow_texture_unit_index.0, 3.0); if (colourIndex < 1.0) @@ -55,8 +67,10 @@ void applyShadowDebugOverlay() else gl_FragData[0].z += 0.1; - if (all(lessThan(shadowXY, vec2(0.95, 0.95))) && all(greaterThan(shadowXY, vec2(0.05, 0.05)))) - doneOverlay = true; + doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); +#if @perspectiveShadowMaps + doneOverlay = doneOverlay && all(lessThan(shadowRegionXYZ.xyz, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); +#endif } } @endforeach diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl index bbc1a4036..4baa249c1 100644 --- a/files/shaders/shadows_vertex.glsl +++ b/files/shaders/shadows_vertex.glsl @@ -4,6 +4,11 @@ @foreach shadow_texture_unit_index @shadow_texture_unit_list uniform int shadowTextureUnit@shadow_texture_unit_index; varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + +#if @perspectiveShadowMaps + uniform mat4 validRegionMatrix@shadow_texture_unit_index; + varying vec4 shadowRegionCoords@shadow_texture_unit_index; +#endif @endforeach #endif // SHADOWS @@ -15,6 +20,10 @@ void setupShadowCoords(vec4 viewPos) @foreach shadow_texture_unit_index @shadow_texture_unit_list eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + +#if @perspectiveShadowMaps + shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; +#endif @endforeach #endif // SHADOWS } \ No newline at end of file From b6b1b3980483ea96459298fd6fbff3ee69fb58e1 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 10 Dec 2018 21:20:29 +0000 Subject: [PATCH 152/168] Make the terrain paging system use the view point rather than the eye point to determine which nodes to use so that it can be inherited by RTT cameras. --- components/terrain/quadtreenode.cpp | 2 +- components/terrain/quadtreeworld.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 2222cbb84..4b4df4365 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -134,7 +134,7 @@ ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv) { osgUtil::CullVisitor* cv = static_cast(&nv); ViewData* vd = mViewDataMap->getViewData(cv->getCurrentCamera()); - vd->setEyePoint(nv.getEyePoint()); + vd->setEyePoint(nv.getViewPoint()); return vd; } else // INTERSECTION_VISITOR diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 0d5b25697..6ec89721a 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -363,7 +363,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) traverseToCell(mRootNode.get(), vd, x,y); } else - traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getEyePoint(), true); + traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true); } else mRootNode->traverse(nv); From 7b108ae9a2cbc45524a86bf5d40cef34417ec357 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Dec 2018 01:45:05 +0000 Subject: [PATCH 153/168] Disable depth sorting for translucent objects in the shadow maps --- components/sceneutil/mwshadowtechnique.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index ea52ec24a..6f3d34cb1 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1554,7 +1554,8 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); - // TODO: figure out if there's some way to disable depth sorting for translucent objects as we don't care about blending. + _shadowCastingStateSet->setRenderBinDetails(osg::StateSet::OPAQUE_BIN, "RenderBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS); + // TODO: compare performance when alpha testing is handled here versus using a discard in the fragment shader // TODO: compare performance when we set a bunch of GL state to the default here with OVERRIDE set so that there are fewer pointless state switches } From 305b9826df7bc72211066b2eb9375df090ad501c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Dec 2018 16:23:32 +0000 Subject: [PATCH 154/168] Use forward declaration to reduce build times. --- components/sceneutil/shadow.cpp | 2 ++ components/sceneutil/shadow.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index d3655dfb5..7f356f51c 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -9,6 +9,8 @@ #include +#include "mwshadowtechnique.hpp" + namespace SceneUtil { using namespace osgShadow; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 26e119d88..acccd2203 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -7,10 +7,10 @@ #include #include -#include "mwshadowtechnique.hpp" - namespace SceneUtil { + class MWShadowTechnique; + class ShadowManager { public: From 199e6ed82ddc660adb47507bebd30af2406ada78 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 19 Dec 2018 23:53:14 +0000 Subject: [PATCH 155/168] Revert "Use forward declaration to reduce build times." This reverts commit 305b9826df7bc72211066b2eb9375df090ad501c. --- components/sceneutil/shadow.cpp | 2 -- components/sceneutil/shadow.hpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 7f356f51c..d3655dfb5 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -9,8 +9,6 @@ #include -#include "mwshadowtechnique.hpp" - namespace SceneUtil { using namespace osgShadow; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index acccd2203..26e119d88 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -7,10 +7,10 @@ #include #include +#include "mwshadowtechnique.hpp" + namespace SceneUtil { - class MWShadowTechnique; - class ShadowManager { public: From 9d84853903da4739f78052947c243f6cc5207254 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 24 Jan 2019 18:56:10 +0000 Subject: [PATCH 156/168] Fix nodemask snafu --- apps/openmw/mwrender/characterpreview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 18bbcee0a..a3679e844 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -137,6 +137,7 @@ namespace MWRender mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); mCamera->setName("CharacterPreview"); mCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + mCamera->setCullMask(~(Mask_UpdateVisitor)); mCamera->setNodeMask(Mask_RenderToTexture); From 4438ab44934f84f04c68a37a6305320677a84444 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 24 Jan 2019 22:42:23 +0000 Subject: [PATCH 157/168] Use CullVisitor traversal mask for light manager. --- components/sceneutil/lightmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index e102653b9..cb6a12c87 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -399,7 +399,7 @@ namespace SceneUtil return false; } - if (!(cv->getCurrentCamera()->getCullMask() & mLightManager->getLightingMask())) + if (!(cv->getTraversalMask() & mLightManager->getLightingMask())) return false; // Possible optimizations: From d82c85913a402d402367b616b941084c17b380f5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 24 Jan 2019 23:07:38 +0000 Subject: [PATCH 158/168] Don't bother multiplying a matrix by its inverse and applying that to the light direction. Hopefully this will improve numerical stability and reduce shadow flicker a little. --- components/sceneutil/mwshadowtechnique.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 6f3d34cb1..08117b4f9 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -474,7 +474,7 @@ void MWShadowTechnique::LightData::setLightData(osg::RefMatrix* lm, const osg::L lightDir.set(-lightPos.x(), -lightPos.y(), -lightPos.z()); lightDir.normalize(); OSG_INFO<<" Directional light, lightPos="< Date: Wed, 30 Jan 2019 22:28:00 +0000 Subject: [PATCH 159/168] Add normal-offset shadow mapping to remove shadow acne (flicker) --- components/sceneutil/shadow.cpp | 8 ++++++++ files/settings-default.cfg | 2 ++ files/shaders/objects_vertex.glsl | 2 +- files/shaders/shadows_vertex.glsl | 28 ++++++++++++++++++++++++++-- files/shaders/terrain_vertex.glsl | 5 +++-- files/shaders/water_vertex.glsl | 2 +- 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index d3655dfb5..5220723fb 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -125,6 +125,10 @@ namespace SceneUtil else definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithShadows["disableNormalOffsetShadows"] = Settings::Manager::getFloat("normal offset distance", "Shadows") == 0.0 ? "1" : "0"; + + definesWithShadows["shadowNormalOffset"] = std::to_string(Settings::Manager::getFloat("normal offset distance", "Shadows")); + return definesWithShadows; } @@ -140,6 +144,10 @@ namespace SceneUtil definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithShadows["enableNormalOffsetShadows"] = "0"; + + definesWithShadows["shadowNormalOffset"] = "0.0"; + return definesWithShadows; } void ShadowManager::enableIndoorMode() diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 240530be0..345a3ee0d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -669,6 +669,8 @@ minimum lispsm near far ratio = 0.25 polygon offset factor = 1.1 # Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset units = 4.0 +# How far along the surface normal to project shadow coordinates. Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. This value is in in-game units, so 1.0 is roughly 1.4 cm. +normal offset distance = 1.0 # Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. use front face culling = true # Allow actors to cast shadows. Potentially decreases performance. diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 3d7f49eee..dcb241274 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -103,5 +103,5 @@ void main(void) passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; - setupShadowCoords(viewPos); + setupShadowCoords(viewPos, viewNormal); } diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl index 4baa249c1..f96e1a673 100644 --- a/files/shaders/shadows_vertex.glsl +++ b/files/shaders/shadows_vertex.glsl @@ -10,20 +10,44 @@ varying vec4 shadowRegionCoords@shadow_texture_unit_index; #endif @endforeach + + // Enabling this may reduce peter panning. Probably unnecessary. + const bool onlyNormalOffsetUV = false; #endif // SHADOWS -void setupShadowCoords(vec4 viewPos) +void setupShadowCoords(vec4 viewPos, vec3 viewNormal) { #if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; + vec4 shadowOffset; @foreach shadow_texture_unit_index @shadow_texture_unit_list eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; #if @perspectiveShadowMaps shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; #endif + +#if @disableNormalOffsetShadows + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; +#else + shadowOffset = vec4(viewNormal * @shadowNormalOffset, 0.0); + + if (onlyNormalOffsetUV) + { + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + + vec4 lightSpaceXY = viewPos + shadowOffset; + lightSpaceXY = lightSpaceXY * eyePlaneMat; + + shadowSpaceCoords@shadow_texture_unit_index.xy = lightSpaceXY.xy; + } + else + { + vec4 offsetViewPosition = viewPos + shadowOffset; + shadowSpaceCoords@shadow_texture_unit_index = offsetViewPosition * eyePlaneMat; + } +#endif @endforeach #endif // SHADOWS } \ No newline at end of file diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 669eac012..8a9cf82cc 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -25,9 +25,10 @@ void main(void) vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); gl_ClipVertex = viewPos; + + vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); #if !PER_PIXEL_LIGHTING - vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); lighting = doLighting(viewPos.xyz, viewNormal, gl_Color, shadowDiffuseLighting); #else passColor = gl_Color; @@ -37,5 +38,5 @@ void main(void) uv = gl_MultiTexCoord0.xy; - setupShadowCoords(viewPos); + setupShadowCoords(viewPos, viewNormal); } diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index b028d90d2..575f8f3c2 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -22,5 +22,5 @@ void main(void) depthPassthrough = gl_Position.z; - setupShadowCoords(gl_ModelViewMatrix * gl_Vertex); + setupShadowCoords(gl_ModelViewMatrix * gl_Vertex, normalize((gl_NormalMatrix * gl_Normal).xyz)); } From a24b8ec3d2bd5a2251d5e4b709dbb19ed92a6e23 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 14:57:56 +0000 Subject: [PATCH 160/168] Fix enable/disable mixup. --- components/sceneutil/shadow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 5220723fb..ebb4868ad 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -144,7 +144,7 @@ namespace SceneUtil definesWithShadows["perspectiveShadowMaps"] = "0"; - definesWithShadows["enableNormalOffsetShadows"] = "0"; + definesWithShadows["disableNormalOffsetShadows"] = "0"; definesWithShadows["shadowNormalOffset"] = "0.0"; From 57e10e26b2276898f0829060018cc4300ced2356 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 14:58:57 +0000 Subject: [PATCH 161/168] Make variable name less confusing --- components/sceneutil/shadow.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index ebb4868ad..97d96f3f4 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -134,21 +134,21 @@ namespace SceneUtil Shader::ShaderManager::DefineMap ShadowManager::getShadowsDisabledDefines() { - Shader::ShaderManager::DefineMap definesWithShadows; - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); - definesWithShadows["shadow_texture_unit_list"] = ""; + Shader::ShaderManager::DefineMap definesWithoutShadows; + definesWithoutShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); + definesWithoutShadows["shadow_texture_unit_list"] = ""; - definesWithShadows["shadowMapsOverlap"] = "0"; + definesWithoutShadows["shadowMapsOverlap"] = "0"; - definesWithShadows["useShadowDebugOverlay"] = "0"; + definesWithoutShadows["useShadowDebugOverlay"] = "0"; - definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithoutShadows["perspectiveShadowMaps"] = "0"; - definesWithShadows["disableNormalOffsetShadows"] = "0"; + definesWithoutShadows["disableNormalOffsetShadows"] = "0"; - definesWithShadows["shadowNormalOffset"] = "0.0"; + definesWithoutShadows["shadowNormalOffset"] = "0.0"; - return definesWithShadows; + return definesWithoutShadows; } void ShadowManager::enableIndoorMode() { From abe9ba736e02df60169e2c3b1569d53da1b73c6a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 15:00:04 +0000 Subject: [PATCH 162/168] Add line breaks to make settings more readable. --- files/settings-default.cfg | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 345a3ee0d..1cd52a280 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -645,41 +645,60 @@ enable nav mesh render = false enable agents paths render = false [Shadows] + # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. enable shadows = false + # How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance. number of shadow maps = 3 + # If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps. allow shadow map overlap = true + # Indirectly controls where to split the shadow map(s). Values closer to 1.0 bring more detail closer to the camera (potentially excessively so), and values closer to 0.0 spread it more evenly across the whole viewing distance. 0.5 is recommended for most viewing distances by the original Parallel Split Shadow Maps paper, but this does not take into account use of a Light Space Perspective transformation, so other values may be preferable. If some of the terms used here go over your head, you might not want to change this, especially not without reading the associated papers first. When "allow shadow map overlap" is combined with a higher-than-default viewing distance, values closer to 1.0 will prevent nearby shadows losing a lot of quality. split point uniform logarithmic ratio = 0.5 + # Indirectly controls where to split the shadow map(s). Positive values move split points away from the camera and negative values move them towards the camera. Intended to be used in conjunction with changes to 'split point uniform logarithmic ratio' to counteract side effects, but may cause additional, more serious side effects. Read the Parallel Split Shadow Maps paper by F Zhang et al before changing. split point bias = 0.0 + # Enable the debug hud to see what the shadow map(s) contain. enable debug hud = false + # Enable the debug overlay to see where each shadow map affects. enable debug overlay = false + # Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. compute tight scene bounds = false + # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. shadow map resolution = 1024 + # Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation. Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera. Increasing this pushes detail further away. minimum lispsm near far ratio = 0.25 + # Used as the factor parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset factor = 1.1 + # Used as the units parameter for the polygon offset used for shadow map rendering. Higher values reduce shadow flicker, but risk increasing Peter Panning. See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml for details. polygon offset units = 4.0 + # How far along the surface normal to project shadow coordinates. Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. This value is in in-game units, so 1.0 is roughly 1.4 cm. normal offset distance = 1.0 + # Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. use front face culling = true + # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false + # Allow the player to cast shadows. Potentially decreases performance. player shadows = false + # Allow terrain to cast shadows. Potentially decreases performance. terrain shadows = false + # Allow world objects to cast shadows. Potentially decreases performance. object shadows = false + # Allow shadows indoors. Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting. enable indoor shadows = true From 2761a3856254eb808702b26f4562f335ce651255 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 20:12:17 +0000 Subject: [PATCH 163/168] Prettify shadow define map setup. --- components/sceneutil/shadow.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 97d96f3f4..9f854cc84 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -103,27 +103,20 @@ namespace SceneUtil return getShadowsDisabledDefines(); Shader::ShaderManager::DefineMap definesWithShadows; - definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); + + definesWithShadows["shadows_enabled"] = "1"; + for (unsigned int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i) definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; // remove extra comma definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); - if (Settings::Manager::getBool("allow shadow map overlap", "Shadows")) - definesWithShadows["shadowMapsOverlap"] = "1"; - else - definesWithShadows["shadowMapsOverlap"] = "0"; + definesWithShadows["shadowMapsOverlap"] = Settings::Manager::getBool("allow shadow map overlap", "Shadows") ? "1" : "0"; - if (Settings::Manager::getBool("enable debug overlay", "Shadows")) - definesWithShadows["useShadowDebugOverlay"] = "1"; - else - definesWithShadows["useShadowDebugOverlay"] = "0"; + definesWithShadows["useShadowDebugOverlay"] = Settings::Manager::getBool("enable debug overlay", "Shadows") ? "1" : "0"; // switch this to reading settings if it's ever exposed to the user - if (mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP) - definesWithShadows["perspectiveShadowMaps"] = "1"; - else - definesWithShadows["perspectiveShadowMaps"] = "0"; + definesWithShadows["perspectiveShadowMaps"] = mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP ? "1" : "0"; definesWithShadows["disableNormalOffsetShadows"] = Settings::Manager::getFloat("normal offset distance", "Shadows") == 0.0 ? "1" : "0"; @@ -135,7 +128,9 @@ namespace SceneUtil Shader::ShaderManager::DefineMap ShadowManager::getShadowsDisabledDefines() { Shader::ShaderManager::DefineMap definesWithoutShadows; - definesWithoutShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("0"))); + + definesWithoutShadows["shadows_enabled"] = "0"; + definesWithoutShadows["shadow_texture_unit_list"] = ""; definesWithoutShadows["shadowMapsOverlap"] = "0"; @@ -150,6 +145,7 @@ namespace SceneUtil return definesWithoutShadows; } + void ShadowManager::enableIndoorMode() { if (Settings::Manager::getBool("enable indoor shadows", "Shadows")) @@ -157,6 +153,7 @@ namespace SceneUtil else mShadowTechnique->disableShadows(); } + void ShadowManager::enableOutdoorMode() { if (mEnableShadows) From cfe921fb824288f794efd7e62be5f97b21a52fd4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 31 Jan 2019 20:12:42 +0000 Subject: [PATCH 164/168] Remove uneeded includes. --- components/sceneutil/shadow.cpp | 5 ----- components/sceneutil/shadow.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 9f854cc84..a69fd8090 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -1,11 +1,6 @@ #include "shadow.hpp" #include -#include -#include -#include -#include -#include #include diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 26e119d88..24deff253 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "mwshadowtechnique.hpp" From 15547750ba97cb2471cbf7f427e188a32c1e40d4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 1 Feb 2019 00:29:13 +0000 Subject: [PATCH 165/168] Correct behaviour of use front face culling setting to not use back face culling either when disabled. --- components/sceneutil/mwshadowtechnique.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 08117b4f9..0addb6f4b 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -849,7 +849,7 @@ void SceneUtil::MWShadowTechnique::disableFrontFaceCulling() _useFrontFaceCulling = false; if (_shadowCastingStateSet) - _shadowCastingStateSet->removeAttribute(osg::StateAttribute::CULLFACE); + _shadowCastingStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) @@ -1462,12 +1462,16 @@ void MWShadowTechnique::createShaders() // In this case we will draw them in their entirety. if (_useFrontFaceCulling) + { _shadowCastingStateSet->setAttribute(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - // make sure GL_CULL_FACE is off by default - // we assume that if object has cull face attribute set to back - // it will also set cull face mode ON so no need for override - _shadowCastingStateSet->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); + // make sure GL_CULL_FACE is off by default + // we assume that if object has cull face attribute set to back + // it will also set cull face mode ON so no need for override + _shadowCastingStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + } + else + _shadowCastingStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } _polygonOffset = new osg::PolygonOffset(_polygonOffsetFactor, _polygonOffsetUnits); From 9b92943d1a649e2c1076a758742adfa3ad645984 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 5 Feb 2019 20:51:56 +0000 Subject: [PATCH 166/168] Don't rely exclusively on a shadow map when out of its depth range --- files/shaders/shadows_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/shadows_fragment.glsl b/files/shaders/shadows_fragment.glsl index 713473458..a925b2f07 100644 --- a/files/shaders/shadows_fragment.glsl +++ b/files/shaders/shadows_fragment.glsl @@ -29,7 +29,7 @@ float unshadowedLightRatio() shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing); - doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); + doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); #if @perspectiveShadowMaps doneShadows = doneShadows && all(lessThan(shadowRegionXYZ, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); #endif @@ -67,7 +67,7 @@ void applyShadowDebugOverlay() else gl_FragData[0].z += 0.1; - doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.05, 0.05))); + doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); #if @perspectiveShadowMaps doneOverlay = doneOverlay && all(lessThan(shadowRegionXYZ.xyz, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); #endif From b1a5a72665aa7151d290dbf675a10928ee91dfea Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 7 Feb 2019 00:27:26 +0000 Subject: [PATCH 167/168] Restore previous night time directional light path --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7d3f41894..dcd1eac8b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -739,7 +739,7 @@ void WeatherManager::update(float duration, bool paused, const TimeStamp& time, } else { - theta = static_cast(osg::PI) + static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; + theta = static_cast(osg::PI) - static_cast(osg::PI) * (adjustedHour - adjustedNightStart) / nightDuration; } osg::Vec3f final( From 0c8ad0a3bbd50a6c2a7539317de04c76455d600b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 19 Feb 2019 18:13:03 +0000 Subject: [PATCH 168/168] Double buffer debug HUD frustum geometries to prevent race conditions. --- components/sceneutil/mwshadowtechnique.cpp | 49 ++++++++++++++++------ components/sceneutil/mwshadowtechnique.hpp | 4 +- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 0addb6f4b..64c2e6e55 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -978,7 +978,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) osg::ref_ptr vertexArray = new osg::Vec3Array(); for (osg::Vec3d &vertex : frustum.corners) vertexArray->push_back((osg::Vec3)vertex); - _debugHud->setFrustumVertices(vertexArray); + _debugHud->setFrustumVertices(vertexArray, cv.getTraversalNumber()); } double reducedNear, reducedFar; @@ -3042,6 +3042,25 @@ void MWShadowTechnique::releaseGLObjects(osg::State* state) const _debugHud->releaseGLObjects(state); } +class DoubleBufferCallback : public osg::Callback +{ +public: + DoubleBufferCallback(osg::NodeList &children) : mChildren(children) {} + + virtual bool run(osg::Object* node, osg::Object* visitor) override + { + // We can't use a static cast as NodeVisitor virtually inherits from Object + osg::ref_ptr nodeVisitor = visitor->asNodeVisitor(); + unsigned int traversalNumber = nodeVisitor->getTraversalNumber(); + mChildren[traversalNumber % 2]->accept(*nodeVisitor); + + return true; + } + +protected: + osg::NodeList mChildren; +}; + SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) : mDebugProgram(new osg::Program) { osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, debugVertexShaderSource); @@ -3049,20 +3068,23 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFragmentShaderSource); mDebugProgram->addShader(fragmentShader); - mFrustumGeometry = new osg::Geometry(); - mFrustumGeometry->setCullingActive(false); - osg::ref_ptr frustumProgram = new osg::Program; vertexShader = new osg::Shader(osg::Shader::VERTEX, debugFrustumVertexShaderSource); frustumProgram->addShader(vertexShader); fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, debugFrustumFragmentShaderSource); frustumProgram->addShader(fragmentShader); - mFrustumGeometry->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); - //mFrustumGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + for (int i = 0; i < 2; ++i) + { + mFrustumGeometries.emplace_back(new osg::Geometry()); + mFrustumGeometries[i]->setCullingActive(false); + + mFrustumGeometries[i]->getOrCreateStateSet()->setAttributeAndModes(frustumProgram, osg::StateAttribute::ON); + } osg::ref_ptr frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP); - mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + for (auto & geom : mFrustumGeometries) + geom->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(0); frustumDrawElements->push_back(1); frustumDrawElements->push_back(2); @@ -3075,7 +3097,8 @@ SceneUtil::MWShadowTechnique::DebugHUD::DebugHUD(int numberOfShadowMapsPerLight) frustumDrawElements->push_back(4); frustumDrawElements = new osg::DrawElementsUShort(osg::PrimitiveSet::LINES); - mFrustumGeometry->addPrimitiveSet(frustumDrawElements); + for (auto & geom : mFrustumGeometries) + geom->addPrimitiveSet(frustumDrawElements); frustumDrawElements->push_back(1); frustumDrawElements->push_back(5); frustumDrawElements->push_back(2); @@ -3118,12 +3141,13 @@ void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) node->releaseGLObjects(state); for (auto const& node : mFrustumTransforms) node->releaseGLObjects(state); - mFrustumGeometry->releaseGLObjects(state); + for (auto const& node : mFrustumGeometries) + node->releaseGLObjects(state); } -void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices) +void SceneUtil::MWShadowTechnique::DebugHUD::setFrustumVertices(osg::ref_ptr vertices, unsigned int traversalNumber) { - mFrustumGeometry->setVertexArray(vertices); + mFrustumGeometries[traversalNumber % 2]->setVertexArray(vertices); } void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() @@ -3146,7 +3170,8 @@ void SceneUtil::MWShadowTechnique::DebugHUD::addAnotherShadowMap() stateSet->addUniform(textureUniform.get()); mFrustumTransforms.push_back(new osg::Group); - mFrustumTransforms[shadowMapNumber]->addChild(mFrustumGeometry); + osg::NodeList frustumGeometryNodeList(mFrustumGeometries.cbegin(), mFrustumGeometries.cend()); + mFrustumTransforms[shadowMapNumber]->setCullCallback(new DoubleBufferCallback(frustumGeometryNodeList)); mFrustumTransforms[shadowMapNumber]->setCullingActive(false); mDebugCameras[shadowMapNumber]->addChild(mFrustumTransforms[shadowMapNumber]); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 16d44c5e2..621066799 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -264,7 +264,7 @@ namespace SceneUtil { virtual void releaseGLObjects(osg::State* state = 0) const; - virtual void setFrustumVertices(osg::ref_ptr vertices); + virtual void setFrustumVertices(osg::ref_ptr vertices, unsigned int traversalNumber); protected: virtual void addAnotherShadowMap(); @@ -275,7 +275,7 @@ namespace SceneUtil { std::vector> mDebugGeometry; std::vector> mFrustumTransforms; std::vector> mFrustumUniforms; - osg::ref_ptr mFrustumGeometry; + std::vector> mFrustumGeometries; }; osg::ref_ptr _debugHud;