cnq3/code/renderer/shaders/crp/dl_denoising.hlsl

105 lines
3.0 KiB
HLSL

/*
===========================================================================
Copyright (C) 2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3).
Challenge Quake 3 is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Challenge Quake 3 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
===========================================================================
*/
// denoising direct lighting from dynamic lights
#include "common.hlsli"
#include "fullscreen.hlsli"
#include "scene_view.h.hlsli"
cbuffer RootConstants
{
float3 lightPosition;
uint textureIndex;
uint vshadowTextureIndex;
uint vshadowSamplerIndex;
float vshadowWorldScale;
};
float4 ps(VOut input) : SV_Target
{
SceneView scene = GetSceneView();
Texture2D shadingPositionTexture = ResourceDescriptorHeap[scene.shadingPositionTextureIndex];
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
Texture3D<float> vshadowTexture = ResourceDescriptorHeap[vshadowTextureIndex];
SamplerState vshadowSampler = SamplerDescriptorHeap[vshadowSamplerIndex];
int2 textureMax = GetTextureSize(texture0) - int2(1, 1);
int2 tcFrag = int2(input.position.xy);
float3 positionFrag = shadingPositionTexture.Load(uint3(tcFrag, 0)).xyz;
float distThreshold = 8.0;
float maxError = 0.0;
for(int y = -4; y <= 4; y++)
{
for(int x = -4; x <= 4; x++)
{
int2 tc = tcFrag + int2(x, y);
if(!IsInRange(tcFrag, int2(0, 0), textureMax))
{
continue;
}
uint3 tc3 = uint3(tc, 0);
float errorFrag = texture0.Load(tc3).w;
maxError = max(maxError, errorFrag);
}
}
maxError = saturate(maxError);
float3 accum = float3(0, 0, 0);
float weightSum = 0.0;
int blurRadius = 1 + int(maxError * 8.0);
for(int y = -blurRadius; y <= blurRadius; y++)
{
for(int x = -blurRadius; x <= blurRadius; x++)
{
int2 tc = tcFrag + int2(x, y);
if(!IsInRange(tcFrag, int2(0, 0), textureMax))
{
continue;
}
uint3 tc3 = uint3(tc, 0);
float3 positionSample = shadingPositionTexture.Load(tc3).xyz;
float3 colorSample = texture0.Load(tc3).rgb;
float posWeight = 1.0 - saturate(distance(positionSample, positionFrag) / distThreshold);
float weight = posWeight;
accum += colorSample * posWeight;
weightSum += weight;
}
}
if(weightSum > 0.0)
{
accum /= weightSum;
}
float3 vshadowTC = AABoxWorldSpaceToTC(positionFrag, lightPosition, GetTextureSize(vshadowTexture), vshadowWorldScale);
float transmittance = vshadowTexture.SampleLevel(vshadowSampler, vshadowTC, 0);
accum *= transmittance;
float4 result = float4(accum, 0);
return result;
}