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;
|
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)
|
float3x3 CalcMatrixFromRotationScale(float4 rotation, float3 scale)
|
||||||
{
|
{
|
||||||
const float x = rotation.x;
|
const float x = rotation.x;
|
||||||
@@ -260,7 +356,9 @@ Shader "Builtin Gaussian Splat Utilities"
|
|||||||
const GaussianSplatOtherData otherData = GaussianSplatOther[index];
|
const GaussianSplatOtherData otherData = GaussianSplatOther[index];
|
||||||
const float4 colorOpacity = GaussianSplatColor[index];
|
const float4 colorOpacity = GaussianSplatColor[index];
|
||||||
const GaussianSplatSHData shData = GaussianSplatSH[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);
|
const uint shOrder = min((uint)gSplatParams.z, 3u);
|
||||||
if (chunkData.posX.x > chunkData.posX.y ||
|
if (chunkData.posX.x > chunkData.posX.y ||
|
||||||
chunkData.posY.x > chunkData.posY.y ||
|
chunkData.posY.x > chunkData.posY.y ||
|
||||||
@@ -270,6 +368,18 @@ Shader "Builtin Gaussian Splat Utilities"
|
|||||||
GaussianSplatViewDataBuffer[index] = viewData;
|
GaussianSplatViewDataBuffer[index] = viewData;
|
||||||
return;
|
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 worldCenter = mul(gModelMatrix, float4(localCenter, 1.0)).xyz;
|
||||||
const float3 viewCenter = mul(gViewMatrix, float4(worldCenter, 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>(cachedGaussianSplat->splatCount),
|
||||||
static_cast<float>(workingSet->sortCapacity),
|
static_cast<float>(workingSet->sortCapacity),
|
||||||
shOrder,
|
shOrder,
|
||||||
0.0f)
|
static_cast<float>(cachedGaussianSplat->chunkCount))
|
||||||
};
|
};
|
||||||
|
|
||||||
if (passLayout->descriptorSetCount > 0u) {
|
if (passLayout->descriptorSetCount > 0u) {
|
||||||
|
|||||||
@@ -50,6 +50,53 @@ constexpr uint32_t kFrameWidth = 1280;
|
|||||||
constexpr uint32_t kFrameHeight = 720;
|
constexpr uint32_t kFrameHeight = 720;
|
||||||
constexpr uint32_t kBaselineSubsetSplatCount = 65536u;
|
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() {
|
std::filesystem::path GetRoomPlyPath() {
|
||||||
return std::filesystem::path(XCENGINE_TEST_ROOM_PLY_PATH);
|
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(),
|
-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) {
|
for (uint32_t subsetIndex = startIndex; subsetIndex < endIndex; ++subsetIndex) {
|
||||||
const Vector3& position = subsetPositions[subsetIndex].position;
|
const Vector3& position = subsetPositions[subsetIndex].position;
|
||||||
|
const Vector3& scale = subsetOther[subsetIndex].scale;
|
||||||
minPosition.x = std::min(minPosition.x, position.x);
|
minPosition.x = std::min(minPosition.x, position.x);
|
||||||
minPosition.y = std::min(minPosition.y, position.y);
|
minPosition.y = std::min(minPosition.y, position.y);
|
||||||
minPosition.z = std::min(minPosition.z, position.z);
|
minPosition.z = std::min(minPosition.z, position.z);
|
||||||
maxPosition.x = std::max(maxPosition.x, position.x);
|
maxPosition.x = std::max(maxPosition.x, position.x);
|
||||||
maxPosition.y = std::max(maxPosition.y, position.y);
|
maxPosition.y = std::max(maxPosition.y, position.y);
|
||||||
maxPosition.z = std::max(maxPosition.z, position.z);
|
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 = {};
|
GaussianSplatChunkRecord chunk = {};
|
||||||
chunk.posX = Vector2(minPosition.x, maxPosition.x);
|
chunk.posX = Vector2(minPosition.x, maxPosition.x);
|
||||||
chunk.posY = Vector2(minPosition.y, maxPosition.y);
|
chunk.posY = Vector2(minPosition.y, maxPosition.y);
|
||||||
chunk.posZ = Vector2(minPosition.z, maxPosition.z);
|
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;
|
subsetChunks[chunkIndex] = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user