Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ namespace ExtendedMaterials
float2 GetParallaxCoords(float distance, float2 coords, float mipLevel, float3 viewDir, float3x3 tbn, float noise, Texture2D<float4> tex, SamplerState texSampler, uint channel, DisplacementParams params, out float pixelOffset)
#endif
{
pixelOffset = 0;
float3 viewDirTS = normalize(mul(tbn, viewDir));
#if defined(LANDSCAPE)
viewDirTS.xy /= viewDirTS.z * 0.7 + 0.3 + params[0].FlattenAmount; // Fix for objects at extreme viewing angles
Expand Down Expand Up @@ -496,7 +497,7 @@ namespace ExtendedMaterials
#endif
nearBlendToFar *= nearBlendToFar;
float offset = (1.0 - parallaxAmount) * -maxHeight + minHeight;
pixelOffset = lerp(parallaxAmount * scale, 0, nearBlendToFar);
pixelOffset = saturate(lerp(parallaxAmount, 0.5, nearBlendToFar));
return lerp(viewDirTS.xy * offset + coords.xy, coords, nearBlendToFar);
}

Expand Down
18 changes: 18 additions & 0 deletions features/Screen Space GI/Shaders/ScreenSpaceGI/blur.cs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ RWTexture2D<unorm float> outAccumFrames : register(u0);
RWTexture2D<float4> outIlY : register(u1);
RWTexture2D<float2> outIlCoCg : register(u2);

#if defined(VR_STEREO_OPT)
Texture2D<uint> StereoOptModeTexture : register(t16);
#endif

// samples = 8, min distance = 0.5, average samples on radius = 2
static const float3 g_Poisson8[8] = {
float3(-0.4706069, -0.4427112, +0.6461146),
Expand Down Expand Up @@ -88,6 +92,20 @@ float2x2 getRotationMatrix(float noise)
// Early exit if dispatch thread is outside frame bounds
if (any(dtid >= uint2(OUT_FRAME_DIM)))
return;

#if defined(VR_STEREO_OPT)
{
float2 uv = (dtid + .5) * RCP_OUT_FRAME_DIM;
uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);
if (eyeIndex == 1) {
uint2 fullResPx = uint2(uv * FrameDim);
uint mode = StereoOptModeTexture[fullResPx];
if (mode == 1 || mode == 2)
return;
}
}
#endif

const float2 frameScale = FrameDim * RcpTexDim;

float radius = BlurRadius;
Expand Down
13 changes: 13 additions & 0 deletions features/Screen Space GI/Shaders/ScreenSpaceGI/gi.cs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ Texture2D<float4> srcPrevY : register(t6); // maybe half-res
Texture2D<float2> srcPrevCoCg : register(t7); // maybe half-res
Texture2D<float4> srcPrevGISpecular : register(t8); // maybe half-res

#if defined(VR_STEREO_OPT)
Texture2D<uint> StereoOptModeTexture : register(t16);
#endif

RWTexture2D<unorm float> outAo : register(u0);
RWTexture2D<float4> outY : register(u1);
RWTexture2D<float2> outCoCg : register(u2);
Expand Down Expand Up @@ -343,6 +347,15 @@ void CalculateGI(
float2 uv = (pxCoord + .5) * RCP_OUT_FRAME_DIM;
uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);

#if defined(VR_STEREO_OPT)
if (eyeIndex == 1) {
uint2 fullResPx = uint2(uv * FrameDim);
uint mode = StereoOptModeTexture[fullResPx];
if (mode == 1 || mode == 2)
return;
}
#endif

float viewspaceZ = READ_DEPTH(srcWorkingDepth, pxCoord);

float2 normalSample = FULLRES_LOAD(srcNormalRoughness, pxCoord, uv * frameScale, samplerLinearClamp).xy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Texture2D<half4> srcPrevIlY : register(t7); // maybe half-res
Texture2D<half2> srcPrevIlCoCg : register(t8); // maybe half-res
Texture2D<half4> srcPrevGISpecular : register(t9); // maybe half-res

#if defined(VR_STEREO_OPT)
Texture2D<uint> StereoOptModeTexture : register(t16);
#endif

RWTexture2D<float3> outRadianceDisocc : register(u0);
RWTexture2D<unorm float> outAccumFrames : register(u1);
RWTexture2D<float> outRemappedAo : register(u2);
Expand Down Expand Up @@ -75,6 +79,16 @@ void readHistory(

const float2 uv = (pixCoord + .5) * RCP_OUT_FRAME_DIM;
const uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);

#if defined(VR_STEREO_OPT)
if (eyeIndex == 1) {
uint2 fullResPx = uint2(uv * FrameDim);
uint mode = StereoOptModeTexture[fullResPx];
if (mode == 1 || mode == 2)
return;
}
#endif

const float2 screen_pos = Stereo::ConvertFromStereoUV(uv, eyeIndex);

float2 prev_screen_pos = screen_pos;
Expand Down
15 changes: 15 additions & 0 deletions features/Screen Space GI/Shaders/ScreenSpaceGI/stereoSync.cs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Texture2D<float> srcAo : register(t1);
Texture2D<float4> srcIlY : register(t2);
Texture2D<float2> srcIlCoCg : register(t3);

# if defined(VR_STEREO_OPT)
Texture2D<uint> StereoOptModeTexture : register(t16);
# endif

RWTexture2D<float> outAo : register(u0);
RWTexture2D<float4> outIlY : register(u1);
RWTexture2D<float2> outIlCoCg : register(u2);
Expand Down Expand Up @@ -59,6 +63,17 @@ float4 SampleCrossDepths(float2 centerUV, float2 step, float2 texScale, uint eye

uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);

# if defined(VR_STEREO_OPT)
if (eyeIndex == 1) {
uint2 fullResPx = uint2(uv * FrameDim);
uint mode = StereoOptModeTexture[fullResPx];
if (mode == 1 || mode == 2) {
Passthrough(dtid);
return;
}
}
# endif

// SSGI working depth is linear view-space Z.
// 0.0 = mask (outside lens area). FP_Z = first-person hands threshold (~18.0).
float depth = srcDepth.SampleLevel(samplerPointClamp, uv * frameScale, RES_MIP);
Expand Down
18 changes: 18 additions & 0 deletions features/Screen Space GI/Shaders/ScreenSpaceGI/upsample.cs.hlsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// depth-aware upsampling: https://gist.github.com/pixelmager/a4364ea18305ed5ca707d89ddc5f8743

#include "Common/FastMath.hlsli"
#include "Common/VR.hlsli"
#include "ScreenSpaceGI/common.hlsli"

Texture2D<half> srcDepth : register(t0);
Expand All @@ -9,6 +10,10 @@ Texture2D<half4> srcIlY : register(t2); // half-res
Texture2D<half2> srcIlCoCg : register(t3); // half-res
Texture2D<half4> srcGiSpecular : register(t4); // half-res

#if defined(VR_STEREO_OPT)
Texture2D<uint> StereoOptModeTexture : register(t16);
#endif

RWTexture2D<half> outAo : register(u0);
RWTexture2D<half4> outIlY : register(u1);
RWTexture2D<half2> outIlCoCg : register(u2);
Expand All @@ -23,6 +28,19 @@ RWTexture2D<half4> outGiSpecular : register(u3);
// Early exit if dispatch thread is outside frame bounds
if (any(dtid >= uint2(FrameDim)))
return;

#if defined(VR_STEREO_OPT)
{
float2 uv = (dtid + .5) * RcpFrameDim;
uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);
if (eyeIndex == 1) {
uint mode = StereoOptModeTexture[dtid];
if (mode == 1 || mode == 2)
return;
}
}
#endif

#ifdef HALF_RES
int2 px00 = (dtid >> 1) + (dtid & 1) - 1;
#else // QUARTER_RES
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ cbuffer PerFrame : register(b1)

parameters.DynamicRes = DynamicRes;

parameters.UsePrecisionOffset = true;
// VR note: precision offset adds a depth bias that can cause subtle shadow
// shifting. Disabled to match the old (stable) SSS implementation.
// See: docs/development/Old code/RaymarchCS.hlsl
parameters.UsePrecisionOffset = false;

WriteScreenSpaceShadow(parameters, groupID, groupThreadID);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,82 @@
// Screen Space Shadows consumption helper.
// Non-VR: depth-weighted 4-sample Poisson blur for spatial denoising.
// VR: direct Load — the Poisson blur's per-pixel noise rotation is
// screen-position-dependent, causing shadows to shift on camera movement.
// Without TAA to average out the rotation noise, the instability hits
// the final output directly. Matches the stable v1.2 VR implementation.

#include "Common/Math.hlsli"

namespace ScreenSpaceShadows
{
Texture2D<unorm half> ScreenSpaceShadowsTexture : register(t45);

float4 GetBlurWeights(float4 depths, float centerDepth)
{
centerDepth += 1.0;
float depthSharpness = saturate((1024.0 * 1024.0) / (centerDepth * centerDepth));
float4 depthDifference = (depths - centerDepth) * depthSharpness;
return exp2(-depthDifference * depthDifference);
}

float GetScreenSpaceShadow(float3 screenPosition, float2 uv, float noise, uint eyeIndex)
{
return ScreenSpaceShadowsTexture.Load(int3(int2(screenPosition.xy + 0.5f), 0)).x;
#if defined(VR)
// VR: direct sample, no spatial blur. The Poisson blur's per-pixel noise
// rotation is screen-position-dependent — camera movement changes the
// rotation angle for the same world surface, causing shadows to visually
// shift. Without TAA to average out the rotation noise, the per-frame
// instability hits the final output directly. Direct Load avoids this.
// Matches the stable v1.2 VR implementation.
return ScreenSpaceShadowsTexture.Load(int3(screenPosition.xy, 0));
#else
// Flat: depth-weighted 4-sample Poisson blur for spatial denoising.
// Rotated per-pixel by screen-space noise to break structured patterns.
// TAA averages out the rotation noise across frames.
noise *= Math::TAU;

half2x2 rotationMatrix = half2x2(cos(noise), sin(noise), -sin(noise), cos(noise));

float4 shadowSamples = 0;
float4 depthSamples = 0;

# if defined(DEFERRED) && !defined(DO_ALPHA_TEST)
depthSamples[0] = screenPosition.z;
# else
depthSamples[0] = SharedData::DepthTexture.Load(int3(screenPosition.xy, 0));
# endif

shadowSamples[0] = ScreenSpaceShadowsTexture.Load(int3(screenPosition.xy, 0));

static const float2 BlurOffsets[3] = {
float2(-0.6720635096678028f, 0.6601738628451107f),
float2(0.6110340335380645f, 0.5269905984201742f),
float2(0.20239029763403027f, -0.7841160574831084f),
};

[unroll] for (uint i = 1; i < 4; i++)
{
float2 offset = mul(BlurOffsets[i - 1], rotationMatrix) * 0.0025;

float2 sampleUV = uv + offset;
sampleUV = saturate(sampleUV);

int3 sampleCoord = SharedData::ConvertUVToSampleCoord(sampleUV, eyeIndex);

depthSamples[i] = SharedData::DepthTexture.Load(sampleCoord).x;
shadowSamples[i] = ScreenSpaceShadowsTexture.Load(sampleCoord);
}

depthSamples = SharedData::GetScreenDepths(depthSamples);

float4 blurWeights = GetBlurWeights(depthSamples, depthSamples[0]);
float shadow = dot(shadowSamples, blurWeights);

float blurWeightsTotal = dot(blurWeights, 1.0);
[flatten] if (blurWeightsTotal > 0.0)
shadow = shadow / blurWeightsTotal;

return shadow;
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
Texture2D<float> SrcDepthTexture : register(t0);
Texture2D<unorm half> SrcShadowTexture : register(t1);

# if defined(VR_STEREO_OPT)
Texture2D<uint> StereoOptModeTexture : register(t16);
# endif

RWTexture2D<unorm half> OutShadowTexture : register(u0);

cbuffer StereoSyncCB : register(b1)
Expand Down Expand Up @@ -90,6 +94,18 @@ float4 SampleCrossDepths(int2 center, int offset, uint eyeIndex)

uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);

# if defined(VR_STEREO_OPT)
// Eye 1 pixels with mode 1 (edge) or 2 (main) will be overwritten by StereoBlend
// reprojection, so skip the expensive stereo sync work and write neutral (unshadowed).
if (eyeIndex == 1) {
uint mode = StereoOptModeTexture[uint2(dtid.xy)] & 0x0F;
if (mode == 1 || mode == 2) {
OutShadowTexture[dtid] = 1.0; // 1.0 = no shadow (neutral)
return;
}
}
# endif

float depth = SrcDepthTexture[dtid];

// depth == 0: VR HMD mask; depth == 1: sky/far plane
Expand Down
Loading
Loading