mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
150 lines
4.9 KiB
HLSL
150 lines
4.9 KiB
HLSL
Texture2D<float> g_DepthTexture : register(t0);
|
|
RWTexture2D<float> g_Output : register(u0);
|
|
sampler g_SamplerLinearClamp : register(s0);
|
|
|
|
// From https://www.shadertoy.com/view/3tB3z3 - except we're using R2 here
|
|
#define XE_HILBERT_LEVEL 6U
|
|
#define XE_HILBERT_WIDTH ( (1U << XE_HILBERT_LEVEL) )
|
|
#define XE_HILBERT_AREA ( XE_HILBERT_WIDTH * XE_HILBERT_WIDTH )
|
|
inline uint HilbertIndex( uint posX, uint posY )
|
|
{
|
|
uint index = 0U;
|
|
for( uint curLevel = XE_HILBERT_WIDTH/2U; curLevel > 0U; curLevel /= 2U )
|
|
{
|
|
uint regionX = ( posX & curLevel ) > 0U;
|
|
uint regionY = ( posY & curLevel ) > 0U;
|
|
index += curLevel * curLevel * ( (3U * regionX) ^ regionY);
|
|
if( regionY == 0U )
|
|
{
|
|
if( regionX == 1U )
|
|
{
|
|
posX = uint( (XE_HILBERT_WIDTH - 1U) ) - posX;
|
|
posY = uint( (XE_HILBERT_WIDTH - 1U) ) - posY;
|
|
}
|
|
|
|
uint temp = posX;
|
|
posX = posY;
|
|
posY = temp;
|
|
}
|
|
}
|
|
return index;
|
|
}
|
|
|
|
// Engine-specific screen & temporal noise loader
|
|
float2 SpatioTemporalNoise( uint2 pixCoord, uint temporalIndex ) // without TAA, temporalIndex is always 0
|
|
{
|
|
float2 noise;
|
|
#if 1 // Hilbert curve driving R2 (see https://www.shadertoy.com/view/3tB3z3)
|
|
#ifdef XE_GTAO_HILBERT_LUT_AVAILABLE // load from lookup texture...
|
|
uint index = g_srcHilbertLUT.Load( uint3( pixCoord % 64, 0 ) ).x;
|
|
#else // ...or generate in-place?
|
|
uint index = HilbertIndex( pixCoord.x, pixCoord.y );
|
|
#endif
|
|
index += 288*(temporalIndex%64); // why 288? tried out a few and that's the best so far (with XE_HILBERT_LEVEL 6U) - but there's probably better :)
|
|
// R2 sequence - see http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/
|
|
return float2( frac( 0.5 + index * float2(0.75487766624669276005, 0.5698402909980532659114) ) );
|
|
#else // Pseudo-random (fastest but looks bad - not a good choice)
|
|
uint baseHash = Hash32( pixCoord.x + (pixCoord.y << 15) );
|
|
baseHash = Hash32Combine( baseHash, temporalIndex );
|
|
return float2( Hash32ToFloat( baseHash ), Hash32ToFloat( Hash32( baseHash ) ) );
|
|
#endif
|
|
}
|
|
|
|
cbuffer DrawConstants : register(b0) {
|
|
float4x4 g_Projection;
|
|
float4x4 g_InverseProjection;
|
|
float3 g_LightDirView;
|
|
float g_NumSamples;
|
|
float g_SampleRange;
|
|
float g_Thickness;
|
|
uint g_FrameIndex;
|
|
}
|
|
|
|
uint2 NdcToPixel(in float2 size, in float4 ndc);
|
|
float2 NdcToUv(in float4 ndc);
|
|
float4 PixelToNdc(in float2 size, in uint2 pixel, in float depth);
|
|
float4 UvToNdc(in float2 uv, in float depth);
|
|
uint2 ViewToPixel(in float2 size, in float3 view);
|
|
float2 ViewToUv(in float3 view);
|
|
float GetPixelDepth(in float2 size, in uint2 pixel);
|
|
float GetUvDepth(in float2 uv);
|
|
float3 PixelToViewWithDepth(in float2 size, in uint2 pixel);
|
|
float3 UvToViewWithDepth(in float2 uv);
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void main(uint3 PixCoord : SV_DispatchThreadID) {
|
|
float2 size;
|
|
g_DepthTexture.GetDimensions(size.x, size.y);
|
|
uint2 pixel = PixCoord.xy;
|
|
|
|
float occlusion = 0;
|
|
g_Output[pixel] = 1.;
|
|
|
|
float2 noise = SpatioTemporalNoise(PixCoord.xy, g_FrameIndex);
|
|
float3 viewPosition = PixelToViewWithDepth(size, pixel);
|
|
float3 sample = viewPosition;
|
|
float3 step = g_LightDirView * g_SampleRange / g_NumSamples;
|
|
sample += noise.x * step;
|
|
for(int i = 0; i < g_NumSamples; ++i) {
|
|
sample += step;
|
|
float2 sample_uv = ViewToUv(sample);
|
|
if(all(and(sample_uv > 0, sample_uv < 1.))) {
|
|
float depthDelta = sample.z * .998 - GetUvDepth(sample_uv);
|
|
if(depthDelta < 0. && depthDelta > -g_Thickness) {
|
|
occlusion = 1.;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
g_Output[pixel] = 1. - occlusion;
|
|
}
|
|
|
|
uint2 NdcToPixel(in float2 size, in float4 ndc) {
|
|
return (uint2)floor(NdcToUv(ndc) * size);
|
|
}
|
|
|
|
float2 NdcToUv(in float4 ndc) {
|
|
return ndc.xy * float2(.5, -.5) + .5;
|
|
}
|
|
|
|
float4 PixelToNdc(in float2 size, in uint2 pixel, in float ndc_depth) {
|
|
return float4(float2(2., -2.) * ((((float2)pixel + .5) / size) - .5), ndc_depth, 1.);
|
|
}
|
|
|
|
float4 UvToNdc(in float2 uv, in float ndc_depth) {
|
|
return float4(float2(2., -2.) * (uv - .5), ndc_depth, 1.);
|
|
}
|
|
|
|
uint2 ViewToPixel(in float2 size, in float3 view) {
|
|
float4 ndc = mul(g_Projection, float4(view, 1.));
|
|
ndc /= ndc.w;
|
|
return NdcToPixel(size, ndc);
|
|
}
|
|
|
|
float2 ViewToUv(in float3 view) {
|
|
float4 ndc = mul(g_Projection, float4(view, 1.));
|
|
ndc /= ndc.w;
|
|
return NdcToUv(ndc);
|
|
}
|
|
|
|
float GetPixelDepth(in float2 size, in uint2 pixel) {
|
|
return PixelToViewWithDepth(size, pixel).z;
|
|
}
|
|
|
|
float GetUvDepth(in float2 uv) {
|
|
return UvToViewWithDepth(uv).z;
|
|
}
|
|
|
|
float3 PixelToViewWithDepth(in float2 size, in uint2 pixel) {
|
|
float4 ndc = PixelToNdc(size, pixel, g_DepthTexture[pixel]);
|
|
ndc = mul(g_InverseProjection, ndc);
|
|
return ndc.xyz / ndc.w;
|
|
}
|
|
|
|
float3 UvToViewWithDepth(in float2 uv) {
|
|
float4 ndc = UvToNdc(uv, g_DepthTexture.SampleLevel(g_SamplerLinearClamp, uv, 0.));
|
|
ndc = mul(g_InverseProjection, ndc);
|
|
return ndc.xyz / ndc.w;
|
|
}
|
|
|