mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 09:33:51 +00:00
58 lines
2.4 KiB
Text
58 lines
2.4 KiB
Text
|
|
#version 450
|
|||
|
|
|
|||
|
|
// Hierarchical-Z depth pyramid builder.
|
|||
|
|
// Builds successive mip levels from the scene depth buffer.
|
|||
|
|
// Each 2×2 block is reduced to its MAXIMUM depth (farthest/largest value).
|
|||
|
|
// This is conservative for occlusion: an object is only culled when its nearest
|
|||
|
|
// depth exceeds the farthest occluder depth in the pyramid region.
|
|||
|
|
//
|
|||
|
|
// Two modes controlled by push constant:
|
|||
|
|
// mipLevel == 0: Sample from the source depth texture (mip 0 of the full-res depth).
|
|||
|
|
// mipLevel > 0: Sample from the previous HiZ mip level.
|
|||
|
|
|
|||
|
|
layout(local_size_x = 8, local_size_y = 8) in;
|
|||
|
|
|
|||
|
|
// Source depth texture (full-resolution scene depth, or previous mip via same image)
|
|||
|
|
layout(set = 0, binding = 0) uniform sampler2D srcDepth;
|
|||
|
|
|
|||
|
|
// Destination mip level (written as storage image)
|
|||
|
|
layout(r32f, set = 0, binding = 1) uniform writeonly image2D dstMip;
|
|||
|
|
|
|||
|
|
layout(push_constant) uniform PushConstants {
|
|||
|
|
ivec2 dstSize; // Width and height of the destination mip level
|
|||
|
|
int mipLevel; // Current mip level being built (0 = from scene depth)
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void main() {
|
|||
|
|
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
|
|||
|
|
if (pos.x >= dstSize.x || pos.y >= dstSize.y) return;
|
|||
|
|
|
|||
|
|
// Each output texel covers a 2×2 block of the source.
|
|||
|
|
// Use texelFetch for precise texel access (no filtering).
|
|||
|
|
ivec2 srcPos = pos * 2;
|
|||
|
|
|
|||
|
|
float d00, d10, d01, d11;
|
|||
|
|
|
|||
|
|
if (mipLevel == 0) {
|
|||
|
|
// Sample from full-res scene depth (sampler2D, lod 0)
|
|||
|
|
d00 = texelFetch(srcDepth, srcPos + ivec2(0, 0), 0).r;
|
|||
|
|
d10 = texelFetch(srcDepth, srcPos + ivec2(1, 0), 0).r;
|
|||
|
|
d01 = texelFetch(srcDepth, srcPos + ivec2(0, 1), 0).r;
|
|||
|
|
d11 = texelFetch(srcDepth, srcPos + ivec2(1, 1), 0).r;
|
|||
|
|
} else {
|
|||
|
|
// Sample from previous HiZ mip level (mipLevel - 1)
|
|||
|
|
d00 = texelFetch(srcDepth, srcPos + ivec2(0, 0), mipLevel - 1).r;
|
|||
|
|
d10 = texelFetch(srcDepth, srcPos + ivec2(1, 0), mipLevel - 1).r;
|
|||
|
|
d01 = texelFetch(srcDepth, srcPos + ivec2(0, 1), mipLevel - 1).r;
|
|||
|
|
d11 = texelFetch(srcDepth, srcPos + ivec2(1, 1), mipLevel - 1).r;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Conservative maximum (standard depth buffer: 0=near, 1=far).
|
|||
|
|
// We store the farthest (largest) depth in each 2×2 block.
|
|||
|
|
// An object is occluded only when its nearest depth > the farthest occluder
|
|||
|
|
// depth in the covered screen region — guaranteeing it's behind EVERYTHING.
|
|||
|
|
float maxDepth = max(max(d00, d10), max(d01, d11));
|
|||
|
|
|
|||
|
|
imageStore(dstMip, pos, vec4(maxDepth));
|
|||
|
|
}
|