156 lines
6.8 KiB
HLSL
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
|