bgfx/examples/43-denoise/fs_denoise_spatial_implementation.sh

98 lines
2.8 KiB
Bash
Raw Normal View History

add denoise example (#2344) /* * Implement SVGF style denoising as bgfx example. Goal is to explore various * options and parameters, not produce an optimized, efficient denoiser. * * Starts with deferred rendering scene with very basic lighting. Lighting is * masked out with a noise pattern to provide something to denoise. There are * two options for the noise pattern. One is a fixed 2x2 dither pattern to * stand-in for lighting at quarter resolution. The other is the common * shadertoy random pattern as a stand-in for some fancier lighting without * enough samples per pixel, like ray tracing. * * First a temporal denoising filter is applied. The temporal filter is only * using normals to reject previous samples. The SVGF paper also describes using * depth comparison to reject samples but that is not implemented here. * * Followed by some number of spatial filters. These are implemented like in the * SVGF paper. As an alternative to the 5x5 Edge-Avoiding A-Trous filter, can * select a 3x3 filter instead. The 3x3 filter takes fewer samples and covers a * smaller area, but takes less time to compute. From a loosely eyeballed * comparison, N 5x5 passes looks similar to N+1 3x3 passes. The wider spatial * filters take a fair chunk of time to compute. I wonder if it would be a good * idea to interleave the input texture before computing, after the first pass * which skips zero pixels. * * I have not implemetened the variance guided part. * * There's also an optional TXAA pass to be applied after. I am not happy with * its implementation yet, so it defaults to off here. */ /* * References: * Spatiotemporal Variance-Guided Filtering: Real-Time Reconstruction for * Path-Traced Global Illumination. by Christoph Schied and more. * - SVGF denoising algorithm * * Streaming G-Buffer Compression for Multi-Sample Anti-Aliasing. * by E. Kerzner and M. Salvi. * - details about history comparison for temporal denoising filter * * Edge-Avoiding À-Trous Wavelet Transform for Fast Global Illumination * Filtering. by Holger Dammertz and more. * - details about a-trous algorithm for spatial denoising filter */
2021-01-02 21:42:02 +03:00
/*
* Copyright 2021 elven cache. All rights reserved.
2022-01-15 22:59:06 +03:00
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
add denoise example (#2344) /* * Implement SVGF style denoising as bgfx example. Goal is to explore various * options and parameters, not produce an optimized, efficient denoiser. * * Starts with deferred rendering scene with very basic lighting. Lighting is * masked out with a noise pattern to provide something to denoise. There are * two options for the noise pattern. One is a fixed 2x2 dither pattern to * stand-in for lighting at quarter resolution. The other is the common * shadertoy random pattern as a stand-in for some fancier lighting without * enough samples per pixel, like ray tracing. * * First a temporal denoising filter is applied. The temporal filter is only * using normals to reject previous samples. The SVGF paper also describes using * depth comparison to reject samples but that is not implemented here. * * Followed by some number of spatial filters. These are implemented like in the * SVGF paper. As an alternative to the 5x5 Edge-Avoiding A-Trous filter, can * select a 3x3 filter instead. The 3x3 filter takes fewer samples and covers a * smaller area, but takes less time to compute. From a loosely eyeballed * comparison, N 5x5 passes looks similar to N+1 3x3 passes. The wider spatial * filters take a fair chunk of time to compute. I wonder if it would be a good * idea to interleave the input texture before computing, after the first pass * which skips zero pixels. * * I have not implemetened the variance guided part. * * There's also an optional TXAA pass to be applied after. I am not happy with * its implementation yet, so it defaults to off here. */ /* * References: * Spatiotemporal Variance-Guided Filtering: Real-Time Reconstruction for * Path-Traced Global Illumination. by Christoph Schied and more. * - SVGF denoising algorithm * * Streaming G-Buffer Compression for Multi-Sample Anti-Aliasing. * by E. Kerzner and M. Salvi. * - details about history comparison for temporal denoising filter * * Edge-Avoiding À-Trous Wavelet Transform for Fast Global Illumination * Filtering. by Holger Dammertz and more. * - details about a-trous algorithm for spatial denoising filter */
2021-01-02 21:42:02 +03:00
*/
#ifndef FS_DENOISE_SPATIAL_IMPLEMENTATION_SH
#define FS_DENOISE_SPATIAL_IMPLEMENTATION_SH
#include "../common/common.sh"
#include "parameters.sh"
#include "normal_encoding.sh"
SAMPLER2D(s_color, 0); // input color, signal to be denoised
SAMPLER2D(s_normal, 1); // scene's gbuffer normal, used for edge stopping function
SAMPLER2D(s_depth, 2); // scene's depth, used for edge stopping function
void main()
{
vec2 texCoord = v_texcoord0;
// read center pixel
vec4 color = texture2D(s_color, texCoord);
vec3 normal = NormalDecode(texture2D(s_normal, texCoord).xyz); // * 2.0 - 1.0;
float depth = texture2D(s_depth, texCoord).x;
// want depth gradient for edge stopping function
float depthGradient = abs(dFdx(depth)) + abs(dFdy(depth));
float du = u_texCoordStep * u_viewTexel.x;
float dv = u_texCoordStep * u_viewTexel.y;
#if USE_SPATIAL_5X5
float gaussianWeights[5];
gaussianWeights[0] = 1.0/16.0;
gaussianWeights[1] = 4.0/16.0;
gaussianWeights[2] = 6.0/16.0;
gaussianWeights[3] = 4.0/16.0;
gaussianWeights[4] = 1.0/16.0;
float initialWeight = (gaussianWeights[2]*gaussianWeights[2]);
int centerIdx = 2;
vec4 accumulateColor = color * initialWeight;
float accumulateWeight = initialWeight;
for (int yy = 0; yy < 5; ++yy)
{
for (int xx = 0; xx < 5; ++xx)
{
#else
float gaussianWeights[3];
gaussianWeights[0] = 1.0/4.0;
gaussianWeights[1] = 2.0/4.0;
gaussianWeights[2] = 1.0/4.0;
float initialWeight = (gaussianWeights[1]*gaussianWeights[1]);
int centerIdx = 1;
vec4 accumulateColor = color * initialWeight;
float accumulateWeight = initialWeight;
for (int yy = 0; yy < 3; ++yy)
{
for (int xx = 0; xx < 3; ++xx)
{
#endif // USE_SPATIAL_5X5
if ((centerIdx == xx) && (centerIdx == yy)) {
continue;
}
float xOffset = float(xx) - float(centerIdx);
float yOffset = float(yy) - float(centerIdx);
vec2 sampleTexCoord = texCoord;
sampleTexCoord.x += xOffset * du;
sampleTexCoord.y += yOffset * dv;
vec4 sampleColor = texture2D(s_color, sampleTexCoord);
vec3 sampleNormal = NormalDecode(texture2D(s_normal, sampleTexCoord).xyz);
float normalWeight = pow(saturate(dot(normal, sampleNormal)), u_sigmaNormal);
float sampleDepth = texture2D(s_depth, sampleTexCoord).x;
float depthDelta = depth - sampleDepth;
float depthWeight = exp(-abs(depthDelta) / max(1e-5, u_sigmaDepth*u_sigmaDepth));
float weight = depthWeight * normalWeight;
// apply gaussian
weight *= (gaussianWeights[xx]*gaussianWeights[yy]);
accumulateColor += sampleColor * weight;
accumulateWeight += weight;
}
}
accumulateColor /= max(accumulateWeight, 1e-5);
gl_FragColor = accumulateColor;
}
#endif // FS_DENOISE_SPATIAL_IMPLEMENTATION_SH