111 lines
4.0 KiB
Plaintext
111 lines
4.0 KiB
Plaintext
// Each #kernel tells which function to compile; you can have many kernels
|
|
#pragma kernel CSMain
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
|
#include "Packages/com.misaki.ao-volume/Runtime/Shader/Includes/GeometryData.cs.hlsl"
|
|
|
|
#define FLT_MIN 1.175494351e-38 // Minimum representable positive floating-point number
|
|
#define FLT_MAX 3.402823466e+38 // Maximum representable floating-point number
|
|
|
|
StructuredBuffer<OrientedBoundingBox> _VolumeBounds;
|
|
StructuredBuffer<int2> _DepthPyramidMipLevelOffsets;
|
|
|
|
uint _FullVolumeCount;
|
|
|
|
uint _DepthPyramidMaxMip;
|
|
|
|
RWByteAddressBuffer _VisibleVolumeIndices : register(u0);
|
|
RWByteAddressBuffer _VisibleVolumeCount : register(u1);
|
|
|
|
RW_TEXTURE2D_X(float, _DebugTexture);
|
|
|
|
float4 ComputeScreenPos(float4 pos, float projectionSign)
|
|
{
|
|
float4 o = pos * 0.5f;
|
|
o.xy = float2(o.x, o.y * projectionSign) + o.w;
|
|
o.zw = pos.zw;
|
|
return o;
|
|
}
|
|
|
|
float SampleDepthLod(int2 uv, int lod)
|
|
{
|
|
int2 mipCoord = uv >> lod;
|
|
int2 mipOffset = _DepthPyramidMipLevelOffsets[lod];
|
|
|
|
float deviceDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, mipOffset + mipCoord).r;
|
|
return deviceDepth;
|
|
}
|
|
|
|
[numthreads(64,1,1)]
|
|
void CSMain(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
if (dispatchThreadId.x >= _FullVolumeCount)
|
|
{
|
|
return; // early exit if outside our range
|
|
}
|
|
|
|
OrientedBoundingBox box = _VolumeBounds[dispatchThreadId.x];
|
|
|
|
// Compute the 8 corners of the OBB.
|
|
// The box is defined by its center, two axes (right & up) and its extents.
|
|
// We compute the forward vector as the cross product (assuming right and up are orthogonal).
|
|
float3 right = box.right * box.extent.x;
|
|
float3 up = box.up * box.extent.y;
|
|
float3 forward = normalize(cross(box.right, box.up));
|
|
float3 fExtent = forward * box.extent.z;
|
|
|
|
float3 corners[8];
|
|
corners[0] = box.center + right + up + fExtent;
|
|
corners[1] = box.center + right + up - fExtent;
|
|
corners[2] = box.center + right - up + fExtent;
|
|
corners[3] = box.center + right - up - fExtent;
|
|
corners[4] = box.center - right + up + fExtent;
|
|
corners[5] = box.center - right + up - fExtent;
|
|
corners[6] = box.center - right - up + fExtent;
|
|
corners[7] = box.center - right - up - fExtent;
|
|
|
|
// Compute screen-space bounding rectangle and find the minimum depth (closest point)
|
|
float2 screenMin = float2(FLT_MAX, FLT_MAX);
|
|
float2 screenMax = float2(-FLT_MAX, -FLT_MAX);
|
|
float boxMaxDepth = -FLT_MAX;
|
|
|
|
[unroll]
|
|
for (int j = 0; j < 8; ++j)
|
|
{
|
|
float3 cornerRWS = GetCameraRelativePositionWS(corners[j]);
|
|
float4 positionCS = TransformWorldToHClip(cornerRWS);
|
|
positionCS /= positionCS.w;
|
|
|
|
float2 screenPos = ComputeScreenPos(positionCS, _ProjectionParams.x).xy * _ScreenSize.xy;
|
|
|
|
screenMin = min(screenMin, screenPos);
|
|
screenMax = max(screenMax, screenPos);
|
|
|
|
boxMaxDepth = max(boxMaxDepth, positionCS.z);
|
|
}
|
|
|
|
// For HZ culling we need to sample the proper mip level.
|
|
// We estimate the rectangle size in pixels.
|
|
float rectWidth = (screenMax.x - screenMin.x);
|
|
float rectHeight = (screenMax.y - screenMin.y);
|
|
float rectSize = max(rectWidth, rectHeight);
|
|
int mipLevel = (int)clamp(floor(log2(rectSize)), 0.0, (float)_DepthPyramidMaxMip);
|
|
|
|
// Sample the hierarchical depth texture.
|
|
// Here we simply sample at the center of the rectangle.
|
|
// TODO: Use a more sophisticated method to sample the depth pyramid.
|
|
int2 uvCenter = (screenMin + screenMax) * 0.5;
|
|
float occluderDepth = SampleDepthLod(uvCenter, mipLevel);
|
|
|
|
// Perform the occlusion test:
|
|
// If the closest point of the box (boxMaxDepth) is behind the occluder,
|
|
// then the box is completely occluded.
|
|
// TODO: pack 16 bits index to save memory
|
|
if (occluderDepth <= boxMaxDepth)
|
|
{
|
|
uint index;
|
|
_VisibleVolumeCount.InterlockedAdd(0, 1, index);
|
|
_VisibleVolumeIndices.Store(index << 2, dispatchThreadId.x);
|
|
}
|
|
} |