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 8b4e9ad4b4..7c8e8cd16e 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 a066784888..6e4a7baab6 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 6ee9b8ae87..87c13f9814 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 d52c7c232e..1f620b7f71 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 0050104cf3..5f0c539a58 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 820fdab49b..1b78bef807 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 14998a3c61..11317a33fe 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 7b8486fbec..892ae485ac 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 892ae485ac..e50e2f9c23 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 e50e2f9c23..fe298e1600 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 fe298e1600..afa636e3c3 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 afa636e3c3..8678d18dd9 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 f90e5f8bab..b3bfa600b5 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 2e61caeb0f..9da9dfad5d 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 47a30f9a01..97744d4dd0 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 04c3355cab..e670eaebc0 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 0000000000..17cc5156bb --- /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 0000000000..51338c5bf8 --- /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 8678d18dd9..5d59754ec6 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 5d59754ec6..09b78b5962 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 11317a33fe..8c73bf78d8 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 8c73bf78d8..3895a0a96d 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 | 28 +- files/shaders/objects_fragment.glsl | 4 +- files/shaders/terrain_fragment.glsl | 4 +- 5 files changed, 714 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e670eaebc0..172ff34a85 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 17cc5156bb..c58334a51a 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) { - LightSpacePerspectiveShadowMapDB::ViewData::init(st, cv); - osg::StateSet * stateset = _camera->getOrCreateStateSet(); - stateset->removeAttribute(osg::StateAttribute::CULLFACE); + 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 + { + 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 { - protected: - struct ViewData : public LightSpacePerspectiveShadowMapDB::ViewData - { - virtual void init(MWShadow * st, osgUtil::CullVisitor * cv); - }; + public: + MWShadow(); - 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; - } + virtual void cull(osgUtil::CullVisitor& cv); + protected: + osg::ref_ptr debugCamera; + + osg::ref_ptr debugProgram; + + osg::ref_ptr debugGeometry; + + osg::ref_ptr testTex; }; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index b3bfa600b5..4dd282dc43 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 9da9dfad5d..e27dd384ea 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 c58334a51a..65ce8d5bde 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 65ce8d5bde..2f57f6e066 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 2f57f6e066..b8600e2116 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 b8600e2116..089a4da3d3 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 931422d5e6..f04a9d8a87 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 7d7b7b18aa..513edc730c 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 e871e1cfcf..3c4c1101ff 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 089a4da3d3..915979bac3 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 3c4c1101ff..cdf4ed16a4 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 f3080e31cd..60d5917070 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 6c599fc3fa..4256f6987b 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 915979bac3..347952b4cb 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 4a4e8b8a5b..a941f9c2e6 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 cdf4ed16a4..aa5240618a 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 42949dccbb..4046386dd6 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 89a2307a1e..17a9c436ea 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 513edc730c..6aaa0537c9 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 aa5240618a..bdabdaeabb 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 a941f9c2e6..4e1725c7fe 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 4256f6987b..9f4542ae9c 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 aa5240618a..645c106679 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 347952b4cb..40b2ff311b 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 a941f9c2e6..e7663c55ac 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 4dd282dc43..f6355aaa69 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 4046386dd6..b90a8722b8 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 e27dd384ea..e79adaafba 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 17a9c436ea..015039252e 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 f04a9d8a87..3529b7347f 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 6aaa0537c9..0c280fb7e0 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 9f4542ae9c..8eec3f30b2 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 7cb49c6cb5..02488dd42b 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 bd820a725c..17c46f58c0 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 f6355aaa69..7d9372c718 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 b90a8722b8..fb612afc82 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 e79adaafba..e512d74756 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 015039252e..692e76cce7 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 3529b7347f..586a247a4b 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 0c280fb7e0..6381155d0b 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 40b2ff311b..9a4e2688af 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 e7663c55ac..e8d5b1b51d 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 b78c4dcd2c..4b60a7cf22 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 02488dd42b..93b0168ae7 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 1f620b7f71..d52c7c232e 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 97744d4dd0..47a30f9a01 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 4b60a7cf22..c7f90bc5f3 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 176d179f47..1b34e433dd 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 8eec3f30b2..331782c7bd 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 a0b426a163..f6af33b25f 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 9a4e2688af..e8b267dadb 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 445a7b0f55..8d8278deb2 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 3b4373387c..a0b1aca83c 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 f6af33b25f..1e3a68ac89 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 c7f90bc5f3..7f3132a9e9 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 f7219959af..15cc638936 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 a0b1aca83c..ea971586ab 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 7d9372c718..9196c14902 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 fb612afc82..f84971c972 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 e512d74756..1b985e14b4 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 692e76cce7..7cb959d3ef 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 586a247a4b..ca09aa94be 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 6381155d0b..1a14bcaa66 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 ea971586ab..59c81f40a6 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 ca09aa94be..fddd81eff2 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 59c81f40a6..b5c292ad77 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 b5c292ad77..a7a5e99a07 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 1b34e433dd..c2ade69d9f 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 e8b267dadb..87aeb051e6 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 a7a5e99a07..b8beffa2e1 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 17c46f58c0..baaa738659 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 c2ade69d9f..52bc8de3c3 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 b8beffa2e1..3b18d0b756 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 52bc8de3c3..9258b754f7 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 87aeb051e6..dfcd5c1e80 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 dfcd5c1e80..a4079d1a00 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 9258b754f7..5449fd4608 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 3b18d0b756..533b3ae561 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 baaa738659..16b4d639bb 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 5449fd4608..41d9969d41 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 533b3ae561..eb3a88eb45 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 16b4d639bb..02f35975d5 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 41d9969d41..caa8089097 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 a4079d1a00..21a0de89a3 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 aa8085f0df..3c665bac79 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 | 89 +++++++++++++++++------ components/sceneutil/shadow.hpp | 15 ++-- files/settings-default.cfg | 19 +++++ 7 files changed, 107 insertions(+), 66 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 15cc638936..e329d9ebc7 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 7f3132a9e9..d4f55f18b0 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 caa8089097..e72149b76b 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 331782c7bd..79f5f00bb7 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 21a0de89a3..0d654a817a 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"; - - MWShadow::MWShadow() : debugProgram(new osg::Program), debugTextureUnit(0) + void MWShadow::setupShadowSettings(osg::ref_ptr settings, int castsShadowMask) { - 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); + if (!Settings::Manager::getBool("enable shadows", "Shadows")) + return; - for (int i = 0; i < numberOfShadowMapsPerLight; ++i) + 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)); + } + + void MWShadow::disableShadowsForStateSet(osg::ref_ptr stateset) + { + 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); + } + + 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 3c665bac79..ec7bbb8d27 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,14 +11,12 @@ 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); + + static void disableShadowsForStateSet(osg::ref_ptr stateSet); MWShadow(); - const static int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; - virtual void cull(osgUtil::CullVisitor& cv); virtual Shader::ShaderManager::DefineMap getShadowDefines(); @@ -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 2538834024..bd63f2bc66 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 e72149b76b..c8b3812b1a 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 56d76a8d10..a11df35a3d 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 0000000000..d8e8624795 --- /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 ec7bbb8d27..e5c3db327c 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 60d5917070..f216bb33bb 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 08e376f083..eca9bb3e65 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 0d654a817a..f1943f08d5 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 d8e8624795..334663fe8f 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 bc18302424..49615dc68e 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 334663fe8f..a0e902d7b2 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 f1943f08d5..e8c7e19472 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 | 234 ++++++++++++++++---------------- components/sceneutil/shadow.hpp | 26 ++++ 2 files changed, 140 insertions(+), 120 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index e8c7e19472..1e4112971f 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); + + pushViewport(viewport); + pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); + pushModelViewMatrix(new osg::RefMatrix(viewMatrix), osg::Transform::ABSOLUTE_RF); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Node& node) + { + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Geode& node) + { + if (isCulled(node)) return; + + // 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) + // pop the culling mode. + popCurrentMask(); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) + { + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); + } + + void MWShadow::ComputeLightSpaceBounds::apply(osg::Billboard&) + { + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; + } + + void MWShadow::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) + { + 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) { - if (isCulled(drawable)) return; + osg::ref_ptr matrix = new osg::RefMatrix(*getModelViewMatrix()); + transform.computeLocalToWorldMatrix(*matrix, this); + pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); - // push the culling mode. - pushCurrentMask(); + traverse(transform); - updateBound(drawable.getBoundingBox()); - - // pop the culling mode. - popCurrentMask(); + popModelViewMatrix(); } - void apply(osg::Billboard&) + // pop the culling mode. + popCurrentMask(); + + } + + 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) { - OSG_INFO << "Warning Billboards not yet supported" << std::endl; + //OSG_NOTICE<<"discarding("< 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; - }; + float x = v.x(); + if (x<-1.0f) x = -1.0f; + if (x>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 e5c3db327c..b92e8658b2 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 1e4112971f..cc3eb0be6c 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 b92e8658b2..897b8759da 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 f310648050..76baa2f45b 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 1e3a68ac89..e68e7ed077 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 0000000000..63b80fed18 --- /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 0000000000..f72f2ce159 --- /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 f72f2ce159..876943c884 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 876943c884..e68e234840 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 0000000000..4352d811a7 --- /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 e68e234840..a7ec6a2d75 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 4352d811a7..d9df993719 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 d9df993719..1d213bc0f8 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 a7ec6a2d75..71cfef2556 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 1d213bc0f8..efbf2ed5cd 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 71cfef2556..5217b48327 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 e329d9ebc7..63fe32dfec 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 d4f55f18b0..97e9c817a9 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 c8b3812b1a..a59ba8c1aa 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 79f5f00bb7..3e81a7610f 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 cc3eb0be6c..8c729e3cc1 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 76baa2f45b..85c43ce1d0 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 5217b48327..e8543c8b4a 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 efbf2ed5cd..e7465ff39f 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 | 219 +++++++++++---------- components/sceneutil/mwshadowtechnique.hpp | 27 +++ 2 files changed, 137 insertions(+), 109 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index e8543c8b4a..522172f42c 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 MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Node& node) +{ + if (isCulled(node)) return; + + // push the culling mode. + pushCurrentMask(); + + traverse(node); + + // pop the culling mode. + popCurrentMask(); +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Drawable& drawable) +{ + if (isCulled(drawable)) return; + + // push the culling mode. + pushCurrentMask(); + + updateBound(drawable.getBoundingBox()); + + // pop the culling mode. + popCurrentMask(); +} + +void MWShadowTechnique::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 MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Billboard&) +{ + OSG_INFO << "Warning Billboards not yet supported" << std::endl; + return; +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Projection&) +{ + // projection nodes won't affect a shadow map so their subgraphs should be ignored + return; +} + +void MWShadowTechnique::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(); } - void apply(osg::Node& node) + // pop the culling mode. + popCurrentMask(); + +} + +void MWShadowTechnique::ComputeLightSpaceBounds::apply(osg::Camera&) +{ + // camera nodes won't affect a shadow map so their subgraphs should be ignored + return; +} + +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 MWShadowTechnique::ComputeLightSpaceBounds::update(const osg::Vec3& v) +{ + if (v.z()<-1.0f) { - 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; -}; + float x = v.x(); + if (x<-1.0f) x = -1.0f; + if (x>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 e7465ff39f..7cf7db1551 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 522172f42c..1b390e33b3 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 1b390e33b3..23ff2e7a98 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 23ff2e7a98..e99d9d6927 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 4b83e6bb71..7494b02bef 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 e99d9d6927..dc64204a30 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 7494b02bef..cd5a71f922 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 dc64204a30..01e65bc36d 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 cd5a71f922..199babf6f6 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 199babf6f6..b1dcbfd311 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 63b80fed18..0000000000 --- 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 b1dcbfd311..797266287b 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 a59ba8c1aa..920c7278ce 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); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode)); + mShadowManager->setupShadowSettings(shadowCastingTraversalMask); - shadowedScene->addChild(sceneRoot); - mRootNode->addChild(shadowedScene); - - 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 f0087e43d2..d322bfaf4f 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 01e65bc36d..123030b258 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 797266287b..41f1d7c32d 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 8c729e3cc1..8c58cb6033 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) + mShadowedScene(new osgShadow::ShadowedScene), + mShadowTechnique(new MWShadowTechnique) { - 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) - { - 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 cfe1a4f3f4..5ac2711852 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 85c43ce1d0..651b2cd24d 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 123030b258..fbf0fc9d24 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 41f1d7c32d..1fad0eee52 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 8c58cb6033..99cb71beb1 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 99cb71beb1..9d25b57646 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(); + + mShadowTechnique->enableShadows(); - osg::ref_ptr settings = mShadowedScene->getShadowSettings(); - - 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 5ac2711852..2936941ff3 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 920c7278ce..5971de9662 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 9d25b57646..00e6b93a99 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 2936941ff3..61a564a2a8 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 00e6b93a99..9b20544790 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 61a564a2a8..6a3fccea64 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 5aa9da425e..773363051b 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 4513d6996a..c2d4304e45 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 6a3fccea64..9444591c96 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 fbf0fc9d24..80e2c1d387 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 651b2cd24d..e1beaee026 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 f0a3d2e381..28b7732c36 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 773363051b..aabfa91a7b 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 d52c7c232e..53026150b5 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 53026150b5..1d94b4bf9d 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 17d0929174..dbce11464c 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 a0e902d7b2..fe471df1e4 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 e2632f9e59..ae3d6eefcd 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 fe471df1e4..8e3b79c003 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 aabfa91a7b..680f4ebd02 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 9444591c96..6829046506 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 80e2c1d387..11089a49c2 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 97e9c817a9..70d7a1dbe6 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 680f4ebd02..33ce9346bf 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 ae3d6eefcd..ee102af520 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 33ce9346bf..bc414401f0 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 8e3b79c003..4dac6a88b1 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 ee102af520..c0283b3785 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 904c51669d..b84e797c1b 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 1fad0eee52..7f5aeb85d4 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 b84e797c1b..db0788318a 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 7f5aeb85d4..eb5b650a00 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 db0788318a..d2c4c3a8f4 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 3cc2b138ee..1ffc745e83 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 | 28 +++++++++++++++++----------- files/shaders/terrain_fragment.glsl | 28 +++++++++++++++++----------- files/shaders/water_fragment.glsl | 28 +++++++++++++++++----------- 4 files changed, 58 insertions(+), 33 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 363e0ac3fd..374faee8ce 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 7ba3d1de0d..5eb98899ad 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; + 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; + 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 68ab1bbdd0..ae9f5a7bab 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; + 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; + 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 e953b2611e..7aa7ca0b0d 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; + 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; + 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 2cf10f4d78..7630675927 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 7630675927..70352541fd 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 f11aec0bbe..ce5c0b6742 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 1ffc745e83..5c404a78f2 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 4dac6a88b1..f9ebd1f63e 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 5c404a78f2..c8d68c14c9 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 6e1fef716f..0b4a8e062a 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 70352541fd..378881d8dc 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 378881d8dc..0bb8a26c98 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 0bb8a26c98..56be0b8a01 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 | 48 +++++++++++------------ files/shaders/objects_vertex.glsl | 20 +++++----- files/shaders/terrain_fragment.glsl | 48 +++++++++++------------ files/shaders/terrain_vertex.glsl | 20 +++++----- files/shaders/water_fragment.glsl | 60 ++++++++++++++--------------- files/shaders/water_vertex.glsl | 32 +++++++-------- 7 files changed, 117 insertions(+), 117 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index e67ed295a3..d234aaaad0 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 e78909abee..c2628eb7fb 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 d38460caa9..f51baf9327 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 7baca78ef1..41763f3e1d 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 4075416347..fffb9c83b3 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 02960e5b43..3d7f49eeeb 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 0000000000..cc1b38b59e --- /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 0000000000..bbc1a40368 --- /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 57403f1a43..219b92c990 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 57af0575cd..669eac0125 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 c2628eb7fb..a227e1e68b 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 f51baf9327..b028d90d22 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 374faee8ce..6e45bdd22f 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 f9ebd1f63e..271ecac20a 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 6cee10e055..277b5dd083 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 fffb9c83b3..64435f001a 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 cc1b38b59e..ce9e958d19 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 219b92c990..c946777bbd 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 a227e1e68b..0102a6eb95 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 56be0b8a01..31c10faff3 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 7f148cf5e3..fdb67d7dec 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 60b3edc9d8..0d8dcbddde 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 410157d800..1b17ce4ea2 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 271ecac20a..34d484925e 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 6e45bdd22f..6c71a9c0fd 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 34d484925e..b88df8942b 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 41063929e5..21af225667 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 d234aaaad0..c70d0a59ab 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 | 158 ++++++++++++--------- 1 file changed, 90 insertions(+), 68 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 963aa1c072..64cef25a63 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 (edge.first == vertex) + connectedVertices.push_back(edge.second); + else if (edge.second == vertex) + connectedVertices.push_back(edge.first); + } + connectedVertices.push_back(osg::Vec3d(vertex.x(), vertex.y(), lowestPoint)); + + Vertices unwantedEdgeEnds = findInternalEdges(vertex, connectedVertices); + for (auto edgeEnd : unwantedEdgeEnds) + { + for (auto itr = _edges.begin(); itr != _edges.end(); ++itr) { - if (edgeItr->first.z() >= edgeItr->second.z()) + if (*itr == Edge(vertex, edgeEnd)) { - // 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; - } + _edges.erase(itr); + break; + } + else if (*itr == Edge(edgeEnd, vertex)) + { + _edges.erase(itr); + break; } } } - 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) + // 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 64cef25a63..c3bf99c962 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 94b87504bb..2ede0abc2d 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 c3bf99c962..b90f67ff6f 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 cb0538d9d3..eab75acbb5 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 a0f051524b..83684b5c91 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 d234aaaad0..ff6ee94199 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 a186ed8e95..c3e68aa680 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 eb20b77021..f37f271edc 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 36f7dfbb7d..8c36c5e715 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 875edbc1c6..558ad49d95 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 6c71a9c0fd..65754629e5 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 6829046506..26e119d88b 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 4556c05a61..457da5c776 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 41763f3e1d..8012c2bc10 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 0000000000..6459467b11 --- /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 0000000000..d578e97b70 --- /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 6459467b11..00b8f9aa1a 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 457da5c776..fad43a3a10 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 eab75acbb5..8737baf599 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 8c36c5e715..8f42f8fcd7 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 ff6ee94199..5c21b7bee1 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 65754629e5..c2c728e12a 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 9ad7dc8dd9..376924d82d 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 00b8f9aa1a..336bfe4a48 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 ce9e958d19..220e00efaa 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 8f42f8fcd7..598a663d3e 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 598a663d3e..e26cfbe76f 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 e26cfbe76f..fa62ae1fae 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 558ad49d95..e1f2884958 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 fa62ae1fae..8f8b9aa961 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 8f8b9aa961..0161891d35 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 b88df8942b..8ab9c25390 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 5e866dbfb0..0ca5ad93d1 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 eb7df28d1c..5ed5e5a99a 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 ccfb6094ba..16d44c5e2f 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 e9091451dd..a6559e9b9e 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 8ab9c25390..c8d3250a0e 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 0ca5ad93d1..df9ea30083 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 fad43a3a10..3080e1318a 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 5ed5e5a99a..ea52ec24a8 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 a6559e9b9e..d3655dfb5c 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 220e00efaa..713473458b 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 bbc1a40368..4baa249c11 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 2222cbb844..4b4df43659 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 0d5b25697b..6ec89721ad 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 ea52ec24a8..6f3d34cb1a 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 d3655dfb5c..7f356f51c4 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 26e119d88b..acccd22037 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 7f356f51c4..d3655dfb5c 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 acccd22037..26e119d88b 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 18bbcee0a9..a3679e844c 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 e102653b90..cb6a12c879 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 6f3d34cb1a..08117b4f95 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 d3655dfb5c..5220723fb4 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 240530be04..345a3ee0d2 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 3d7f49eeeb..dcb2412745 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 4baa249c11..f96e1a6735 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 669eac0125..8a9cf82cc3 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 b028d90d22..575f8f3c2f 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 5220723fb4..ebb4868ad3 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 ebb4868ad3..97d96f3f4e 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 345a3ee0d2..1cd52a2802 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 97d96f3f4e..9f854cc845 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 9f854cc845..a69fd80909 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 26e119d88b..24deff2531 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 08117b4f95..0addb6f4bb 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 713473458b..a925b2f07e 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 7d3f41894d..dcd1eac8b0 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 0addb6f4bb..64c2e6e55f 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 16d44c5e2f..6210667990 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;