diff --git a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/Common.hlsl b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/Common.hlsl index 1312484d1..dc024b8bc 100644 --- a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/Common.hlsl +++ b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/Common.hlsl @@ -48,3 +48,11 @@ float2 ViewToUV(float3 position, bool is_position, uint a_eyeIndex) float4 uv = mul(ProjMatrix[a_eyeIndex], float4(position, (float)is_position)); return (uv.xy / uv.w) * float2(0.5f, -0.5f) + 0.5f; } + +uint GetEyeIndexFromTexCoord(float2 texCoord) +{ +#ifdef VR + return (texCoord.x >= 0.5) ? 1 : 0; +#endif // VR + return 0; +} diff --git a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/FilterCS.hlsl b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/FilterCS.hlsl index 738ce35ee..e85a08dc3 100644 --- a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/FilterCS.hlsl +++ b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/FilterCS.hlsl @@ -81,12 +81,7 @@ float InverseProjectUV(float2 uv, uint a_eyeIndex) #endif float2 texCoord = (DTid.xy + 0.5) * RcpBufferDim; - -#ifdef VR - uint eyeIndex = (texCoord.x >= 0.5) ? 1 : 0; -#else - uint eyeIndex = 0; -#endif // VR + uint eyeIndex = GetEyeIndexFromTexCoord(texCoord); float startDepth = GetDepth(texCoord * 2 * DynamicRes.zw); if (startDepth >= 1) diff --git a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/RaymarchCS.hlsl b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/RaymarchCS.hlsl index 153d55f91..6d5815506 100644 --- a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/RaymarchCS.hlsl +++ b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/RaymarchCS.hlsl @@ -2,6 +2,24 @@ Texture2D ShadowTexture : register(t1); +// Needed to fix a bug in VR that caused the arm +// to have the "outline" of the VR headset canvas +// rendered into it and to not cast rays outside the eyes +#ifdef VR +Texture2D StencilTexture : register(t89); + +float GetStencil(float2 uv) +{ + return StencilTexture.Load(int3(uv * BufferDim * DynamicRes.xy, 0)).g; +} + +float GetStencil(float2 uv, uint a_eyeIndex) +{ + uv = ConvertToStereoUV(uv, a_eyeIndex); + return GetStencil(uv); +} +#endif // VR + bool IsSaturated(float value) { return value == saturate(value); } bool IsSaturated(float2 value) { return IsSaturated(value.x) && IsSaturated(value.y); } @@ -31,16 +49,20 @@ float GetScreenDepth(float2 uv, uint a_eyeIndex) return GetScreenDepth(depth); } -float ScreenSpaceShadowsUV(float2 stereoTexCoord, uint eyeIndex) +float ScreenSpaceShadowsUV(float2 texcoord, float3 lightDirectionVS, uint eyeIndex) { - float2 texcoord = ConvertFromStereoUV(stereoTexCoord, eyeIndex); +#ifdef VR + if (GetStencil(texcoord) != 0) + return 1; +#endif // VR + // Ignore the sky - float startDepth = GetDepth(stereoTexCoord); + float startDepth = GetDepth(texcoord); if (startDepth >= 1) return 1; // Compute ray position in view-space - float3 rayPos = InverseProjectUVZ(texcoord, startDepth, eyeIndex); + float3 rayPos = InverseProjectUVZ(ConvertFromStereoUV(texcoord, eyeIndex), startDepth, eyeIndex); // Blends effect variables between near, mid and far field float blendFactorFar = smoothstep(ShadowDistance / 3, ShadowDistance / 2, rayPos.z); @@ -56,10 +78,10 @@ float ScreenSpaceShadowsUV(float2 stereoTexCoord, uint eyeIndex) float stepLength = maxDistance / (float)maxSteps; // Compute ray step - float3 rayStep = InvDirLightDirectionVS.xyz * stepLength; + float3 rayStep = lightDirectionVS * stepLength; // Offset starting position with interleaved gradient noise - float offset = InterleavedGradientNoise(stereoTexCoord * BufferDim); + float offset = InterleavedGradientNoise(texcoord * BufferDim); rayPos += rayStep * offset; float thickness = lerp(NearThickness, rayPos.z * FarThicknessScale, blendFactorFar); @@ -80,6 +102,11 @@ float ScreenSpaceShadowsUV(float2 stereoTexCoord, uint eyeIndex) if (!IsSaturated(rayUV)) break; +#ifdef VR + if (GetStencil(rayUV, eyeIndex) != 0) + break; +#endif // VR + // Compute the difference between the ray's and the camera's depth float rayDepth = GetScreenDepth(rayUV, eyeIndex); @@ -107,12 +134,6 @@ float ScreenSpaceShadowsUV(float2 stereoTexCoord, uint eyeIndex) [numthreads(32, 32, 1)] void main(uint3 DTid : SV_DispatchThreadID) { float2 texCoord = (DTid.xy + 0.5) * RcpBufferDim * DynamicRes.zw; - -#ifdef VR - uint eyeIndex = (texCoord.x >= 0.5) ? 1 : 0; -#else - uint eyeIndex = 0; -#endif // VR - - OcclusionRW[DTid.xy] = ScreenSpaceShadowsUV(texCoord, eyeIndex); + uint eyeIndex = GetEyeIndexFromTexCoord(texCoord); + OcclusionRW[DTid.xy] = ScreenSpaceShadowsUV(texCoord, InvDirLightDirectionVS.xyz, eyeIndex); } \ No newline at end of file diff --git a/src/Feature.cpp b/src/Feature.cpp index 6c4ba1fd4..600f89ce6 100644 --- a/src/Feature.cpp +++ b/src/Feature.cpp @@ -119,13 +119,13 @@ const std::vector& Feature::GetFeatureList() }; static std::vector featuresVR = { + DynamicCubemaps::GetSingleton(), GrassLighting::GetSingleton(), GrassCollision::GetSingleton(), ScreenSpaceShadows::GetSingleton(), ExtendedMaterials::GetSingleton(), WetnessEffects::GetSingleton(), LightLimitFix::GetSingleton(), - DynamicCubemaps::GetSingleton(), TerrainBlending::GetSingleton(), WaterCaustics::GetSingleton(), SubsurfaceScattering::GetSingleton() diff --git a/src/Features/ScreenSpaceShadows.cpp b/src/Features/ScreenSpaceShadows.cpp index e4aa2c60b..809e19b33 100644 --- a/src/Features/ScreenSpaceShadows.cpp +++ b/src/Features/ScreenSpaceShadows.cpp @@ -53,7 +53,7 @@ void ScreenSpaceShadows::DrawSettings() } if (ImGui::TreeNodeEx("Near Shadows", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::SliderFloat("Near Distance", &settings.NearDistance, 0, 128); + ImGui::SliderFloat("Near Distance", &settings.NearDistance, 0.25f, 128); if (auto _tt = Util::HoverTooltipWrapper()) { ImGui::Text("Near Shadow Distance."); } @@ -339,6 +339,12 @@ void ScreenSpaceShadows::ModifyLighting(const RE::BSShader*, const uint32_t) ID3D11ShaderResourceView* view = depth.depthSRV; context->CSSetShaderResources(0, 1, &view); + ID3D11ShaderResourceView* stencilView = nullptr; + if (REL::Module::IsVR()) { + stencilView = depth.stencilSRV; + context->CSSetShaderResources(89, 1, &stencilView); + } + ID3D11UnorderedAccessView* uav = screenSpaceShadowsTexture->uav.get(); context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); @@ -347,6 +353,11 @@ void ScreenSpaceShadows::ModifyLighting(const RE::BSShader*, const uint32_t) context->Dispatch((uint32_t)std::ceil(resolutionX / 32.0f), (uint32_t)std::ceil(resolutionY / 32.0f), 1); + if (REL::Module::IsVR()) { + stencilView = nullptr; + context->CSSetShaderResources(89, 1, &stencilView); + } + // Filter { uav = nullptr; diff --git a/src/Features/ScreenSpaceShadows.h b/src/Features/ScreenSpaceShadows.h index 81a82186b..71bed5d20 100644 --- a/src/Features/ScreenSpaceShadows.h +++ b/src/Features/ScreenSpaceShadows.h @@ -19,7 +19,7 @@ struct ScreenSpaceShadows : Feature struct Settings { - uint32_t MaxSamples = 24; + uint32_t MaxSamples = !REL::Module::IsVR() ? 24u : 12u; float FarDistanceScale = 0.025f; float FarThicknessScale = 0.025f; float FarHardness = 8.0f;