Shader "Hidden/HizCull" { SubShader { ZTest Off ZWrite Off Pass { HLSLPROGRAM #pragma vertex Vertex #pragma fragment CullFrag #pragma enable_d3d11_debug_symbols #pragma target 5.0 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 texcoord : TEXCOORD0; }; struct Varyings { float2 uv : TEXCOORD0; float4 positionCS : SV_POSITION; }; Varyings Vertex(Attributes input) { Varyings output = (Varyings)0; output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.uv = input.texcoord; return output; } TEXTURE2D(_ObjectAABBTexture0); SAMPLER(sampler_ObjectAABBTexture0); TEXTURE2D(_ObjectAABBTexture1); SAMPLER(sampler_ObjectAABBTexture1); TEXTURE2D(_DepthPyramidTexture); SAMPLER(sampler_DepthPyramidTexture); float4x4 _GPUCullingVP; float2 _MipmapLevelMinMaxIndex; float2 _Mip0Size; float4 _MipOffsetAndSize[16]; static const float3 aggressiveExtentArray[8] = { float3(1, 1, 1), float3(1, 1, -1), float3(1, -1, 1), float3(1, -1, -1), float3(-1, 1, 1), float3(-1, 1, -1), float3(-1, -1, 1), float3(-1, -1, -1) }; float3 TransferNDC(float3 pos) { float4 ndc = mul(_GPUCullingVP, float4(pos, 1.0)); ndc.xyz /= ndc.w; ndc.xy = ndc.xy * 0.5f + 0.5f; ndc.y = 1 - ndc.y; return ndc.xyz; } half CullFrag(Varyings input) : SV_Target { float2 uv = input.uv; float4 aabbCenter = SAMPLE_TEXTURE2D_LOD(_ObjectAABBTexture0, sampler_ObjectAABBTexture0, uv, 0.0); float4 aabbSize = SAMPLE_TEXTURE2D_LOD(_ObjectAABBTexture1, sampler_ObjectAABBTexture1, uv, 0.0); float3 aabbExtent = aabbSize.xyz; UNITY_BRANCH if (aabbCenter.a == 0.0) { return 1; } #ifdef UNITY_REVERSED_Z float minZ = 0; #else float minZ = 1; #endif float2 maxXY = 0; float2 minXY = 1; for (uint i = 0; i < 8; ++i) { float3 boxCorner = aabbCenter + aabbExtent * aggressiveExtentArray[i]; float4 clipPos = mul(_GPUCullingVP, float4(boxCorner, 1)); clipPos /= clipPos.w; clipPos.xy = clipPos.xy * 0.5f + 0.5f; #if UNITY_UV_STARTS_AT_TOP clipPos.y = 1 - clipPos.y; #endif minXY = min(clipPos.xy, minXY); maxXY = max(clipPos.xy, maxXY); #ifdef UNITY_REVERSED_Z minZ = max(minZ, clipPos.z); #else minZ = min(minZ, clipPos.z); #endif } float4 boxUVs = float4(minXY, maxXY); // if( boxUVs.x < 0 || boxUVs.y < 0 || boxUVs.x > 1 || boxUVs.y > 1 || boxUVs.z >1 || boxUVs.z<0) // { // return 1; // } float2 size = (boxUVs.zw - boxUVs.xy) * _Mip0Size.xy; float mip = (log2(max(size.x, size.y))); mip = ceil(mip); mip = clamp(mip, _MipmapLevelMinMaxIndex.x, _MipmapLevelMinMaxIndex.y); // float level_lower = max(mip - 1, 0); // float2 scale = exp2(-level_lower) / _Mip0Size.xy; // float2 a = floor(boxUVs.xy*scale); // float2 b = ceil(boxUVs.zw*scale); // float2 dims = b - a; // // // Use the lower level if we only touch <= 2 texels in both dimensions // if (dims.x <= 2 && dims.y <= 2) // mip = level_lower; float4 offsetAndSize = _MipOffsetAndSize[mip]; int4 pxMinMax = boxUVs * offsetAndSize.zwzw + offsetAndSize.xyxy; float4 depth = float4(LOAD_TEXTURE2D_LOD(_DepthPyramidTexture, pxMinMax.xy, 0).r, LOAD_TEXTURE2D_LOD(_DepthPyramidTexture, pxMinMax.zy, 0).r, LOAD_TEXTURE2D_LOD(_DepthPyramidTexture, pxMinMax.xw, 0).r, LOAD_TEXTURE2D_LOD(_DepthPyramidTexture, pxMinMax.zw, 0).r ); #ifdef UNITY_REVERSED_Z depth.xy = min(depth.xy, depth.zw); depth.x = min(depth.x, depth.y); return minZ > depth.x ? 0 : 1; #else depth.xy = max(depth.xy, depth.zw); depth.x = max(depth.x, depth.y); return minZ < depth.x ? 1 : 0; #endif } ENDHLSL } } }