/* =========================================================================== 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 . =========================================================================== */ // 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 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; }