diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ca26697b76..8ecb69b9e7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -54,6 +54,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::OgrePlatform* platform = new sh::OgrePlatform("General", (resDir / "materials").string()); platform->setCacheFolder ("./"); mFactory = new sh::Factory(platform); + mFactory->setSharedParameter ("pssmSplitPoints", sh::makeProperty(new sh::Vector4(0,0,0,0))); + mFactory->setSharedParameter ("shadowFar_fadeStart", sh::makeProperty(new sh::Vector4(0,0,0,0))); //The fog type must be set before any terrain objects are created as if the //fog type is set to FOG_NONE then the initially created terrain won't have any fog diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 2e09f4c31f..b4982e22d7 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "renderconst.hpp" using namespace Ogre; @@ -84,6 +86,12 @@ void Shadows::recreate() mSceneMgr->setShadowTextureConfig(i, texsize/4, texsize/4, Ogre::PF_FLOAT32_R);*/ } + // Populate from split point 1, not 0, since split 0 isn't useful (usually 0) + const PSSMShadowCameraSetup::SplitPointList& splitPointList = getPSSMSetup()->getSplitPoints(); + sh::Vector4* splitPoints = new sh::Vector4(splitPointList[1], splitPointList[2], splitPointList[3], 1.0); + + sh::Factory::getInstance ().setSharedParameter ("pssmSplitPoints", sh::makeProperty(splitPoints)); + shadowCameraSetup = ShadowCameraSetupPtr(mPSSMSetup); } else @@ -96,6 +104,9 @@ void Shadows::recreate() } mSceneMgr->setShadowCameraSetup(shadowCameraSetup); + sh::Vector4* shadowFar_fadeStart = new sh::Vector4(mShadowFar, mFadeStart * mShadowFar, 0, 0); + sh::Factory::getInstance ().setSharedParameter ("shadowFar_fadeStart", sh::makeProperty(shadowFar_fadeStart)); + // Set visibility mask for the shadow render textures int visibilityMask = RV_Actors * Settings::Manager::getBool("actor shadows", "Shadows") + (RV_Statics + RV_StaticsSmall) * Settings::Manager::getBool("statics shadows", "Shadows") @@ -111,7 +122,7 @@ void Shadows::recreate() // -------------------------------------------------------------------------------------------------------------------- // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- // -------------------------------------------------------------------------------------------------------------------- -/* + OverlayManager& mgr = OverlayManager::getSingleton(); Overlay* overlay; @@ -157,7 +168,7 @@ void Shadows::recreate() overlay->add2D(debugPanel); overlay->show(); } -*/ + } PSSMShadowCameraSetup* Shadows::getPSSMSetup() diff --git a/extern/shiny b/extern/shiny index 3e7e02a846..b3cfd41dff 160000 --- a/extern/shiny +++ b/extern/shiny @@ -1 +1 @@ -Subproject commit 3e7e02a846ce6c3de7e2344a82d346293115eb7d +Subproject commit b3cfd41dff2758e268ce16f366b7e7857eee80ea diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 324fe1b2a3..76e64112b2 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -42,10 +42,30 @@ material openmw_objects_base ffp_vertex_colour_ambient $has_vertex_colour + texture_unit diffuseMap { direct_texture $diffuseMap create_in_ffp true } + + texture_unit shadowMap0 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap1 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap2 + { + content_type shadow + tex_address_mode clamp + filtering none + } } } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 8316993641..dd1b489d52 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -1,20 +1,28 @@ #include "core.h" +#include "shadows.h" + #define FOG @shPropertyBool(fog) #define MRT @shPropertyNotBool(is_transparent) && @shPropertyBool(mrt_output) #define LIGHTING @shPropertyBool(lighting) -#if FOG || MRT +#define SHADOWS LIGHTING && 0 +#define SHADOWS_PSSM LIGHTING + +#define SHADOWS 1 && LIGHTING +#define SHADOWS_PSSM 0 && LIGHTING + +#if FOG || MRT || SHADOWS_PSSM #define NEED_DEPTH #endif -#define NUM_LIGHTS 8 - #define HAS_VERTEXCOLOR @shPropertyBool(has_vertex_colour) #ifdef SH_VERTEX_SHADER + // ------------------------------------- VERTEX --------------------------------------- + SH_BEGIN_PROGRAM shUniform(float4x4 wvp) @shAutoConstant(wvp, worldviewproj_matrix) shInput(float2, uv0) @@ -33,11 +41,28 @@ shColourInput(float4) shOutput(float4, colorPassthrough) #endif + +#if SHADOWS + shOutput(float4, lightSpacePos0) + shUniform(float4x4 texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) + shUniform(float4x4 worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + +#if SHADOWS_PSSM + @shForeach(3) + shOutput(float4, lightSpacePos@shIterator) + shUniform(float4x4 texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) + @shEndForeach + shUniform(float4x4 worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; +#if LIGHTING normalPassthrough = normal.xyz; +#endif + #ifdef NEED_DEPTH depthPassthrough = shOutputPosition.z; #endif @@ -49,10 +74,22 @@ #if HAS_VERTEXCOLOR colorPassthrough = colour; #endif + +#if SHADOWS + lightSpacePos0 = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); +#endif +#if SHADOWS_PSSM + float4 wPos = shMatrixMult(worldMatrix, shInputPosition); + @shForeach(3) + lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); + @shEndForeach +#endif } #else + // ----------------------------------- FRAGMENT ------------------------------------------ + SH_BEGIN_PROGRAM shSampler2D(diffuseMap) shInput(float2, UV) @@ -76,7 +113,7 @@ shUniform(float4 materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) shUniform(float4 materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4 materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) - @shForeach(NUM_LIGHTS) + @shForeach(8) shUniform(float4 lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) shUniform(float4 lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) shUniform(float4 lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) @@ -91,6 +128,24 @@ #ifdef HAS_VERTEXCOLOR shInput(float4, colorPassthrough) #endif + +#if SHADOWS + shInput(float4, lightSpacePos0) + shSampler2D(shadowMap0) + shUniform(float2 invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, 0) +#endif +#if SHADOWS_PSSM + @shForeach(3) + shInput(float4, lightSpacePos@shIterator) + shSampler2D(shadowMap@shIterator) + shUniform(float2 invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator) + @shEndForeach + shUniform(float4 pssmSplitPoints) @shSharedParameter(pssmSplitPoints) +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4 shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) +#endif SH_START_PROGRAM { shOutputColor(0) = shSample(diffuseMap, UV); @@ -101,15 +156,38 @@ float d; float3 ambient = materialAmbient.xyz * lightAmbient.xyz; - @shForeach(NUM_LIGHTS) + @shForeach(8) + + // shadows only for the first (directional) light +#if @shIterator == 0 + #if SHADOWS + float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); + #endif + #if SHADOWS_PSSM + float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); + #endif + + #if SHADOWS || SHADOWS_PSSM + float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; + float fade = 1-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); + shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); + #endif + + #if !SHADOWS && !SHADOWS_PSSM + float shadow = 1.0; + #endif +#endif lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePositionPassthrough.xyz * lightPosObjSpace@shIterator.w); d = length(lightDir); lightDir = normalize(lightDir); +#if @shIterator == 0 + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow; +#else diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); - +#endif @shEndForeach #if HAS_VERTEXCOLOR diff --git a/files/materials/objects.shaderset b/files/materials/objects.shaderset index 7d01973e3c..e84368a5b9 100644 --- a/files/materials/objects.shaderset +++ b/files/materials/objects.shaderset @@ -2,7 +2,7 @@ shader_set openmw_objects_vertex { source objects.shader type vertex - profiles_cg vs_2_0 arbvp1 + profiles_cg vs_2_0 vp40 arbvp1 profiles_hlsl vs_2_0 } @@ -10,6 +10,6 @@ shader_set openmw_objects_fragment { source objects.shader type fragment - profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 profiles_hlsl ps_2_0 } diff --git a/files/materials/shadows.h b/files/materials/shadows.h new file mode 100644 index 0000000000..a3518b9764 --- /dev/null +++ b/files/materials/shadows.h @@ -0,0 +1,47 @@ + + + +float depthShadowPCF (shTexture2D shadowMap, float4 shadowMapPos, float2 offset) +{ + shadowMapPos /= shadowMapPos.w; + float3 o = float3(offset.xy, -offset.x) * 0.3; + //float3 o = float3(0,0,0); + float c = (shadowMapPos.z <= shSample(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left + c += (shadowMapPos.z <= shSample(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right + c += (shadowMapPos.z <= shSample(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left + c += (shadowMapPos.z <= shSample(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right + return c / 4; +} + + + +float pssmDepthShadow ( + + + float4 lightSpacePos0, + float2 invShadowmapSize0, + shTexture2D shadowMap0, + + float4 lightSpacePos1, + float2 invShadowmapSize1, + shTexture2D shadowMap1, + + float4 lightSpacePos2, + float2 invShadowmapSize2, + shTexture2D shadowMap2, + + float depth, + float4 pssmSplitPoints) + +{ + float shadow; + + if (depth < pssmSplitPoints.x) + shadow = depthShadowPCF(shadowMap0, lightSpacePos0, invShadowmapSize0); + else if (depth < pssmSplitPoints.y) + shadow = depthShadowPCF(shadowMap1, lightSpacePos1, invShadowmapSize1); + else + shadow = depthShadowPCF(shadowMap2, lightSpacePos2, invShadowmapSize2); + + return shadow; +}