Cull invisible gaussian splat chunks in prepare pass
This commit is contained in:
@@ -107,6 +107,102 @@ Shader "Builtin Gaussian Splat Utilities"
|
||||
return rawValue ^ mask;
|
||||
}
|
||||
|
||||
float2 UnpackHalfRange(uint packedValue)
|
||||
{
|
||||
return float2(
|
||||
f16tof32(packedValue & 0xffffu),
|
||||
f16tof32(packedValue >> 16u));
|
||||
}
|
||||
|
||||
float4 TransformLocalPointToClip(
|
||||
float3 localPosition,
|
||||
float4x4 modelMatrix,
|
||||
float4x4 viewMatrix,
|
||||
float4x4 projectionMatrix)
|
||||
{
|
||||
const float3 worldPosition = mul(modelMatrix, float4(localPosition, 1.0)).xyz;
|
||||
const float3 viewPosition = mul(viewMatrix, float4(worldPosition, 1.0)).xyz;
|
||||
return mul(projectionMatrix, float4(viewPosition, 1.0));
|
||||
}
|
||||
|
||||
bool IsChunkDefinitelyOutsideFrustum(
|
||||
GaussianSplatChunkData chunkData,
|
||||
uint chunkCount,
|
||||
uint chunkIndex,
|
||||
float4x4 modelMatrix,
|
||||
float4x4 viewMatrix,
|
||||
float4x4 projectionMatrix)
|
||||
{
|
||||
if (chunkCount == 0u || chunkIndex >= chunkCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float3 localMin = float3(chunkData.posX.x, chunkData.posY.x, chunkData.posZ.x);
|
||||
float3 localMax = float3(chunkData.posX.y, chunkData.posY.y, chunkData.posZ.y);
|
||||
if (localMin.x > localMax.x || localMin.y > localMax.y || localMin.z > localMax.z)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Inflate by a conservative 3-sigma envelope derived from the chunk's maximum splat scale.
|
||||
const float3 maxScale = float3(
|
||||
UnpackHalfRange(chunkData.sclX).y,
|
||||
UnpackHalfRange(chunkData.sclY).y,
|
||||
UnpackHalfRange(chunkData.sclZ).y);
|
||||
const float radius = max(maxScale.x, max(maxScale.y, maxScale.z)) * 3.0;
|
||||
localMin -= radius.xxx;
|
||||
localMax += radius.xxx;
|
||||
|
||||
bool allBehind = true;
|
||||
bool anyBehind = false;
|
||||
bool outsideLeft = true;
|
||||
bool outsideRight = true;
|
||||
bool outsideBottom = true;
|
||||
bool outsideTop = true;
|
||||
bool outsideNear = true;
|
||||
bool outsideFar = true;
|
||||
|
||||
[unroll]
|
||||
for (uint cornerIndex = 0u; cornerIndex < 8u; ++cornerIndex)
|
||||
{
|
||||
const float3 localCorner = float3(
|
||||
(cornerIndex & 1u) != 0u ? localMax.x : localMin.x,
|
||||
(cornerIndex & 2u) != 0u ? localMax.y : localMin.y,
|
||||
(cornerIndex & 4u) != 0u ? localMax.z : localMin.z);
|
||||
const float4 clipCorner = TransformLocalPointToClip(
|
||||
localCorner,
|
||||
modelMatrix,
|
||||
viewMatrix,
|
||||
projectionMatrix);
|
||||
const bool behind = clipCorner.w <= 0.0;
|
||||
allBehind = allBehind && behind;
|
||||
anyBehind = anyBehind || behind;
|
||||
|
||||
if (!behind)
|
||||
{
|
||||
outsideLeft = outsideLeft && (clipCorner.x < -clipCorner.w);
|
||||
outsideRight = outsideRight && (clipCorner.x > clipCorner.w);
|
||||
outsideBottom = outsideBottom && (clipCorner.y < -clipCorner.w);
|
||||
outsideTop = outsideTop && (clipCorner.y > clipCorner.w);
|
||||
outsideNear = outsideNear && (clipCorner.z < 0.0);
|
||||
outsideFar = outsideFar && (clipCorner.z > clipCorner.w);
|
||||
}
|
||||
}
|
||||
|
||||
if (allBehind)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (anyBehind)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return outsideLeft || outsideRight || outsideBottom || outsideTop || outsideNear || outsideFar;
|
||||
}
|
||||
|
||||
float3x3 CalcMatrixFromRotationScale(float4 rotation, float3 scale)
|
||||
{
|
||||
const float x = rotation.x;
|
||||
@@ -260,7 +356,9 @@ Shader "Builtin Gaussian Splat Utilities"
|
||||
const GaussianSplatOtherData otherData = GaussianSplatOther[index];
|
||||
const float4 colorOpacity = GaussianSplatColor[index];
|
||||
const GaussianSplatSHData shData = GaussianSplatSH[index];
|
||||
const GaussianSplatChunkData chunkData = GaussianSplatChunks[index / GAUSSIAN_SPLAT_CHUNK_SIZE];
|
||||
const uint chunkIndex = index / GAUSSIAN_SPLAT_CHUNK_SIZE;
|
||||
const uint chunkCount = (uint)gSplatParams.w;
|
||||
const GaussianSplatChunkData chunkData = GaussianSplatChunks[chunkIndex];
|
||||
const uint shOrder = min((uint)gSplatParams.z, 3u);
|
||||
if (chunkData.posX.x > chunkData.posX.y ||
|
||||
chunkData.posY.x > chunkData.posY.y ||
|
||||
@@ -270,6 +368,18 @@ Shader "Builtin Gaussian Splat Utilities"
|
||||
GaussianSplatViewDataBuffer[index] = viewData;
|
||||
return;
|
||||
}
|
||||
if (IsChunkDefinitelyOutsideFrustum(
|
||||
chunkData,
|
||||
chunkCount,
|
||||
chunkIndex,
|
||||
gModelMatrix,
|
||||
gViewMatrix,
|
||||
gProjectionMatrix))
|
||||
{
|
||||
GaussianSplatSortDistances[index] = 0xffffffffu;
|
||||
GaussianSplatViewDataBuffer[index] = viewData;
|
||||
return;
|
||||
}
|
||||
|
||||
const float3 worldCenter = mul(gModelMatrix, float4(localCenter, 1.0)).xyz;
|
||||
const float3 viewCenter = mul(gViewMatrix, float4(worldCenter, 1.0)).xyz;
|
||||
|
||||
@@ -1106,7 +1106,7 @@ bool BuiltinGaussianSplatPass::PrepareVisibleGaussianSplat(
|
||||
static_cast<float>(cachedGaussianSplat->splatCount),
|
||||
static_cast<float>(workingSet->sortCapacity),
|
||||
shOrder,
|
||||
0.0f)
|
||||
static_cast<float>(cachedGaussianSplat->chunkCount))
|
||||
};
|
||||
|
||||
if (passLayout->descriptorSetCount > 0u) {
|
||||
|
||||
Reference in New Issue
Block a user