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) {
|
||||
|
||||
@@ -50,6 +50,53 @@ constexpr uint32_t kFrameWidth = 1280;
|
||||
constexpr uint32_t kFrameHeight = 720;
|
||||
constexpr uint32_t kBaselineSubsetSplatCount = 65536u;
|
||||
|
||||
XCEngine::Core::uint16 FloatToHalfBits(float value) {
|
||||
uint32_t bits = 0u;
|
||||
std::memcpy(&bits, &value, sizeof(bits));
|
||||
|
||||
const uint32_t sign = (bits >> 16u) & 0x8000u;
|
||||
uint32_t mantissa = bits & 0x007fffffu;
|
||||
int32_t exponent = static_cast<int32_t>((bits >> 23u) & 0xffu) - 127 + 15;
|
||||
|
||||
if (exponent <= 0) {
|
||||
if (exponent < -10) {
|
||||
return static_cast<XCEngine::Core::uint16>(sign);
|
||||
}
|
||||
|
||||
mantissa = (mantissa | 0x00800000u) >> static_cast<uint32_t>(1 - exponent);
|
||||
if ((mantissa & 0x00001000u) != 0u) {
|
||||
mantissa += 0x00002000u;
|
||||
}
|
||||
|
||||
return static_cast<XCEngine::Core::uint16>(sign | (mantissa >> 13u));
|
||||
}
|
||||
|
||||
if (exponent >= 31) {
|
||||
return static_cast<XCEngine::Core::uint16>(sign | 0x7c00u);
|
||||
}
|
||||
|
||||
if ((mantissa & 0x00001000u) != 0u) {
|
||||
mantissa += 0x00002000u;
|
||||
if ((mantissa & 0x00800000u) != 0u) {
|
||||
mantissa = 0u;
|
||||
++exponent;
|
||||
if (exponent >= 31) {
|
||||
return static_cast<XCEngine::Core::uint16>(sign | 0x7c00u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<XCEngine::Core::uint16>(
|
||||
sign |
|
||||
(static_cast<uint32_t>(exponent) << 10u) |
|
||||
(mantissa >> 13u));
|
||||
}
|
||||
|
||||
uint32_t PackHalfRange(float minValue, float maxValue) {
|
||||
return static_cast<uint32_t>(FloatToHalfBits(minValue)) |
|
||||
(static_cast<uint32_t>(FloatToHalfBits(maxValue)) << 16u);
|
||||
}
|
||||
|
||||
std::filesystem::path GetRoomPlyPath() {
|
||||
return std::filesystem::path(XCENGINE_TEST_ROOM_PLY_PATH);
|
||||
}
|
||||
@@ -153,21 +200,39 @@ GaussianSplat* CreateGaussianSplatSubset(
|
||||
-std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max());
|
||||
Vector3 minScale(
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::max());
|
||||
Vector3 maxScale(
|
||||
-std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max());
|
||||
|
||||
for (uint32_t subsetIndex = startIndex; subsetIndex < endIndex; ++subsetIndex) {
|
||||
const Vector3& position = subsetPositions[subsetIndex].position;
|
||||
const Vector3& scale = subsetOther[subsetIndex].scale;
|
||||
minPosition.x = std::min(minPosition.x, position.x);
|
||||
minPosition.y = std::min(minPosition.y, position.y);
|
||||
minPosition.z = std::min(minPosition.z, position.z);
|
||||
maxPosition.x = std::max(maxPosition.x, position.x);
|
||||
maxPosition.y = std::max(maxPosition.y, position.y);
|
||||
maxPosition.z = std::max(maxPosition.z, position.z);
|
||||
minScale.x = std::min(minScale.x, scale.x);
|
||||
minScale.y = std::min(minScale.y, scale.y);
|
||||
minScale.z = std::min(minScale.z, scale.z);
|
||||
maxScale.x = std::max(maxScale.x, scale.x);
|
||||
maxScale.y = std::max(maxScale.y, scale.y);
|
||||
maxScale.z = std::max(maxScale.z, scale.z);
|
||||
}
|
||||
|
||||
GaussianSplatChunkRecord chunk = {};
|
||||
chunk.posX = Vector2(minPosition.x, maxPosition.x);
|
||||
chunk.posY = Vector2(minPosition.y, maxPosition.y);
|
||||
chunk.posZ = Vector2(minPosition.z, maxPosition.z);
|
||||
chunk.sclX = PackHalfRange(minScale.x, maxScale.x);
|
||||
chunk.sclY = PackHalfRange(minScale.y, maxScale.y);
|
||||
chunk.sclZ = PackHalfRange(minScale.z, maxScale.z);
|
||||
subsetChunks[chunkIndex] = chunk;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user