Skip to content

Commit

Permalink
fix codestyle and add author of spartial reconstruction
Browse files Browse the repository at this point in the history
  • Loading branch information
LifeKILLED committed Dec 24, 2024
1 parent 86e39f0 commit bf0b9ae
Showing 1 changed file with 115 additions and 128 deletions.
243 changes: 115 additions & 128 deletions ref/vk/shaders/spartial_reconstruction.glsl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// originally implemented by Mikhail Gorobets for Diligent Engine
// https://github.com/DiligentGraphics/DiligentEngine

#ifndef SPARTIAL_RECONSTRUCTION_RADIUS
#define SPARTIAL_RECONSTRUCTION_RADIUS 7.
#endif
Expand Down Expand Up @@ -50,124 +53,109 @@ void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) {
shading_normal = normalDecode(n.zw);
}

struct PixelAreaStatistic
{
float Mean;
float Variance;
float WeightSum;
vec4 ColorSum;
struct PixelAreaStatistic {
float mean;
float variance;
float weightSum;
vec4 colorSum;
};

float ComputeGaussianWeight(float Distance)
{
return exp(-0.66 * Distance * Distance); // assuming Distance is normalized to 1
float computeGaussianWeight(float texelDistance) {
return exp(-0.66 * texelDistance * texelDistance); // assuming texelDistance is normalized to 1
}

// vec4 ComputeBlurKernelRotation(ivec2 pix, uint FrameIndex)
// {
// float Angle = Bayer4x4(pix, FrameIndex);
// return GetRotator(2.0 * PI * Angle);
// }

// Visibility = G2(v,l,a) / (4 * (n,v) * (n,l))
// see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf
float SmithGGXVisibilityCorrelated(float NdotL, float NdotV, float AlphaRoughness)
{
// G1 (masking) is % microfacets visible in 1 direction
// G2 (shadow-masking) is % microfacets visible in 2 directions
// If uncorrelated:
// G2(NdotL, NdotV) = G1(NdotL) * G1(NdotV)
// Less realistic as higher points are more likely visible to both L and V
//
// https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf

float a2 = AlphaRoughness * AlphaRoughness;

float GGXV = NdotL * sqrt(max(NdotV * NdotV * (1.0 - a2) + a2, 1e-7));
float GGXL = NdotV * sqrt(max(NdotL * NdotL * (1.0 - a2) + a2, 1e-7));

return 0.5 / (GGXV + GGXL);
float smithGGXVisibilityCorrelated(float NdotL, float NdotV, float alphaRoughness) {
// G1 (masking) is % microfacets visible in 1 direction
// G2 (shadow-masking) is % microfacets visible in 2 directions
// If uncorrelated:
// G2(NdotL, NdotV) = G1(NdotL) * G1(NdotV)
// Less realistic as higher points are more likely visible to both L and V
//
// https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf

float a2 = alphaRoughness * alphaRoughness;

float GGXV = NdotL * sqrt(max(NdotV * NdotV * (1.0 - a2) + a2, 1e-7));
float GGXL = NdotV * sqrt(max(NdotL * NdotL * (1.0 - a2) + a2, 1e-7));

return 0.5 / (GGXV + GGXL);
}

// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games, Equation 3.
float NormalDistribution_GGX(float NdotH, float AlphaRoughness)
{
// "Sampling the GGX Distribution of Visible Normals" (2018) by Eric Heitz - eq. (1)
// https://jcgt.org/published/0007/04/01/

// Make sure we reasonably handle AlphaRoughness == 0
// (which corresponds to delta function)
AlphaRoughness = max(AlphaRoughness, 1e-3);

float a2 = AlphaRoughness * AlphaRoughness;
float nh2 = NdotH * NdotH;
float f = nh2 * a2 + (1.0 - nh2);
return a2 / max(PI * f * f, 1e-9);
float normalDistribution_GGX(float NdotH, float alphaRoughness) {
// "Sampling the GGX Distribution of Visible Normals" (2018) by Eric Heitz - eq. (1)
// https://jcgt.org/published/0007/04/01/

// Make sure we reasonably handle alphaRoughness == 0
// (which corresponds to delta function)
alphaRoughness = max(alphaRoughness, 1e-3);

float a2 = alphaRoughness * alphaRoughness;
float nh2 = NdotH * NdotH;
float f = nh2 * a2 + (1.0 - nh2);
return a2 / max(PI * f * f, 1e-9);
}

vec2 ComputeWeightRayLength(ivec2 pix, vec3 V, vec3 N, float roughness, float NdotV, float Weight)
{
vec4 RayDirectionPDF = imageLoad(reflection_direction_pdf, pix);
float rayLength = length(RayDirectionPDF.xyz);
vec3 RayDirection = normalize(RayDirectionPDF.xyz);
float PDF = RayDirectionPDF.w;
float AlphaRoughness = roughness * roughness;

vec3 L = RayDirection;
vec3 H = normalize(L + V);

float NdotH = saturate(dot(N, H));
float NdotL = saturate(dot(N, L));

float Vis = SmithGGXVisibilityCorrelated(NdotL, NdotV, AlphaRoughness);
float D = NormalDistribution_GGX(NdotH, AlphaRoughness);
float LocalBRDF = Vis * D * NdotL;
LocalBRDF *= ComputeGaussianWeight(Weight);
float rcpRayLength = rayLength == 0. ? 0. : 1. / rayLength;
return vec2(max(LocalBRDF / max(PDF, 1.0e-5f), 1e-6), rcpRayLength);
vec2 computeWeightRayLength(ivec2 pix, vec3 V, vec3 N, float roughness, float NdotV, float weight) {
vec4 rayDirectionPDF = imageLoad(reflection_direction_pdf, pix);
float rayLength = length(rayDirectionPDF.xyz);
vec3 rayDirection = normalize(rayDirectionPDF.xyz);
float PDF = rayDirectionPDF.w;
float alphaRoughness = roughness * roughness;

vec3 L = rayDirection;
vec3 H = normalize(L + V);

float NdotH = saturate(dot(N, H));
float NdotL = saturate(dot(N, L));

float vis = smithGGXVisibilityCorrelated(NdotL, NdotV, alphaRoughness);
float D = normalDistribution_GGX(NdotH, alphaRoughness);
float localBRDF = vis * D * NdotL;
localBRDF *= computeGaussianWeight(weight);
float rcpRayLength = rayLength == 0. ? 0. : 1. / rayLength;
return vec2(max(localBRDF / max(PDF, 1.0e-5f), 1e-6), rcpRayLength);
}

// Weighted incremental variance
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
void ComputeWeightedVariance(inout PixelAreaStatistic Stat, vec3 SampleColor, float Weight)
{
Stat.ColorSum.xyz += Weight * SampleColor;
Stat.WeightSum += Weight;
void computeWeightedVariance(inout PixelAreaStatistic stat, vec3 sampleColor, float weight) {
stat.colorSum.xyz += weight * sampleColor;
stat.weightSum += weight;

float Value = luminance(SampleColor.rgb);
float PrevMean = Stat.Mean;
float value = luminance(sampleColor.rgb);
float prevMean = stat.mean;

float rcpWeightSum = Stat.WeightSum == 0. ? 0. : 1. / Stat.WeightSum;
float rcpWeightSum = stat.weightSum == 0. ? 0. : 1. / stat.weightSum;

Stat.Mean += Weight * rcpWeightSum * (Value - PrevMean);
Stat.Variance += Weight * (Value - PrevMean) * (Value - Stat.Mean);
stat.mean += weight * rcpWeightSum * (value - prevMean);
stat.variance += weight * (value - prevMean) * (value - stat.mean);
}

float ComputeResolvedDepth(vec3 origin, vec3 PositionWS, float SurfaceHitDistance)
{
return distance(origin, PositionWS) + SurfaceHitDistance;
float computeResolvedDepth(vec3 origin, vec3 position, float surfaceHitDistance) {
return distance(origin, position) + surfaceHitDistance;
}

ivec2 ClampScreenCoord(ivec2 pix, ivec2 res)\
{
ivec2 clampScreenCoord(ivec2 pix, ivec2 res) {
return max(ivec2(0), min(ivec2(res - 1), pix));
}


float ComputeSpatialWeight(float Distance, float Sigma)
{
return exp(-(Distance) / (2.0 * Sigma * Sigma));
float computeSpatialWeight(float texelDistance, float sigma) {
return exp(-(texelDistance) / (2.0 * sigma * sigma));
}

vec3 clampSpecular(vec3 specular, float maxLuminace) {
float lum = luminance(specular);
if (lum == 0.)
return vec3(0.);
float lum = luminance(specular);
if (lum == 0.)
return vec3(0.);

float clamped = min(maxLuminace, lum);
return specular * (clamped / lum);
float clamped = min(maxLuminace, lum);
return specular * (clamped / lum);
}

void main() {
Expand All @@ -178,73 +166,72 @@ void main() {
}

if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SPARTIAL_RECONSTRUCTION) == 0) {
imageStore(SPECULAR_OUTPUT_IMAGE, pix, imageLoad(SPECULAR_INPUT_IMAGE, pix));
return;
}
imageStore(SPECULAR_OUTPUT_IMAGE, pix, imageLoad(SPECULAR_INPUT_IMAGE, pix));
return;
}

const vec2 uv = (gl_GlobalInvocationID.xy + .5) / res * 2. - 1.;

const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz;
const vec3 position = imageLoad(position_t, pix * INDIRECT_SCALE).xyz;

// samples = 8, min distance = 0.5, average samples on radius = 2
vec3 Poisson[SPATIAL_RECONSTRUCTION_SAMPLES];
Poisson[0] = vec3(-0.4706069, -0.4427112, +0.6461146);
Poisson[1] = vec3(-0.9057375, +0.3003471, +0.9542373);
Poisson[2] = vec3(-0.3487388, +0.4037880, +0.5335386);
Poisson[3] = vec3(+0.1023042, +0.6439373, +0.6520134);
Poisson[4] = vec3(+0.5699277, +0.3513750, +0.6695386);
Poisson[5] = vec3(+0.2939128, -0.1131226, +0.3149309);
Poisson[6] = vec3(+0.7836658, -0.4208784, +0.8895339);
Poisson[7] = vec3(+0.1564120, -0.8198990, +0.8346850);
// samples = 8, min distance = 0.5, average samples on radius = 2
vec3 poisson[SPATIAL_RECONSTRUCTION_SAMPLES];
poisson[0] = vec3(-0.4706069, -0.4427112, +0.6461146);
poisson[1] = vec3(-0.9057375, +0.3003471, +0.9542373);
poisson[2] = vec3(-0.3487388, +0.4037880, +0.5335386);
poisson[3] = vec3(+0.1023042, +0.6439373, +0.6520134);
poisson[4] = vec3(+0.5699277, +0.3513750, +0.6695386);
poisson[5] = vec3(+0.2939128, -0.1131226, +0.3149309);
poisson[6] = vec3(+0.7836658, -0.4208784, +0.8895339);
poisson[7] = vec3(+0.1564120, -0.8198990, +0.8346850);

vec3 geometry_normal, shading_normal;
readNormals(pix * INDIRECT_SCALE, geometry_normal, shading_normal);

vec3 V = normalize(origin - position);
float NdotV = saturate(dot(shading_normal, V));
vec3 V = normalize(origin - position);
float NdotV = saturate(dot(shading_normal, V));

float roughness = imageLoad(material_rmxx, pix * INDIRECT_SCALE).x;
float roughness = imageLoad(material_rmxx, pix * INDIRECT_SCALE).x;

float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness);
float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor);
float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness);
float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor);

PixelAreaStatistic PixelAreaStat;
PixelAreaStat.ColorSum = vec4(0.0, 0.0, 0.0, 0.0);
PixelAreaStat.WeightSum = 0.0;
PixelAreaStat.Variance = 0.0;
PixelAreaStat.Mean = 0.0;
PixelAreaStatistic pixelAreaStat;
pixelAreaStat.colorSum = vec4(0.0, 0.0, 0.0, 0.0);
pixelAreaStat.weightSum = 0.0;
pixelAreaStat.variance = 0.0;
pixelAreaStat.mean = 0.0;

float NearestSurfaceHitDistance = 0.0;
float nearestSurfaceHitDistance = 0.0;

vec3 result_color = vec3(0.);
float weights_sum = 0.;

// TODO: Try to implement sampling from https://youtu.be/MyTOGHqyquU?t=1043
for (int SampleIdx = 0; SampleIdx < SPATIAL_RECONSTRUCTION_SAMPLES; SampleIdx++)
{
vec2 Xi = Poisson[SampleIdx].xy;
ivec2 SampleCoord = max(ivec2(0), min(ivec2(res) - ivec2(1), ivec2(pix + radius * Xi)));
// TODO: Try to implement sampling from https://youtu.be/MyTOGHqyquU?t=1043
for (int i = 0; i < SPATIAL_RECONSTRUCTION_SAMPLES; i++)
{
ivec2 p = max(ivec2(0), min(ivec2(res) - ivec2(1), ivec2(pix + radius * poisson[i].xy)));

float WeightS = ComputeSpatialWeight(Poisson[SampleIdx].z * Poisson[SampleIdx].z, SPATIAL_RECONSTRUCTION_SIGMA);
vec2 WeightLength = ComputeWeightRayLength(SampleCoord, V, shading_normal, roughness, NdotV, WeightS);
vec3 SampleColor = clampSpecular(imageLoad(SPECULAR_INPUT_IMAGE, SampleCoord).xyz, SPECULAR_CLAMPING_MAX);
ComputeWeightedVariance(PixelAreaStat, SampleColor, WeightLength.x);
float weightS = computeSpatialWeight(poisson[i].z * poisson[i].z, SPATIAL_RECONSTRUCTION_SIGMA);
vec2 weightLength = computeWeightRayLength(p, V, shading_normal, roughness, NdotV, weightS);
vec3 sampleColor = clampSpecular(imageLoad(SPECULAR_INPUT_IMAGE, p).xyz, SPECULAR_CLAMPING_MAX);
computeWeightedVariance(pixelAreaStat, sampleColor, weightLength.x);

if (WeightLength.x > 1.0e-6)
NearestSurfaceHitDistance = max(WeightLength.y, NearestSurfaceHitDistance);
if (weightLength.x > 1.0e-6)
nearestSurfaceHitDistance = max(weightLength.y, nearestSurfaceHitDistance);

result_color += SampleColor.xyz * WeightLength.x;
weights_sum += WeightLength.x;
}
result_color += sampleColor.xyz * weightLength.x;
weights_sum += weightLength.x;
}

if (weights_sum > 0.) {
result_color /= weights_sum;
}

vec4 ResolvedRadiance = PixelAreaStat.ColorSum / max(PixelAreaStat.WeightSum, 1e-6f);
float ResolvedVariance = PixelAreaStat.Variance / max(PixelAreaStat.WeightSum, 1e-6f);
float ResolvedDepth = ComputeResolvedDepth(origin, position, NearestSurfaceHitDistance);
vec4 resolvedRadiance = pixelAreaStat.colorSum / max(pixelAreaStat.weightSum, 1e-6f);
float resolvedVariance = pixelAreaStat.variance / max(pixelAreaStat.weightSum, 1e-6f);
float resolvedDepth = computeResolvedDepth(origin, position, nearestSurfaceHitDistance);

imageStore(SPECULAR_OUTPUT_IMAGE, pix, vec4(ResolvedRadiance.xyz, ResolvedVariance));
imageStore(SPECULAR_OUTPUT_IMAGE, pix, vec4(resolvedRadiance.xyz, resolvedVariance));
}

0 comments on commit bf0b9ae

Please sign in to comment.