Files
ZHGD_Web/Assets/Art/Art Plugins/GPUInstancer/Resources/Compute/Include/CullingVR.hlsl
2025-07-13 23:16:20 +08:00

156 lines
6.8 KiB
HLSL

#ifndef __cullingVR_hlsl_
#define __cullingVR_hlsl_
#include "Params.hlsl"
#include "Culling.hlsl"
uniform float4x4 mvpMatrix2;
inline bool IsOcclusionCulledVR(in float4x4 instanceMatrix, in float4 BoundingBox[8])
{
bool isCulled = false;
// Hierarchical Z-Buffer Occlusion Culling
if (!isCulled && isOcclusionCulling)
{
// NOTE: for Direct3D, the clipping space z coordinate ranges from 0 to w and for OpenGL, it ranges from -w to w. However, since we use Unity's Projection Matrix directly,
// there is no need to worry about the difference between platforms. The projection matrix will always be left handed.
// Also, the reversed depth value between these APIs are taken care of in the blit and compute shaders while creating the hiZ depth texture.
for (int i = 0; i < 8; i++)
{
BoundingBox[i].xyz /= BoundingBox[i].w; // unscale clip depth to NDC
BoundingBox[i].z = BoundingBox[i].z * 0.5 + 0.5; // map BB depth values back to [0, 1];
}
float4 BoundingRect;
BoundingRect.x = (min(min(min(BoundingBox[0].x, BoundingBox[1].x),
min(BoundingBox[2].x, BoundingBox[3].x)),
min(min(BoundingBox[4].x, BoundingBox[5].x),
min(BoundingBox[6].x, BoundingBox[7].x))) / 2.0 + 0.5) * 0.5;
BoundingRect.y = min(min(min(BoundingBox[0].y, BoundingBox[1].y),
min(BoundingBox[2].y, BoundingBox[3].y)),
min(min(BoundingBox[4].y, BoundingBox[5].y),
min(BoundingBox[6].y, BoundingBox[7].y))) / 2.0 + 0.5;
BoundingRect.z = (max(max(max(BoundingBox[0].x, BoundingBox[1].x),
max(BoundingBox[2].x, BoundingBox[3].x)),
max(max(BoundingBox[4].x, BoundingBox[5].x),
max(BoundingBox[6].x, BoundingBox[7].x))) / 2.0 + 0.5) * 0.5;
BoundingRect.w = max(max(max(BoundingBox[0].y, BoundingBox[1].y),
max(BoundingBox[2].y, BoundingBox[3].y)),
max(max(BoundingBox[4].y, BoundingBox[5].y),
max(BoundingBox[6].y, BoundingBox[7].y))) / 2.0 + 0.5;
float InstanceDepth = min(min(min(BoundingBox[0].z, BoundingBox[1].z),
min(BoundingBox[2].z, BoundingBox[3].z)),
min(min(BoundingBox[4].z, BoundingBox[5].z),
min(BoundingBox[6].z, BoundingBox[7].z)));
// Calculate the bounding rectangle size in viewport coordinates
float ViewSizeX = (BoundingRect.z - BoundingRect.x) * hiZTxtrSize.x * 0.5;
float ViewSizeY = (BoundingRect.w - BoundingRect.y) * hiZTxtrSize.y;
// Calculate the texture LOD used for lookup in the depth buffer texture
float LOD = ceil(log2(max(ViewSizeX, ViewSizeY) / pow(2, occlusionAccuracy)));
float MaxDepth = OcclusionSample(BoundingRect, LOD, 0);
isCulled = InstanceDepth > MaxDepth + occlusionOffset;
if (isCulled)
{
float4x4 to_clip_space_mat2 = mul(mvpMatrix2, instanceMatrix); // Calculate clip space matrix
float3 Min = boundsCenter - boundsExtents;
float3 Max = boundsCenter + boundsExtents;
float4 BoundingBox2[8];
BoundingBox2[0] = mul(to_clip_space_mat2, float4(Min.x, Max.y, Min.z, 1.0));
BoundingBox2[1] = mul(to_clip_space_mat2, float4(Min.x, Max.y, Max.z, 1.0));
BoundingBox2[2] = mul(to_clip_space_mat2, float4(Max.x, Max.y, Max.z, 1.0));
BoundingBox2[3] = mul(to_clip_space_mat2, float4(Max.x, Max.y, Min.z, 1.0));
BoundingBox2[4] = mul(to_clip_space_mat2, float4(Max.x, Min.y, Min.z, 1.0));
BoundingBox2[5] = mul(to_clip_space_mat2, float4(Max.x, Min.y, Max.z, 1.0));
BoundingBox2[6] = mul(to_clip_space_mat2, float4(Min.x, Min.y, Max.z, 1.0));
BoundingBox2[7] = mul(to_clip_space_mat2, float4(Min.x, Min.y, Min.z, 1.0));
for (int j = 0; j < 8; j++)
{
BoundingBox2[j].xyz /= BoundingBox2[j].w; // unscale clip depth to NDC
BoundingBox2[j].z = BoundingBox2[j].z * 0.5 + 0.5; // map BB depth values back to [0, 1];
}
float4 BoundingRect2;
BoundingRect2.x = (min(min(min(BoundingBox2[0].x, BoundingBox2[1].x),
min(BoundingBox2[2].x, BoundingBox2[3].x)),
min(min(BoundingBox2[4].x, BoundingBox2[5].x),
min(BoundingBox2[6].x, BoundingBox2[7].x))) / 2.0 + 0.5) * 0.5;
BoundingRect2.y = min(min(min(BoundingBox2[0].y, BoundingBox2[1].y),
min(BoundingBox2[2].y, BoundingBox2[3].y)),
min(min(BoundingBox2[4].y, BoundingBox2[5].y),
min(BoundingBox2[6].y, BoundingBox2[7].y))) / 2.0 + 0.5;
BoundingRect2.z = (max(max(max(BoundingBox2[0].x, BoundingBox2[1].x),
max(BoundingBox2[2].x, BoundingBox2[3].x)),
max(max(BoundingBox2[4].x, BoundingBox2[5].x),
max(BoundingBox2[6].x, BoundingBox2[7].x))) / 2.0 + 0.5) * 0.5;
BoundingRect2.w = max(max(max(BoundingBox2[0].y, BoundingBox2[1].y),
max(BoundingBox2[2].y, BoundingBox2[3].y)),
max(max(BoundingBox2[4].y, BoundingBox2[5].y),
max(BoundingBox2[6].y, BoundingBox2[7].y))) / 2.0 + 0.5;
InstanceDepth = min(min(min(BoundingBox2[0].z, BoundingBox2[1].z),
min(BoundingBox2[2].z, BoundingBox2[3].z)),
min(min(BoundingBox2[4].z, BoundingBox2[5].z),
min(BoundingBox2[6].z, BoundingBox2[7].z)));
// Calculate the bounding rectangle size in viewport coordinates
ViewSizeX = (BoundingRect2.z - BoundingRect2.x) * hiZTxtrSize.x * 0.5;
ViewSizeY = (BoundingRect2.w - BoundingRect2.y) * hiZTxtrSize.y;
// Calculate the texture LOD used for lookup in the depth buffer texture
LOD = ceil(log2(max(ViewSizeX, ViewSizeY) / pow(2, occlusionAccuracy)));
MaxDepth = OcclusionSample(BoundingRect2, LOD, 0.5);
isCulled = InstanceDepth > MaxDepth + occlusionOffset;
}
}
return isCulled;
}
inline void IsCulledVR(in float4x4 instanceMatrix, in float dist, out bool culled)
{
culled = false;
// Distance culling
if (dist >= maxDistance || dist < minDistance)
{
culled = true;
}
if (!culled && dist >= minCullingDistance)
{
float4 BoundingBox[8];
CalculateBoundingBox(instanceMatrix, BoundingBox);
// OBB Frustum Culling
if (isFrustumCulling)
{
culled = IsFrustumCulled(BoundingBox);
}
// Hierarchical Z-Buffer Occlusion Culling
if (!culled && isOcclusionCulling)
{
culled = IsOcclusionCulledVR(instanceMatrix, BoundingBox);
}
}
}
#endif