Skip to content

Commit

Permalink
Merge vsm-upgrades and fixed some buggies
Browse files Browse the repository at this point in the history
  • Loading branch information
JuanDiegoMontoya committed Jun 29, 2024
2 parents 5b43673 + 439be52 commit 2926cfd
Show file tree
Hide file tree
Showing 25 changed files with 603 additions and 89 deletions.
18 changes: 17 additions & 1 deletion data/shaders/Config.shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@
#define DEPTH_ZERO_TO_ONE 1
#define REVERSE_Z 1

// Adds a depth buffer that is cleared before each VSM clipmap is drawn and forces early fragment tests.
// Reduces overdraw and improves perf in certain situations.
#define VSM_USE_TEMP_ZBUFFER 0

// If true, VSM will properly support alpha masked geometry (e.g. foliage) that requires sampling and discarding.
// WARNING: because the above option enables early fragment tests, rendering will be incorrect if used with it.
#define VSM_SUPPORT_ALPHA_MASKED_GEOMETRY 1

// When enabled VsmShadow.frag will increment a per-texel overdraw counter.
// This allows for overdraw debug visualizations at the expense of some perf.
#define VSM_RENDER_OVERDRAW 1

// When VSM_RENDER_OVERDRAW is enabled, clamp the colormap to this amount of overdraw.
// This number should be a float.
#define VSM_MAX_OVERDRAW 32.0f

#if REVERSE_Z
#define NEAR_DEPTH 1.0f
#define FAR_DEPTH 0.0f
Expand All @@ -25,4 +41,4 @@
#endif
#endif

#endif // CONFIG_SHARED_H
#endif // CONFIG_SHARED_H
29 changes: 29 additions & 0 deletions data/shaders/Math.h.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,33 @@ float ComputeHashedAlphaThreshold(vec3 objectSpacePos, float maxObjSpaceDerivLen
return clamp(threshold, 1e-6, 1.0);
}

// Copyright 2019 Google LLC.
// SPDX-License-Identifier: Apache-2.0

// Polynomial approximation in GLSL for the Turbo colormap
// Original LUT: https://gist.github.com/mikhailov-work/ee72ba4191942acecc03fe6da94fc73f

// Authors:
// Colormap Design: Anton Mikhailov ([email protected])
// GLSL Approximation: Ruofei Du ([email protected])

vec3 TurboColormap(float x)
{
const vec4 kRedVec4 = vec4(0.13572138, 4.61539260, -42.66032258, 132.13108234);
const vec4 kGreenVec4 = vec4(0.09140261, 2.19418839, 4.84296658, -14.18503333);
const vec4 kBlueVec4 = vec4(0.10667330, 12.64194608, -60.58204836, 110.36276771);
const vec2 kRedVec2 = vec2(-152.94239396, 59.28637943);
const vec2 kGreenVec2 = vec2(4.27729857, 2.82956604);
const vec2 kBlueVec2 = vec2(-89.90310912, 27.34824973);

x = clamp(x, 0, 1);
vec4 v4 = vec4( 1.0, x, x * x, x * x * x);
vec2 v2 = v4.zw * v4.z;
return vec3(
dot(v4, kRedVec4) + dot(v2, kRedVec2),
dot(v4, kGreenVec4) + dot(v2, kGreenVec2),
dot(v4, kBlueVec4) + dot(v2, kBlueVec2)
);
}

#endif // MATH_H
3 changes: 3 additions & 0 deletions data/shaders/Resources.h.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@

#define Fvog_sampler2D(textureIndex, samplerIndex) \
NonUniformIndex(sampler2D(FvogGetSampledImage(texture2D, textureIndex), FvogGetSampler(samplerIndex)))

#define Fvog_usampler2D(textureIndex, samplerIndex) \
NonUniformIndex(usampler2D(FvogGetSampledImage(utexture2D, textureIndex), FvogGetSampler(samplerIndex)))

#define Fvog_usampler2DArray(textureIndex, samplerIndex) \
NonUniformIndex(usampler2DArray(FvogGetSampledImage(utexture2DArray, textureIndex), FvogGetSampler(samplerIndex)))
Expand Down
25 changes: 21 additions & 4 deletions data/shaders/ShadeDeferredPbr.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ layout(location = 0) out vec3 o_color;
#define VSM_SHOW_SHADOW_DEPTH (1 << 3)
#define VSM_SHOW_DIRTY_PAGES (1 << 4)
#define BLEND_NORMALS (1 << 5)
#define VSM_SHOW_OVERDRAW (1 << 6)

//layout(binding = 1, std140) uniform ShadingUniforms
FVOG_DECLARE_STORAGE_BUFFERS(restrict readonly ShadingUniforms)
Expand Down Expand Up @@ -106,6 +107,7 @@ struct ShadowVsmOut
float shadowDepth;
float projectedDepth;
uint clipmapLevel;
uint overdraw;
};

ShadowVsmOut ShadowVsm(vec3 fragWorldPos, vec3 normal)
Expand All @@ -115,6 +117,7 @@ ShadowVsmOut ShadowVsm(vec3 fragWorldPos, vec3 normal)
ret.vsmUv = vec2(0);
ret.shadowDepth = 0;
ret.projectedDepth = 0;
ret.overdraw = 0;

const ivec2 gid = ivec2(gl_FragCoord.xy);
const float depthSample = texelFetch(FvogGetSampledImage(texture2D, gDepthIndex), gid, 0).x;
Expand All @@ -135,6 +138,10 @@ ShadowVsmOut ShadowVsm(vec3 fragWorldPos, vec3 normal)
const uint physicalAddress = GetPagePhysicalAddress(ret.pageData);
ret.shadowDepth = LoadPageTexel(pageTexel, physicalAddress);

#if VSM_RENDER_OVERDRAW
ret.overdraw = imageLoad(i_physicalPagesOverdrawHeatmap, GetPhysicalTexelAddress(pageTexel, physicalAddress)).x;
#endif

const float maxBias = exp2(ret.clipmapLevel) * 0.1;
const float bias = min(maxBias, 0.01 + CalcVsmShadowBias(addr.clipmapLevel, normal)) / clipmapUniforms.projectionZLength;

Expand Down Expand Up @@ -346,9 +353,11 @@ void main()




// ShadowVsm is only used for debugging
ShadowVsmOut shadowVsm = ShadowVsm(fragWorldPos, flatNormal);
float shadowSun = shadowVsm.shadow;

// Filtered shadow
shadowSun = ShadowVsmPcss(fragWorldPos, flatNormal);


Expand Down Expand Up @@ -410,10 +419,18 @@ void main()
// UV + shadow map depth view
if ((shadingUniforms.debugFlags & VSM_SHOW_SHADOW_DEPTH) != 0)
{
if (GetIsPageVisible(shadowVsm.pageData))
if (GetIsPageVisible(shadowVsm.pageData) && GetIsPageBacked(shadowVsm.pageData))
{
o_color.rgb += 3.0 * shadowVsm.shadowDepth.rrr;
}
}

// Overdraw heatmap
if ((shadingUniforms.debugFlags & VSM_SHOW_OVERDRAW) != 0)
{
if (shadowVsm.overdraw > 0 && GetIsPageVisible(shadowVsm.pageData) && GetIsPageBacked(shadowVsm.pageData))
{
if (GetIsPageBacked(shadowVsm.pageData))
o_color.rgb += 3.0 * shadowVsm.shadowDepth.rrr;
o_color.rgb += 3.0 * TurboColormap(shadowVsm.overdraw / VSM_MAX_OVERDRAW);
}
}

Expand Down
2 changes: 2 additions & 0 deletions data/shaders/ShadeDeferredPbr.h.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ FVOG_DECLARE_ARGUMENTS(ShadingPushConstants)
FVOG_UINT32 dirtyPageListBufferIndex;
FVOG_UINT32 clipmapUniformsBufferIndex;
FVOG_UINT32 nearestSamplerIndex;

FVOG_UINT32 physicalPagesOverdrawIndex;
};

#endif // SHADE_DEFERRED_PBR_H
27 changes: 27 additions & 0 deletions data/shaders/debug/viewer/VsmOverdrawHeatmap.frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#version 460 core

#include "../../Config.shared.h"
#include "../../Math.h.glsl"
#include "../../Resources.h.glsl"

FVOG_DECLARE_ARGUMENTS(ViewerUniforms)
{
uint textureIndex;
uint samplerIndex;
int texLayer;
int texLevel;
}pc;

FVOG_DECLARE_SAMPLERS;
FVOG_DECLARE_SAMPLED_IMAGES(utexture2D);

layout(location = 0) in vec2 v_uv;

layout(location = 0) out vec4 o_color;

void main()
{
const uint overdraw = textureLod(Fvog_usampler2D(pc.textureIndex, pc.samplerIndex), v_uv, pc.texLevel).x;

o_color = vec4(vec3(TurboColormap(overdraw / VSM_MAX_OVERDRAW)), 1);
}
2 changes: 2 additions & 0 deletions data/shaders/shadows/ShadowMain.vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

layout(location = 0) out vec2 v_uv;
layout(location = 1) out uint v_materialId;
layout(location = 2) out vec3 i_objectSpacePos;

void main()
{
Expand All @@ -26,5 +27,6 @@ void main()

v_materialId = meshletInstance.materialId;
v_uv = PackedToVec2(vertex.uv);
i_objectSpacePos = position;
gl_Position = d_currentView.viewProj * transform * vec4(position, 1.0);
}
103 changes: 95 additions & 8 deletions data/shaders/shadows/vsm/VsmCommon.h.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ FVOG_DECLARE_ARGUMENTS(VsmPushConstants)
FVOG_UINT32 allocRequestsIndex;
FVOG_UINT32 visiblePagesBitmaskIndex;
FVOG_UINT32 physicalPagesUintIndex;

FVOG_UINT32 physicalPagesOverdrawIndex;
};
#endif

Expand All @@ -65,9 +67,11 @@ FVOG_DECLARE_ARGUMENTS(VsmPushConstants)
//FVOG_DECLARE_STORAGE_IMAGES(uimage2DArray);
layout(set = 0, binding = FVOG_STORAGE_IMAGE_BINDING, r32ui) uniform uimage2DArray pageTablesImages[];
layout(set = 0, binding = FVOG_STORAGE_IMAGE_BINDING, r32f) uniform image2D physicalPagesImages[];
layout(set = 0, binding = FVOG_STORAGE_IMAGE_BINDING, r32ui) uniform restrict uimage2D physicalPagesOverdrawHeatmapImages[];
FVOG_DECLARE_SAMPLED_IMAGES(utexture2DArray);
FVOG_DECLARE_SAMPLERS;

#define i_physicalPagesOverdrawHeatmap physicalPagesOverdrawHeatmapImages[physicalPagesOverdrawIndex]
#define i_pageTables pageTablesImages[pageTablesIndex]
#define i_physicalPages physicalPagesImages[physicalPagesIndex]
#define s_vsmBitmaskHzb Fvog_usampler2DArray(vsmBitmaskHzbIndex, nearestSamplerIndex)
Expand Down Expand Up @@ -159,18 +163,21 @@ bool TryPushPageClear(uint pageIndex)
return true;
}

float LoadPageTexel(ivec2 texel, uint page)
ivec2 GetPhysicalTexelAddress(ivec2 texel, uint page)
{
const int atlasWidth = imageSize(i_physicalPages).x / PAGE_SIZE;
const ivec2 pageCorner = PAGE_SIZE * ivec2(page / atlasWidth, page % atlasWidth);
return imageLoad(i_physicalPages, pageCorner + texel).x;
return pageCorner + texel;
}

float LoadPageTexel(ivec2 texel, uint page)
{
return imageLoad(i_physicalPages, GetPhysicalTexelAddress(texel, page)).x;
}

void StorePageTexel(ivec2 texel, uint page, float value)
{
const int atlasWidth = imageSize(i_physicalPages).x / PAGE_SIZE;
const ivec2 pageCorner = PAGE_SIZE * ivec2(page / atlasWidth, page % atlasWidth);
imageStore(i_physicalPages, pageCorner + texel, vec4(value, 0, 0, 0));
imageStore(i_physicalPages, GetPhysicalTexelAddress(texel, page), vec4(value, 0, 0, 0));
}

bool SampleVsmBitmaskHzb(uint vsmIndex, vec2 uv, int level)
Expand Down Expand Up @@ -219,9 +226,7 @@ struct PageAddressInfo
vec3 posLightNdc;
};

// Analyzes the provided depth buffer and returns and address and data of a page.
// Works for clipmaps only.
PageAddressInfo GetClipmapPageFromDepth(float depth, ivec2 gid, ivec2 depthBufferSize)
PageAddressInfo GetClipmapPageFromDepth1(float depth, ivec2 gid, ivec2 depthBufferSize)
{
const vec2 texel = 1.0 / depthBufferSize;
const vec2 uvCenter = (vec2(gid) + 0.5) * texel;
Expand Down Expand Up @@ -260,5 +265,87 @@ PageAddressInfo GetClipmapPageFromDepth(float depth, ivec2 gid, ivec2 depthBuffe
return addr;
}

PageAddressInfo GetClipmapPageFromDepth2(float depth, ivec2 gid, ivec2 depthBufferSize)
{
const vec2 texel = 1.0 / depthBufferSize;
const vec2 uvCenter = (vec2(gid) + 0.5) * texel;

const vec3 posW = UnprojectUV_ZO(depth, uvCenter, perFrameUniforms.invViewProj);
const float dist = distance(posW, perFrameUniforms.cameraPos.xyz);

// Assume each clipmap is 2x the side length of the previous. Additional bias of 2.5 is arbitrary
const ivec2 tableSize = imageSize(i_pageTables).xy;
const float firstClipmapWidth = tableSize.x * PAGE_SIZE * clipmapUniforms.firstClipmapTexelLength;
const uint clipmapLevel = clamp(uint(ceil(2.5 + vsmUniforms.lodBias + log2(2.0 * dist / firstClipmapWidth))), 0, clipmapUniforms.numClipmaps - 1);
const uint clipmapIndex = clipmapUniforms.clipmapTableIndices[clipmapLevel];

const vec4 posLightC = clipmapUniforms.clipmapViewProjections[clipmapLevel] * vec4(posW, 1.0);
const vec3 posLightNdc = posLightC.xyz / posLightC.w;
const vec2 posLightUv = fract(posLightNdc.xy * 0.5 + 0.5);

const ivec2 posLightTexel = ivec2(posLightUv * imageSize(i_pageTables).xy);
const ivec3 pageAddress = ivec3(posLightTexel, clipmapIndex);

PageAddressInfo addr;
addr.pageAddress = pageAddress;
// Tile UV across VSM
addr.pageUv = tableSize * mod(posLightUv, 1.0 / tableSize);
addr.projectedDepth = posLightC.z / posLightC.w;
addr.clipmapLevel = clipmapLevel;
addr.vsmUv = posLightUv;
addr.posLightNdc = posLightNdc;

return addr;
}

PageAddressInfo GetClipmapPageFromDepth3(float depth, ivec2 gid, ivec2 depthBufferSize)
{
const vec2 texel = 1.0 / depthBufferSize;
const vec2 uvCenter = (vec2(gid) + 0.5) * texel;
const vec2 uvCenter2 = vec2(0);
// Unproject arbitrary, but opposing sides of the pixel (assume square) to compute side length
const vec2 uvLeft = uvCenter2 + vec2(-texel.x, 0) * 0.5;
const vec2 uvRight = uvCenter2 + vec2(texel.x, 0) * 0.5;

const mat4 invProj = perFrameUniforms.invProj;
const vec3 leftV = UnprojectUV_ZO(depth, uvLeft, invProj);
const vec3 rightV = UnprojectUV_ZO(depth, uvRight, invProj);

const float projLength = distance(leftV, rightV);

// Assume each clipmap is 2x the side length of the previous
precise const uint clipmapLevel = clamp(uint(ceil(vsmUniforms.lodBias + log2(projLength / clipmapUniforms.firstClipmapTexelLength))), 0, clipmapUniforms.numClipmaps - 1);
const uint clipmapIndex = clipmapUniforms.clipmapTableIndices[clipmapLevel];

const vec3 posW = UnprojectUV_ZO(depth, uvCenter, perFrameUniforms.invViewProj);
const vec4 posLightC = clipmapUniforms.clipmapViewProjections[clipmapLevel] * vec4(posW, 1.0);
const vec3 posLightNdc = posLightC.xyz / posLightC.w;
const vec2 posLightUv = fract(posLightNdc.xy * 0.5 + 0.5);

const ivec2 posLightTexel = ivec2(posLightUv * imageSize(i_pageTables).xy);
const ivec3 pageAddress = ivec3(posLightTexel, clipmapIndex);

PageAddressInfo addr;
addr.pageAddress = pageAddress;
// Tile UV across VSM
const ivec2 tableSize = imageSize(i_pageTables).xy;
addr.pageUv = tableSize * mod(posLightUv, 1.0 / tableSize);
addr.projectedDepth = posLightC.z / posLightC.w;
addr.clipmapLevel = clipmapLevel;
addr.vsmUv = posLightUv;
addr.posLightNdc = posLightNdc;

return addr;
}

// Analyzes the provided depth buffer and returns and address and data of a page.
// Works for clipmaps only.
PageAddressInfo GetClipmapPageFromDepth(float depth, ivec2 gid, ivec2 depthBufferSize)
{
return GetClipmapPageFromDepth1(depth, gid, depthBufferSize);
//return GetClipmapPageFromDepth2(depth, gid, depthBufferSize);
//return GetClipmapPageFromDepth3(depth, gid, depthBufferSize);
}

#endif // __cplusplus
#endif // VSM_COMMON_H
28 changes: 28 additions & 0 deletions data/shaders/shadows/vsm/VsmInitStencil.frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#version 460 core
#extension GL_GOOGLE_include_directive : enable

#include "../../Config.shared.h"
#include "VsmCommon.h.glsl"

layout(binding = 1, r32ui) uniform restrict uimage2D i_physicalPagesUint;

layout(binding = 1, std140) uniform VsmShadowUniforms
{
uint clipmapLod;
};

layout(location = 0) in vec2 v_uv;

void main()
{
const uint clipmapIndex = clipmapUniforms.clipmapTableIndices[clipmapLod];
const ivec2 pageOffset = clipmapUniforms.clipmapPageOffsets[clipmapLod];
const ivec2 pageAddressXy = ivec2(mod(vec2(ivec2(gl_FragCoord.xy) / PAGE_SIZE + pageOffset), vec2(imageSize(i_pageTables).xy)));
const uint pageData = imageLoad(i_pageTables, ivec3(pageAddressXy, clipmapIndex)).x;
const bool pageIsActive = GetIsPageBacked(pageData) && GetIsPageDirty(pageData);

if (!pageIsActive) // write stencil ref to active pages only
{
discard;
}
}
Loading

0 comments on commit 2926cfd

Please sign in to comment.