Fixing depth mip generation

This commit is contained in:
Dynamitos
2024-06-17 16:21:41 +02:00
parent 0fd331b3b5
commit 7cdbb19331
5 changed files with 221 additions and 43 deletions
+12 -10
View File
@@ -11,6 +11,7 @@ groupshared float4x4 modelViewProjection;
struct DepthData
{
Texture2D<float> texture;
RWStructuredBuffer<float> buffer;
}
ParameterBlock<DepthData> pDepthAttachment;
@@ -21,7 +22,6 @@ void taskMain(
uint threadID: SV_GroupThreadID,
uint groupID: SV_GroupID, )
{
const uint mipLevels = uint(log2(max(pViewParams.screenDimensions.x, pViewParams.screenDimensions.y)));
if (threadID == 0)
{
head = 0;
@@ -57,8 +57,9 @@ void taskMain(
// if the meshlet is outside of the frustum, we skip it since we cant do depth culling anyways
if(meshlet.bounding.insideFrustum(viewFrustum))
{
uint2 mipDimensions = uint2((uint(pViewParams.screenDimensions.x) + BLOCK_SIZE - 1) / BLOCK_SIZE, (uint(pViewParams.screenDimensions.y) + BLOCK_SIZE - 1) / BLOCK_SIZE);
// now we calculate what mip level we need to only sample up to 4 texels covering the entire meshlet
uint2 screenCornerMin = uint2(uint(pViewParams.screenDimensions.x), uint(pViewParams.screenDimensions.y));
uint2 screenCornerMin = mipDimensions;
uint2 screenCornerMax = uint2(0, 0);
// we use reverse depth, so higher values are closer
float maxDepth = 0;
@@ -75,26 +76,27 @@ void taskMain(
for(uint i = 0; i < 8; ++i)
{
float4 clipCorner = mul(modelViewProjection, corners[i]);
float4 screenCorner = clipToScreen(clipCorner);
float4 screenCorner = clipToScreen(clipCorner) / BLOCK_SIZE;
screenCornerMin = uint2(min(screenCornerMin.x, uint(screenCorner.x)), min(screenCornerMin.y, uint(screenCorner.y)));
screenCornerMax = uint2(max(screenCornerMax.x, uint(screenCorner.x)), max(screenCornerMax.y, uint(screenCorner.y)));
maxDepth = max(maxDepth, screenCorner.z);
}
}
uint mipLevel = 0;
uint mipOffset = 0;
// in theory this wouldnt work if no corner was in screen, as min would be greater that max, however we verified that with view culling
while(screenCornerMax.x - screenCornerMin.x > 1 || screenCornerMax.y - screenCornerMin.y > 1)
{
mipLevel++;
mipOffset += mipDimensions.x * mipDimensions.y;
mipDimensions = uint2(mipDimensions.x + 1, mipDimensions.y + 1) / 2;
screenCornerMin /= 2;
screenCornerMax /= 2;
}
// now we sample 4 texels from the depth at the calculated mip level, this should give us the
float d1 = pDepthAttachment.texture.Load(int3(screenCornerMin.x, screenCornerMin.y, mipLevel)).r;
float d2 = pDepthAttachment.texture.Load(int3(screenCornerMin.x, screenCornerMax.y, mipLevel)).r;
float d3 = pDepthAttachment.texture.Load(int3(screenCornerMax.x, screenCornerMin.y, mipLevel)).r;
float d4 = pDepthAttachment.texture.Load(int3(screenCornerMax.x, screenCornerMax.y, mipLevel)).r;
// now we sample 4 texels from the depth at the calculated mip level, this should give us the screen extent of the meshlet
float d1 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMin.x];
float d2 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMax.x];
float d3 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMin.x];
float d4 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMax.x];
// we want to check if the minimum depth (the value farthest away) is smaller than the maximum bounding box depth
// otherwise, there is no way for the meshlet to be visible
+82
View File
@@ -0,0 +1,82 @@
import Common;
struct DepthData
{
Texture2D<float> texture;
RWStructuredBuffer<float> buffer;
}
ParameterBlock<DepthData> pDepthAttachment;
struct MipParam
{
uint srcMipOffset;
uint dstMipOffset;
uint2 srcMipDim;
uint2 dstMipDim;
}
layout(push_constants)
ConstantBuffer<MipParam> pMipParam;
float getSrcDepth(uint2 pos)
{
return pDepthAttachment.buffer[pMipParam.srcMipOffset + pos.x + (pos.y * pMipParam.srcMipDim.x)];
}
void setDstDepth(uint2 pos, float depth)
{
pDepthAttachment.buffer[pMipParam.dstMipOffset + pos.x + (pos.y * pMipParam.dstMipDim.x)] = depth;
}
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
[shader("compute")]
void reduceLevel(
uint3 threadID: SV_GroupThreadID,
uint3 groupID: SV_GroupID,
){
uint2 minCoords = (groupID.xy * BLOCK_SIZE + threadID.xy) * 2;
if(minCoords.x >= pMipParam.srcMipDim.x || minCoords.y >= pMipParam.srcMipDim.y)
{
return;
}
uint2 maxCoords = uint2(min(minCoords.x + 1, pMipParam.srcMipDim.x - 1), min(minCoords.y + 1, pMipParam.srcMipDim.y - 1));
float d0 = getSrcDepth(uint2(minCoords.x, minCoords.y));
float d1 = getSrcDepth(uint2(maxCoords.x, minCoords.y));
float d2 = getSrcDepth(uint2(minCoords.x, maxCoords.y));
float d3 = getSrcDepth(uint2(maxCoords.x, maxCoords.y));
float minDepth = min(min(d0, d1), min(d2, d3));
setDstDepth(minCoords / 2, minDepth);
}
groupshared uint uMinDepth;
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
[shader("compute")]
void initialReduce(
uint3 threadID: SV_GroupThreadID,
uint3 groupID: SV_GroupID,
) {
uint reducedWidth = uint(pViewParams.screenDimensions.x) / BLOCK_SIZE;
int2 groupOffset = groupID.xy * BLOCK_SIZE;
int2 texCoord = groupOffset + threadID.xy;
float fDepth = pDepthAttachment.texture.Load(int3(texCoord, 0)).r;
uint uDepth = asuint(fDepth);
if(groupID.x == 0 && groupID.y == 0)
{
uMinDepth = 0xffffffff;
}
GroupMemoryBarrierWithGroupSync();
InterlockedMin(uMinDepth, uDepth);
GroupMemoryBarrierWithGroupSync();
float fMinDepth = asfloat(uMinDepth);
if(threadID.x == 0 && threadID.y == 0)
{
pDepthAttachment.buffer[groupID.x + (groupID.y * reducedWidth)] = fMinDepth;
}
}
+3 -3
View File
@@ -89,18 +89,18 @@ void cullLights(ComputeShaderInput in)
float maxDepthWS = clipToWorld(float4(0, 0, fMaxDepth, 1)).z;
float nearClipWS = clipToWorld(float4(0, 0, 0, 1)).z;
Plane minPlane = {float3(0, 0, -1), -minDepthWS};
Plane maxPlane = {float3(0, 0, -1), -maxDepthWS};
for ( uint i = in.groupIndex; i < pLightEnv.numPointLights; i += BLOCK_SIZE * BLOCK_SIZE )
{
PointLight light = pLightEnv.pointLights[i];
#ifdef LIGHT_CULLING
if(light.insideFrustum(groupFrustum, light.getPosition(), nearClipWS, maxDepthWS))
if(light.insideFrustum(groupFrustum, light.getPosition(), nearClipWS, minDepthWS))
#endif
{
tAppendLight(i);
#ifdef LIGHT_CULLING
if(!light.insidePlane(minPlane, light.getPosition()))
if(!light.insidePlane(maxPlane, light.getPosition()))
#endif
{
oAppendLight(i);