Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: sh skylighting, fixes and cleanup #334

Merged
merged 70 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
a776c4e
feat: spherical harmonic skylighting
doodlum Jul 6, 2024
db7ca2a
chore: reduced wetness light intensity
doodlum Jul 6, 2024
ac3cdf3
chore: optimise setting constant buffers
doodlum Jul 6, 2024
00fafff
fix: disable VRS
doodlum Jul 6, 2024
b3deb2f
style: 🎨 apply clang-format changes
doodlum Jul 6, 2024
a5e9415
chore: performance improvements
doodlum Jul 7, 2024
721a984
fix: water reflections
doodlum Jul 7, 2024
05db32c
fix: skylighting flicker
doodlum Jul 7, 2024
ba96d4d
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 7, 2024
0daa7af
style: 🎨 apply clang-format changes
doodlum Jul 7, 2024
7ab4bd8
chore: minor cleanup
doodlum Jul 7, 2024
f5226c5
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 7, 2024
834e8d6
chore: convolve and ZH3 hallucination for diffuse skylighitng
Pentalimbed Jul 7, 2024
8bc8baa
chore: convolve and ZH3 hallucination for diffuse skylighting (#332)
doodlum Jul 7, 2024
0e4a4ca
chore: skylighting cleanup
doodlum Jul 7, 2024
152290c
fix: SSS crash
doodlum Jul 7, 2024
31eadc6
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 7, 2024
afb2a6f
fix: incorrect reflections
doodlum Jul 8, 2024
b0ff02b
style: 🎨 apply clang-format changes
doodlum Jul 8, 2024
5111476
fix: reflection and shadow fixes
doodlum Jul 8, 2024
a53436f
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 8, 2024
4c94688
style: 🎨 apply clang-format changes
doodlum Jul 8, 2024
a638774
feat: cubemap optimisation
doodlum Jul 8, 2024
15ffeee
chore: use correct depth buffer
doodlum Jul 8, 2024
b45bd68
fix: wetness edge seam
doodlum Jul 8, 2024
297d09b
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 8, 2024
f1fb1af
chore: cleaned up legacy code pending further changes
doodlum Jul 9, 2024
d5f6848
style: 🎨 apply clang-format changes
doodlum Jul 9, 2024
867c9ed
Merge branch 'skylighting-sh' into skylighting-sh-merge
doodlum Jul 9, 2024
064164f
style: 🎨 apply clang-format changes
doodlum Jul 9, 2024
f73ef3e
Merge pull request #333 from doodlum/skylighting-sh-merge
doodlum Jul 9, 2024
46d0ea7
fix: minor wetness issues
doodlum Jul 9, 2024
7514711
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 9, 2024
4df420f
style: 🎨 apply clang-format changes
doodlum Jul 9, 2024
5a38714
fix: fix VR in skylighting-sh branch
FlayaN Jul 9, 2024
5e3ebb1
Merge pull request #335 from FlayaN/skylighting-sh
doodlum Jul 9, 2024
cce0993
feat: adjustments to improve dynamic cubemaps after quality reduction
doodlum Jul 10, 2024
8507f39
style: 🎨 apply clang-format changes
doodlum Jul 10, 2024
5abe536
fix: fix AE support
FlayaN Jul 10, 2024
e669c4a
chore: dynamic cubemap tweaks
doodlum Jul 10, 2024
19a7022
chore: more contrast to specular skylighting
doodlum Jul 10, 2024
6a1d546
style: 🎨 apply clang-format changes
doodlum Jul 10, 2024
3c78c8a
Merge branch 'dynamic-cubemap-improvements' of https://github.com/doo…
doodlum Jul 10, 2024
1504e48
fix: dynamic cubemap feedback loop
doodlum Jul 10, 2024
7987468
fix: dynamic cubemap fade fixes
doodlum Jul 10, 2024
88e6c60
style: 🎨 apply clang-format changes
doodlum Jul 10, 2024
f944345
fix: reset dynamic cubemap when shaders are missing
doodlum Jul 11, 2024
a934533
Merge branch 'dynamic-cubemap-improvements' of https://github.com/doo…
doodlum Jul 11, 2024
acc603a
Merge pull request #336 from FlayaN/skylighting-sh
doodlum Jul 11, 2024
e1e6dc1
Merge pull request #337 from doodlum/dynamic-cubemap-improvements
doodlum Jul 11, 2024
a79da75
feat: GetTemporal utility function
doodlum Jul 11, 2024
95d0a32
feat: skylighting optimisation and blur pass
doodlum Jul 11, 2024
851c6af
feat: low precision depth buffer
doodlum Jul 11, 2024
7384dd8
style: 🎨 apply clang-format changes
doodlum Jul 11, 2024
e85d4e5
fix: skylighting position adjust
doodlum Jul 11, 2024
c7aa022
feat: low precision depth when available
doodlum Jul 11, 2024
858d5bc
refactor: lower case frameCount
doodlum Jul 11, 2024
9b1c2f4
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 11, 2024
054c798
style: 🎨 apply clang-format changes
doodlum Jul 11, 2024
5ff6535
chore: artistic tweaks to skylighting application
doodlum Jul 11, 2024
57b4898
Merge branch 'skylighting-sh' of https://github.com/doodlum/skyrim-co…
doodlum Jul 11, 2024
cb9dec0
style: 🎨 apply clang-format changes
doodlum Jul 11, 2024
47c3a0a
feat: skylighting update timer
doodlum Jul 11, 2024
033273d
feat: skylighting and ambient improvements
doodlum Jul 18, 2024
d78b628
style: 🎨 apply clang-format changes
doodlum Jul 18, 2024
5a26332
Merge branch 'dev' into skylighting-sh
doodlum Jul 18, 2024
c3fe52f
refactor: switch on UpdateCubemap
doodlum Jul 18, 2024
4f7fd44
refactor: divide instead of multiply
doodlum Jul 18, 2024
aad4529
chore: remove unused CameraData
doodlum Jul 22, 2024
fa53725
Merge branch 'dev' into skylighting-sh
doodlum Jul 22, 2024
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 @@ -18,7 +18,7 @@ float3 GetDynamicCubemap(float2 uv, float3 N, float3 VN, float3 V, float roughne
float3 R = reflect(-V, N);
float NoV = saturate(dot(N, V));

float level = roughness * 9.0;
float level = roughness * 7.0;

float2 specularBRDF = EnvBRDFApprox(roughness, NoV);

Expand Down
3 changes: 3 additions & 0 deletions features/Skylighting/Shaders/Skylighting/Skylighting.hlsli
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "Common/Spherical Harmonics/SphericalHarmonics.hlsli"

Texture2D<unorm float> OcclusionMapSampler : register(t29);
Texture2D<unorm float4> SkylightingTexture : register(t30);
Texture2D<unorm float> WetnessOcclusionTexture : register(t31);

cbuffer SkylightingData : register(b8)
{
Expand Down
248 changes: 117 additions & 131 deletions features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "../Common/DeferredShared.hlsli"
#include "../Common/FrameBuffer.hlsl"
#include "../Common/GBuffer.hlsli"
#include "../Common/Spherical Harmonics/SphericalHarmonics.hlsli"
#include "../Common/VR.hlsli"

Texture2D<unorm float> DepthTexture : register(t0);
Texture2D<float> DepthTexture : register(t0);

struct PerGeometry
{
Expand All @@ -26,15 +26,19 @@ Texture2DArray<unorm float> TexShadowMapSampler : register(t1);
StructuredBuffer<PerGeometry> perShadow : register(t2);
Texture2DArray<float4> BlueNoise : register(t3);
Texture2D<unorm float> OcclusionMapSampler : register(t4);
Texture2D<unorm half3> NormalRoughnessTexture : register(t5);

RWTexture2D<half2> SkylightingTextureRW : register(u0);
RWTexture2D<float4> SkylightingTextureRW : register(u0);
RWTexture2D<unorm float> WetnessOcclusionTextureRW : register(u1);

cbuffer PerFrame : register(b0)
{
row_major float4x4 OcclusionViewProj;
float4 EyePosition;
float4 ShadowDirection;
float4 Parameters;
float4 BufferDim;
float4 CameraData;
uint FrameCount;
};

SamplerState LinearSampler : register(s0);
Expand All @@ -45,130 +49,113 @@ half GetBlueNoise(half2 uv)
return BlueNoise[uint3(uv % 128, FrameCount % 64)];
}

half GetScreenDepth(half depth)
{
return (CameraData.w / (-depth * CameraData.z + CameraData.x));
}

#define PI 3.1415927

#if !defined(SHADOWMAP)
[numthreads(8, 8, 1)] void main(uint3 globalId
: SV_DispatchThreadID) {
float2 uv = float2(globalId.xy + 0.5) * BufferDim.zw * DynamicResolutionParams2.xy;
float2 uv = float2(globalId.xy + 0.5) * (BufferDim.zw) * DynamicResolutionParams2.xy;
uint eyeIndex = GetEyeIndexFromTexCoord(uv);
uv = ConvertFromStereoUV(uv, eyeIndex);

half3 normalGlossiness = NormalRoughnessTexture[globalId.xy];
half3 normalVS = DecodeNormal(normalGlossiness.xy);
half3 normalWS = normalize(mul(CameraViewInverse[eyeIndex], half4(normalVS, 0)));
half roughness = 1.0 - normalGlossiness.z;

float rawDepth = DepthTexture[globalId.xy];

float4 positionCS = float4(2 * float2(uv.x, -uv.y + 1) - 1, rawDepth, 1);

float4 positionMS = mul(CameraViewProjInverse[eyeIndex], positionCS);
positionMS.xyz = positionMS.xyz / positionMS.w;

positionMS.xyz = positionMS.xyz - CameraPosAdjust[eyeIndex] + EyePosition;

float3 startPositionMS = positionMS;

half noise = GetBlueNoise(globalId.xy) * 2.0 * PI;
half noise = GetBlueNoise(globalId.xy) * 2.0 * shPI;

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

half2 PoissonDisk[16] = {
half2(-0.94201624, -0.39906216),
half2(0.94558609, -0.76890725),
half2(-0.094184101, -0.92938870),
half2(0.34495938, 0.29387760),
half2(-0.91588581, 0.45771432),
half2(-0.81544232, -0.87912464),
half2(-0.38277543, 0.27676845),
half2(0.97484398, 0.75648379),
half2(0.44323325, -0.97511554),
half2(0.53742981, -0.47373420),
half2(-0.26496911, -0.41893023),
half2(0.79197514, 0.19090188),
half2(-0.24188840, 0.99706507),
half2(-0.81409955, 0.91437590),
half2(0.19984126, 0.78641367),
half2(0.14383161, -0.14100790)
float2 PoissonDisc[16] = {
float2(0.107883f, 0.374004f),
float2(0.501633f, 0.773888f),
float2(0.970519f, 0.248024f),
float2(0.999939f, 0.896329f),
float2(0.492874f, 0.0122379f),
float2(0.00650044f, 0.943358f),
float2(0.569201f, 0.382672f),
float2(0.0345164f, 0.00137333f),
float2(0.93289f, 0.616749f),
float2(0.3155f, 0.989013f),
float2(0.197119f, 0.701132f),
float2(0.721946f, 0.983612f),
float2(0.773705f, 0.0301218f),
float2(0.400403f, 0.541612f),
float2(0.728111f, 0.236213f),
float2(0.240547f, 0.0980255f)
};

uint sampleCount = 16;

float occlusionThreshold = mul(OcclusionViewProj, float4(positionMS.xyz, 1)).z;

half3 V = normalize(positionMS.xyz);
half3 R = reflect(V, normalWS);

bool fadeOut = length(startPositionMS) > 1024;

half3 skylighting = 0;
half3 weights = 0.0;
half weight = 0;
half wetnessWeight = 0;

sh2 shSkylighting = shZero();
float wetnessOcclusion = 0;

half fadeFactor = pow(saturate(length(positionMS.xyz) / 10000.0), 8);

[unroll] for (uint i = 0; i < sampleCount; i++)
{
half2 offset = mul(PoissonDisk[i].xy, rotationMatrix);
half shift = half(i) / half(sampleCount);
half radius = length(offset);
float3 rayDir = float3(PoissonDisc[i].xy * 2.0 - 1.0, 0);
rayDir.xy = mul(rayDir.xy, rotationMatrix);

positionMS.xy = startPositionMS + rayDir.xy * 128;

positionMS.xy = startPositionMS + offset * 128;
rayDir = normalize(rayDir);

half2 occlusionPosition = mul((float2x4)OcclusionViewProj, float4(positionMS.xyz, 1));
occlusionPosition.y = -occlusionPosition.y;
half2 occlusionUV = occlusionPosition.xy * 0.5 + 0.5;

half3 offsetDirection = normalize(half3(offset.xy, pow(1.0 - (radius * 0.5), Parameters.y)));
float wetnessScale = 1.0 - (length(rayDir) * 0.5);

if ((occlusionUV.x == saturate(occlusionUV.x) && occlusionUV.y == saturate(occlusionUV.y)) || !fadeOut) {
half shadowMapValues = OcclusionMapSampler.SampleCmpLevelZero(ShadowSamplerPCF, occlusionUV, occlusionThreshold - (1e-2 * 0.05 * radius));

half3 H = normalize(-offsetDirection + V);
half NoH = dot(normalWS, H);
half a = NoH * roughness;
half k = roughness / (1.0 - NoH * NoH + a * a);
half ggx = k * k * (1.0 / PI);

half NDotL = dot(normalWS.xyz, offsetDirection.xyz);

half3 contributions = half3(saturate(NDotL), ggx, NDotL * 0.5 + 0.5);

skylighting += shadowMapValues * contributions;
weights += contributions;
half shadowMapValues = saturate((OcclusionMapSampler.SampleLevel(LinearSampler, occlusionUV, 0) - occlusionThreshold + 0.001) * 1024);
sh2 sh = shEvaluate(rayDir);
shSkylighting = shAdd(shSkylighting, shScale(sh, lerp(shadowMapValues, 1.0, fadeFactor)));
wetnessOcclusion += shadowMapValues * wetnessScale;
wetnessWeight += wetnessScale;
weight++;
} else {
skylighting++;
weights++;
sh2 sh = shEvaluate(rayDir);
shSkylighting = shAdd(shSkylighting, shScale(sh, 1));
weight++;
wetnessWeight += wetnessScale;
}
}

if (weights.x > 0.0)
skylighting.x /= weights.x;
if (weights.y > 0.0)
skylighting.y /= weights.y;
if (weights.z > 0.0)
skylighting.z /= weights.z;

skylighting.x = lerp(skylighting.z, 1.0, Parameters.x) * Parameters.z + skylighting.x * saturate(dot(normalWS, float3(0, 0, 1))) * Parameters.w;
skylighting.y = saturate(skylighting.y);

half fadeFactor = pow(saturate(length(positionMS.xyz) / 10000.0), 8);
if (weight > 0.0) {
float shFactor = 4.0 * shPI / weight;
shSkylighting = shScale(shSkylighting, shFactor);
wetnessOcclusion /= wetnessWeight;
}

SkylightingTextureRW[globalId.xy] = lerp(skylighting.xy, 1.0, fadeFactor);
SkylightingTextureRW[globalId.xy] = shSkylighting;
WetnessOcclusionTextureRW[globalId.xy] = saturate(wetnessOcclusion * wetnessOcclusion * 4);
}
#else

half GetScreenDepth(half depth)
{
return (CameraData.w / (-depth * CameraData.z + CameraData.x));
}

[numthreads(8, 8, 1)] void main(uint3 globalId
: SV_DispatchThreadID) {
float2 uv = float2(globalId.xy + 0.5) * BufferDim.zw * DynamicResolutionParams2.xy;
uint eyeIndex = GetEyeIndexFromTexCoord(uv);
uv = ConvertFromStereoUV(uv, eyeIndex);

half3 normalGlossiness = NormalRoughnessTexture[globalId.xy];
half3 normalVS = DecodeNormal(normalGlossiness.xy);
half3 normalWS = normalize(mul(CameraViewInverse[eyeIndex], half4(normalVS, 0)));
half roughness = 1.0 - normalGlossiness.z;

float rawDepth = DepthTexture[globalId.xy];

float4 positionCS = float4(2 * float2(uv.x, -uv.y + 1) - 1, rawDepth, 1);
Expand All @@ -187,100 +174,99 @@ half GetScreenDepth(half depth)

half fadeFactor = pow(saturate(dot(positionMS.xyz, positionMS.xyz) / sD.ShadowLightParam.z), 8);

half noise = GetBlueNoise(globalId.xy) * 2.0 * PI;
fadeFactor = lerp(1.0, fadeFactor, pow(saturate(dot(float3(0, 0, -1), ShadowDirection.xyz)), 0.25));

half noise = GetBlueNoise(globalId.xy) * 2.0 * shPI;

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

half2 PoissonDisk[16] = {
half2(-0.94201624, -0.39906216),
half2(0.94558609, -0.76890725),
half2(-0.094184101, -0.92938870),
half2(0.34495938, 0.29387760),
half2(-0.91588581, 0.45771432),
half2(-0.81544232, -0.87912464),
half2(-0.38277543, 0.27676845),
half2(0.97484398, 0.75648379),
half2(0.44323325, -0.97511554),
half2(0.53742981, -0.47373420),
half2(-0.26496911, -0.41893023),
half2(0.79197514, 0.19090188),
half2(-0.24188840, 0.99706507),
half2(-0.81409955, 0.91437590),
half2(0.19984126, 0.78641367),
half2(0.14383161, -0.14100790)
float2 PoissonDisc[16] = {
float2(0.107883f, 0.374004f),
float2(0.501633f, 0.773888f),
float2(0.970519f, 0.248024f),
float2(0.999939f, 0.896329f),
float2(0.492874f, 0.0122379f),
float2(0.00650044f, 0.943358f),
float2(0.569201f, 0.382672f),
float2(0.0345164f, 0.00137333f),
float2(0.93289f, 0.616749f),
float2(0.3155f, 0.989013f),
float2(0.197119f, 0.701132f),
float2(0.721946f, 0.983612f),
float2(0.773705f, 0.0301218f),
float2(0.400403f, 0.541612f),
float2(0.728111f, 0.236213f),
float2(0.240547f, 0.0980255f)
};

uint sampleCount = 16;

half3 V = normalize(positionMS.xyz);
half3 R = reflect(V, normalWS);
sh2 shSkylighting = shZero();
float wetnessOcclusion = 0;

half3 skylighting = 0;
half3 weights = 0.0;
half weight = 0.0;
half wetnessWeight = 0;

uint validSamples = 0;
[unroll] for (uint i = 0; i < sampleCount; i++)
{
half2 offset = mul(PoissonDisk[i].xy, rotationMatrix);
half shift = half(i) / half(sampleCount);
half radius = length(offset);
float3 rayDir = float3(PoissonDisc[i].xy * 2.0 - 1.0, 0);
rayDir.xy = mul(rayDir.xy, rotationMatrix);

positionMS.xy = startPositionMS + offset.xy * 128 + length(offset.xy) * ShadowDirection.xy * 128;
positionMS.xy = startPositionMS + rayDir.xy * 128 + length(rayDir.xy) * ShadowDirection.xy * 128;

half3 offsetDirection = normalize(half3(offset.xy, pow(1.0 - (radius * 0.5), Parameters.y)));
rayDir = normalize(rayDir);

float shadowMapDepth = length(positionMS.xyz);

[flatten] if (sD.EndSplitDistances.z > shadowMapDepth)
{
half cascadeIndex = 0;
float4x3 lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][0];
float shadowMapThreshold = sD.AlphaTestRef.y;

[flatten] if (2.5 < sD.EndSplitDistances.w && sD.EndSplitDistances.y < shadowMapDepth)
{
lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][2];
shadowMapThreshold = sD.AlphaTestRef.z;
cascadeIndex = 2;
}
else if (sD.EndSplitDistances.x < shadowMapDepth)
{
lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][1];
shadowMapThreshold = sD.AlphaTestRef.z;
cascadeIndex = 1;
}

float3 positionLS = mul(transpose(lightProjectionMatrix), float4(positionMS.xyz, 1)).xyz;

half shadowMapValues = TexShadowMapSampler.SampleLevel(LinearSampler, float3(positionLS.xy, cascadeIndex), 0) > positionLS.z - shadowMapThreshold;
half shadowMapValues = saturate((TexShadowMapSampler.SampleLevel(LinearSampler, float3(positionLS.xy, cascadeIndex), 0) - positionLS.z + 0.001) * 1024);

half3 H = normalize(-offsetDirection + V);
half NoH = dot(normalWS, H);
half a = NoH * roughness;
half k = roughness / (1.0 - NoH * NoH + a * a);
half ggx = k * k * (1.0 / PI);
sh2 sh = shEvaluate(rayDir);
shSkylighting = shAdd(shSkylighting, shScale(sh, lerp(shadowMapValues, 1.0, fadeFactor)));

half NDotL = dot(normalWS.xyz, offsetDirection.xyz);
float wetnessScale = 1.0 - (length(rayDir) * 0.5);
wetnessOcclusion += shadowMapValues * wetnessScale;
wetnessWeight += wetnessScale;

half3 contributions = half3(saturate(NDotL), ggx, NDotL * 0.5 + 0.5);

skylighting += shadowMapValues * contributions;
weights += contributions;
weight++;
}
}
else
{
sh2 sh = shEvaluate(rayDir);
shSkylighting = shAdd(shSkylighting, shScale(sh, 1.0));

if (weights.x > 0.0)
skylighting.x /= weights.x;
if (weights.y > 0.0)
skylighting.y /= weights.y;
if (weights.z > 0.0)
skylighting.z /= weights.z;
float wetnessScale = 1.0 - (length(rayDir) * 0.5);
wetnessOcclusion += wetnessScale;
wetnessWeight += wetnessScale;

skylighting.x = lerp(skylighting.z, 1.0, Parameters.x) * Parameters.z + skylighting.x * saturate(dot(normalWS, float3(0, 0, 1))) * Parameters.w;
skylighting.y = saturate(skylighting.y);
weight++;
}
}

skylighting = lerp(1.0, skylighting, pow(saturate(dot(float3(0, 0, -1), ShadowDirection.xyz)), 0.25));
if (weight > 0.0) {
float shFactor = 4.0 * shPI / weight;
shSkylighting = shScale(shSkylighting, shFactor);
wetnessOcclusion /= wetnessWeight;
}

SkylightingTextureRW[globalId.xy] = lerp(skylighting.xy, 1.0, fadeFactor);
SkylightingTextureRW[globalId.xy] = shSkylighting;
WetnessOcclusionTextureRW[globalId.xy] = saturate(wetnessOcclusion * wetnessOcclusion * 4);
}
#endif
Loading
Loading