perf(generation): inline exact IsFinite -- LOD0 ~11-12% faster, field-exact

The sampler's last "unknown" LOD0 bucket (~13.8%) was ucrtbase.dll!_finite: FMath::IsFinite is an
out-of-line CRT call on the MSVC game path, hit from the innermost tunnel, passage, density,
spatial-index and meshing loops.

- VoxelMath::IsFiniteFast(float/double) in VoxelTypes.h: memcpy to uint32/uint64,
  (Bits & ExpMask) != ExpMask. It is the same predicate for every bit pattern, with no FP
  comparison for fast-math to fold. The disassembly shows it inlined (movd/movq, mask, compare).
- VoxelMath::IsFinite routes through a plain global, voxel.FastIsFinite (default 1), for the A/B.
  The CRT call remains only on the switch-off branch. Hot generation-path uses are replaced; no
  _finite / std::isfinite remains in Source/VoxelForge. Tool/editor/test code keeps FMath.
- A test that can fail: VoxelForge.Math.IsFiniteExact compares against FMath::IsFinite over 22
  explicit float/double patterns (+-0, denormals, min/max normal, +-Inf, quiet and signalling NaN
  payloads) plus 2,000,000 hashed patterns each: 0 mismatches. The explicit NaNs make a NaN-wrong
  helper fail.

Field exact: 841/841 keyed tiles identical to NextHeadStaticTrace_20260913 (verdict/empty/
triangles), export OBJ unchanged (b3e5f4c3..9b377), capability 20,830 / 10,909.

Within-round A/B, game path, two interleaved runs each, sampler off (off -> on):
  static  LOD0 request p50  95.5 -> 84.8 ms   generation p50/p95  70.3/114.1 -> 62.3/100.6 ms
          worker            35.4 -> 31.6 s (-10.5%)
  moving  LOD0 request p50/p95  70.8/144.2 -> 62.0/126.1 ms
          generation p50/p95    62.6/113.4 -> 55.1/101.0 ms
          worker            102.6 -> 91.3 s (-11.0%)
Sampler-on moving: the _finite/CRT cluster is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
Fr0zkaandClaude Opus 5 committed 2026-09-13 23:50:30 +02:00
1 parent 22186473f9
commit 5489b5e311
11 files changed
+816 -558

No files matched your search

@@ -0,0 +1,181 @@
// Bit-exact equivalence coverage for the generation-path finite predicate.
#if WITH_DEV_AUTOMATION_TESTS
#include "Misc/AutomationTest.h"
#include "VoxelTypes.h"
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FVoxelForgeIsFiniteTest,
"VoxelForge.Math.IsFiniteExact",
EAutomationTestFlags_ApplicationContextMask | EAutomationTestFlags::EngineFilter)
namespace
{
template <typename TValue, typename TBits>
TValue ValueFromBits(TBits Bits)
{
TValue Value;
FMemory::Memcpy(&Value, &Bits, sizeof(Value));
return Value;
}
FORCEINLINE uint64 NextHashedBits(uint64& State)
{
State += 0x9E3779B97F4A7C15ull;
uint64 Z = State;
Z = (Z ^ (Z >> 30)) * 0xBF58476D1CE4E5B9ull;
Z = (Z ^ (Z >> 27)) * 0x94D049BB133111EBull;
return Z ^ (Z >> 31);
}
struct FFloatPattern
{
const TCHAR* Name;
uint32 Bits;
};
struct FDoublePattern
{
const TCHAR* Name;
uint64 Bits;
};
}
bool FVoxelForgeIsFiniteTest::RunTest(const FString& Parameters)
{
int32 FloatMismatches = 0;
int32 DoubleMismatches = 0;
auto CheckFloat = [&](const TCHAR* Name, uint32 Bits)
{
const float Value = ValueFromBits<float>(Bits);
const bool Fast = VoxelMath::IsFiniteFast(Value);
const bool Reference = FMath::IsFinite(Value);
if (Fast != Reference)
{
++FloatMismatches;
if (FloatMismatches <= 8)
{
AddError(FString::Printf(
TEXT("%s: float bits 0x%08X produced fast=%s, FMath=%s"),
Name, Bits,
Fast ? TEXT("true") : TEXT("false"),
Reference ? TEXT("true") : TEXT("false")));
}
}
};
auto CheckDouble = [&](const TCHAR* Name, uint64 Bits)
{
const double Value = ValueFromBits<double>(Bits);
const bool Fast = VoxelMath::IsFiniteFast(Value);
const bool Reference = FMath::IsFinite(Value);
if (Fast != Reference)
{
++DoubleMismatches;
if (DoubleMismatches <= 8)
{
AddError(FString::Printf(
TEXT("%s: double bits 0x%08X%08X produced fast=%s, FMath=%s"),
Name,
static_cast<uint32>(Bits >> 32), static_cast<uint32>(Bits),
Fast ? TEXT("true") : TEXT("false"),
Reference ? TEXT("true") : TEXT("false")));
}
}
};
// Explicit classes make a NaN regression fail even if the random stream happens not to hit a
// NaN. In particular, a helper that only checks the sign/exponent incorrectly must fail here.
const FFloatPattern FloatPatterns[] =
{
{ TEXT("+0"), 0x00000000u },
{ TEXT("-0"), 0x80000000u },
{ TEXT("+min subnormal"), 0x00000001u },
{ TEXT("-min subnormal"), 0x80000001u },
{ TEXT("+max subnormal"), 0x007FFFFFu },
{ TEXT("-max subnormal"), 0x807FFFFFu },
{ TEXT("+min normal"), 0x00800000u },
{ TEXT("-min normal"), 0x80800000u },
{ TEXT("+max normal"), 0x7F7FFFFFu },
{ TEXT("-max normal"), 0xFF7FFFFFu },
{ TEXT("+infinity"), 0x7F800000u },
{ TEXT("-infinity"), 0xFF800000u },
{ TEXT("+quiet NaN payload 1"), 0x7FC00001u },
{ TEXT("-quiet NaN payload 1"), 0xFFC00001u },
{ TEXT("+quiet NaN payload mixed"), 0x7FC12345u },
{ TEXT("-quiet NaN payload mixed"), 0xFFC12345u },
{ TEXT("+signalling NaN payload 1"), 0x7F800001u },
{ TEXT("-signalling NaN payload 1"), 0xFF800001u },
{ TEXT("+signalling NaN payload mixed"), 0x7FA00001u },
{ TEXT("-signalling NaN payload mixed"), 0xFFA00001u },
{ TEXT("+signalling NaN max payload"), 0x7FBFFFFFu },
{ TEXT("-signalling NaN max payload"), 0xFFBFFFFFu },
};
for (const FFloatPattern& Pattern : FloatPatterns)
{
CheckFloat(Pattern.Name, Pattern.Bits);
}
const FDoublePattern DoublePatterns[] =
{
{ TEXT("+0"), 0x0000000000000000ull },
{ TEXT("-0"), 0x8000000000000000ull },
{ TEXT("+min subnormal"), 0x0000000000000001ull },
{ TEXT("-min subnormal"), 0x8000000000000001ull },
{ TEXT("+max subnormal"), 0x000FFFFFFFFFFFFFull },
{ TEXT("-max subnormal"), 0x800FFFFFFFFFFFFFull },
{ TEXT("+min normal"), 0x0010000000000000ull },
{ TEXT("-min normal"), 0x8010000000000000ull },
{ TEXT("+max normal"), 0x7FEFFFFFFFFFFFFFull },
{ TEXT("-max normal"), 0xFFEFFFFFFFFFFFFFull },
{ TEXT("+infinity"), 0x7FF0000000000000ull },
{ TEXT("-infinity"), 0xFFF0000000000000ull },
{ TEXT("+quiet NaN payload 1"), 0x7FF8000000000001ull },
{ TEXT("-quiet NaN payload 1"), 0xFFF8000000000001ull },
{ TEXT("+quiet NaN payload mixed"), 0x7FF8123456789ABCull },
{ TEXT("-quiet NaN payload mixed"), 0xFFF8123456789ABCull },
{ TEXT("+signalling NaN payload 1"), 0x7FF0000000000001ull },
{ TEXT("-signalling NaN payload 1"), 0xFFF0000000000001ull },
{ TEXT("+signalling NaN payload mixed"), 0x7FF4000000000001ull },
{ TEXT("-signalling NaN payload mixed"), 0xFFF4000000000001ull },
{ TEXT("+signalling NaN max payload"), 0x7FF7FFFFFFFFFFFFull },
{ TEXT("-signalling NaN max payload"), 0xFFF7FFFFFFFFFFFFull },
};
for (const FDoublePattern& Pattern : DoublePatterns)
{
CheckDouble(Pattern.Name, Pattern.Bits);
}
// Deterministic hash-generated raw bit patterns exercise ordinary values and special values
// without converting through floating point. The loop counts are intentionally large enough
// to make this a broad bit-pattern check rather than a handful of representative numbers.
constexpr uint32 NumRandomFloatPatterns = 2000000u;
constexpr uint32 NumRandomDoublePatterns = 2000000u;
uint64 FloatState = 0x123456789ABCDEF0ull;
for (uint32 Index = 0; Index < NumRandomFloatPatterns; ++Index)
{
CheckFloat(TEXT("hashed random"), static_cast<uint32>(NextHashedBits(FloatState)));
}
uint64 DoubleState = 0x0FEDCBA987654321ull;
for (uint32 Index = 0; Index < NumRandomDoublePatterns; ++Index)
{
CheckDouble(TEXT("hashed random"), NextHashedBits(DoubleState));
}
AddInfo(FString::Printf(
TEXT("Compared %d explicit + %u hashed float patterns and %d explicit + %u hashed double "
"patterns; float mismatches=%d, double mismatches=%d."),
UE_ARRAY_COUNT(FloatPatterns), NumRandomFloatPatterns,
UE_ARRAY_COUNT(DoublePatterns), NumRandomDoublePatterns,
FloatMismatches, DoubleMismatches));
TestEqual(TEXT("float finite predicate has no mismatches"), FloatMismatches, 0);
TestEqual(TEXT("double finite predicate has no mismatches"), DoubleMismatches, 0);
return FloatMismatches == 0 && DoubleMismatches == 0;
}
#endif // WITH_DEV_AUTOMATION_TESTS
File diff suppressed because it is too large. Load diff
@@ -190,9 +190,9 @@ namespace
FORCEINLINE float VF_PerlinAbsBoundOverBox( FORCEINLINE float VF_PerlinAbsBoundOverBox(
const FVector3f& InMin, const FVector3f& InMax) const FVector3f& InMin, const FVector3f& InMax)
{ {
if (!FMath::IsFinite(InMin.X) || !FMath::IsFinite(InMin.Y) if (!VoxelMath::IsFinite(InMin.X) || !VoxelMath::IsFinite(InMin.Y)
|| !FMath::IsFinite(InMin.Z) || !FMath::IsFinite(InMax.X) || !VoxelMath::IsFinite(InMin.Z) || !VoxelMath::IsFinite(InMax.X)
|| !FMath::IsFinite(InMax.Y) || !FMath::IsFinite(InMax.Z) || !VoxelMath::IsFinite(InMax.Y) || !VoxelMath::IsFinite(InMax.Z)
|| InMin.X > InMax.X || InMin.Y > InMax.Y || InMin.Z > InMax.Z || InMin.X > InMax.X || InMin.Y > InMax.Y || InMin.Z > InMax.Z
|| FMath::Abs(InMin.X) > 1000000.0f || FMath::Abs(InMax.X) > 1000000.0f || FMath::Abs(InMin.X) > 1000000.0f || FMath::Abs(InMax.X) > 1000000.0f
|| FMath::Abs(InMin.Y) > 1000000.0f || FMath::Abs(InMax.Y) > 1000000.0f || FMath::Abs(InMin.Y) > 1000000.0f || FMath::Abs(InMax.Y) > 1000000.0f
@@ -279,7 +279,7 @@ namespace
ValueMax += Contribution.Max; ValueMax += Contribution.Max;
} }
if (!FMath::IsFinite(ValueMin) || !FMath::IsFinite(ValueMax)) if (!VoxelMath::IsFinite(ValueMin) || !VoxelMath::IsFinite(ValueMax))
{ {
return VF_PerlinAbsBound; return VF_PerlinAbsBound;
} }
@@ -420,8 +420,8 @@ namespace
FORCEINLINE float VF_LatticeAxisDistanceToPoint( FORCEINLINE float VF_LatticeAxisDistanceToPoint(
float BoxMin, float BoxMax, float Origin, float Step, float Target, float Extra) float BoxMin, float BoxMax, float Origin, float Step, float Target, float Extra)
{ {
if (!(Step > 0.0f) || !FMath::IsFinite(BoxMin) || !FMath::IsFinite(BoxMax) if (!(Step > 0.0f) || !VoxelMath::IsFinite(BoxMin) || !VoxelMath::IsFinite(BoxMax)
|| !FMath::IsFinite(Origin) || !FMath::IsFinite(Target) || !VoxelMath::IsFinite(Origin) || !VoxelMath::IsFinite(Target)
|| BoxMin > BoxMax) || BoxMin > BoxMax)
{ {
return FLT_MAX; return FLT_MAX;
@@ -451,7 +451,7 @@ namespace
float BoxMin, float BoxMax, float Origin, float Step, float BoxMin, float BoxMax, float Origin, float Step,
float TargetMin, float TargetMax, float Extra) float TargetMin, float TargetMax, float Extra)
{ {
if (!(Step > 0.0f) || !FMath::IsFinite(TargetMin) || !FMath::IsFinite(TargetMax) if (!(Step > 0.0f) || !VoxelMath::IsFinite(TargetMin) || !VoxelMath::IsFinite(TargetMax)
|| TargetMin > TargetMax) || TargetMin > TargetMax)
{ {
return FLT_MAX; return FLT_MAX;
@@ -483,7 +483,7 @@ namespace
FORCEINLINE float VF_SaturatingAdd(float A, float B) FORCEINLINE float VF_SaturatingAdd(float A, float B)
{ {
if (!FMath::IsFinite(A) || !FMath::IsFinite(B)) { return FLT_MAX; } if (!VoxelMath::IsFinite(A) || !VoxelMath::IsFinite(B)) { return FLT_MAX; }
if (B > 0.0f && A > FLT_MAX - B) { return FLT_MAX; } if (B > 0.0f && A > FLT_MAX - B) { return FLT_MAX; }
if (B < 0.0f && A < -FLT_MAX - B) { return -FLT_MAX; } if (B < 0.0f && A < -FLT_MAX - B) { return -FLT_MAX; }
return A + B; return A + B;
@@ -603,7 +603,7 @@ namespace
void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox&, void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox&,
const FVoxelOpContext&) const override const FVoxelOpContext&) const override
{ {
if (!FMath::IsFinite(CellSize) || !FMath::IsFinite(CorridorRadius) if (!VoxelMath::IsFinite(CellSize) || !VoxelMath::IsFinite(CorridorRadius)
|| CellSize <= 0.0f || CorridorRadius < 0.0f) || CellSize <= 0.0f || CorridorRadius < 0.0f)
{ {
InOut.SetUnknown(); InOut.SetUnknown();
@@ -1575,8 +1575,8 @@ namespace
const FVoxelOpContext&) const override const FVoxelOpContext&) const override
{ {
if (!InOut.IsKnown()) { return; } if (!InOut.IsKnown()) { return; }
if (!FMath::IsFinite(Strength) || !FMath::IsFinite(Frequency) if (!VoxelMath::IsFinite(Strength) || !VoxelMath::IsFinite(Frequency)
|| !FMath::IsFinite(ApplyWithin) || BaseOctaves <= 0) || !VoxelMath::IsFinite(ApplyWithin) || BaseOctaves <= 0)
{ {
InOut.SetUnknown(); InOut.SetUnknown();
return; return;
@@ -1589,7 +1589,7 @@ namespace
FMath::Max(FMath::Abs((float)VoxelBox.Min.X), FMath::Abs((float)VoxelBox.Max.X)), FMath::Max(FMath::Abs((float)VoxelBox.Min.X), FMath::Abs((float)VoxelBox.Max.X)),
FMath::Max(FMath::Abs((float)VoxelBox.Min.Y), FMath::Abs((float)VoxelBox.Max.Y)), FMath::Max(FMath::Abs((float)VoxelBox.Min.Y), FMath::Abs((float)VoxelBox.Max.Y)),
FMath::Max(FMath::Abs((float)VoxelBox.Min.Z), FMath::Abs((float)VoxelBox.Max.Z))); FMath::Max(FMath::Abs((float)VoxelBox.Min.Z), FMath::Abs((float)VoxelBox.Max.Z)));
if (!FMath::IsFinite(MaxAbsCoord) || !FMath::IsFinite(MaxAbsCoord * FMath::Abs(Frequency))) if (!VoxelMath::IsFinite(MaxAbsCoord) || !VoxelMath::IsFinite(MaxAbsCoord * FMath::Abs(Frequency)))
{ {
InOut.SetUnknown(); InOut.SetUnknown();
return; return;
@@ -1806,8 +1806,8 @@ namespace
EVoxelOpEffect EffectOverBox(const FBox&, const FVoxelOpContext&) const override EVoxelOpEffect EffectOverBox(const FBox&, const FVoxelOpContext&) const override
{ {
const float Coefficient = Sign * BaseDensity * 2.0f; const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient) || !FMath::IsFinite(Blend) if (!VoxelMath::IsFinite(Coefficient) || !VoxelMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{ {
return EVoxelOpEffect::Both; return EVoxelOpEffect::Both;
} }
@@ -1831,8 +1831,8 @@ namespace
float MaxCarveOverBox(const FBox&, const FVoxelOpContext&) const override float MaxCarveOverBox(const FBox&, const FVoxelOpContext&) const override
{ {
const float Coefficient = Sign * BaseDensity * 2.0f; const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient) || !FMath::IsFinite(Blend) if (!VoxelMath::IsFinite(Coefficient) || !VoxelMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{ {
return FLT_MAX; return FLT_MAX;
} }
@@ -1842,8 +1842,8 @@ namespace
float MaxFillOverBox(const FBox&, const FVoxelOpContext&) const override float MaxFillOverBox(const FBox&, const FVoxelOpContext&) const override
{ {
const float Coefficient = Sign * BaseDensity * 2.0f; const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient) || !FMath::IsFinite(Blend) if (!VoxelMath::IsFinite(Coefficient) || !VoxelMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{ {
return FLT_MAX; return FLT_MAX;
} }
@@ -1854,8 +1854,8 @@ namespace
const FVoxelBoxHypotheses& H) const override const FVoxelBoxHypotheses& H) const override
{ {
const float Coefficient = Sign * BaseDensity * 2.0f; const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient)) { return FLT_MAX; } if (!VoxelMath::IsFinite(Coefficient)) { return FLT_MAX; }
if (!FMath::IsFinite(Blend) || !FMath::IsFinite(MinDivisor) || Blend <= 0.0f) if (!VoxelMath::IsFinite(Blend) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{ {
return FLT_MAX; return FLT_MAX;
} }
@@ -1867,8 +1867,8 @@ namespace
const FVoxelBoxHypotheses& H) const override const FVoxelBoxHypotheses& H) const override
{ {
const float Coefficient = Sign * BaseDensity * 2.0f; const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient)) { return FLT_MAX; } if (!VoxelMath::IsFinite(Coefficient)) { return FLT_MAX; }
if (!FMath::IsFinite(Blend) || !FMath::IsFinite(MinDivisor) || Blend <= 0.0f) if (!VoxelMath::IsFinite(Blend) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{ {
return FLT_MAX; return FLT_MAX;
} }
@@ -1891,14 +1891,14 @@ namespace
float MaxFactor(const FVoxelBoxHypotheses& H) const float MaxFactor(const FVoxelBoxHypotheses& H) const
{ {
if (!H.Sdf.IsKnown() || !FMath::IsFinite(Blend) if (!H.Sdf.IsKnown() || !VoxelMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{ {
return 1.0f; return 1.0f;
} }
const float Denom = FMath::Max(Blend * 2.0f, MinDivisor); const float Denom = FMath::Max(Blend * 2.0f, MinDivisor);
if (!(Denom > 0.0f) || !FMath::IsFinite(Denom)) { return 1.0f; } if (!(Denom > 0.0f) || !VoxelMath::IsFinite(Denom)) { return 1.0f; }
const float T = FMath::Clamp((Blend - H.Sdf.Min) / Denom, 0.0f, 1.0f); const float T = FMath::Clamp((Blend - H.Sdf.Min) / Denom, 0.0f, 1.0f);
return SmoothStep01(T); return SmoothStep01(T);
@@ -2223,18 +2223,18 @@ namespace
const float MaxFactor = LiveManager->MaxPassageCarveFactorNearLattice( const float MaxFactor = LiveManager->MaxPassageCarveFactorNearLattice(
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step); VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step);
if (!(MaxFactor > 0.0f)) { return 0.0f; } if (!(MaxFactor > 0.0f)) { return 0.0f; }
if (!(H.SolidMargin > 0.0f) || !FMath::IsFinite(H.SolidMargin) if (!(H.SolidMargin > 0.0f) || !VoxelMath::IsFinite(H.SolidMargin)
|| !FMath::IsFinite(Base) || !FMath::IsFinite(Seal)) || !VoxelMath::IsFinite(Base) || !VoxelMath::IsFinite(Seal))
{ {
return FLT_MAX; return FLT_MAX;
} }
const float AirTarget = -(Base * 2.0f + Seal + 4.0f); const float AirTarget = -(Base * 2.0f + Seal + 4.0f);
if (!FMath::IsFinite(AirTarget)) { return FLT_MAX; } if (!VoxelMath::IsFinite(AirTarget)) { return FLT_MAX; }
const float LowerAfterCarve = FMath::Min( const float LowerAfterCarve = FMath::Min(
H.SolidMargin, H.SolidMargin,
FMath::Lerp(H.SolidMargin, AirTarget, FMath::Clamp(MaxFactor, 0.0f, 1.0f))); FMath::Lerp(H.SolidMargin, AirTarget, FMath::Clamp(MaxFactor, 0.0f, 1.0f)));
if (!FMath::IsFinite(LowerAfterCarve)) { return FLT_MAX; } if (!VoxelMath::IsFinite(LowerAfterCarve)) { return FLT_MAX; }
return FMath::Max(0.0f, H.SolidMargin - LowerAfterCarve); return FMath::Max(0.0f, H.SolidMargin - LowerAfterCarve);
} }
@@ -2355,13 +2355,13 @@ namespace
void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox& VoxelBox, void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox& VoxelBox,
const FVoxelOpContext&) const override const FVoxelOpContext&) const override
{ {
if (!FMath::IsFinite((float)VoxelBox.Min.X) || !FMath::IsFinite((float)VoxelBox.Min.Y) if (!VoxelMath::IsFinite((float)VoxelBox.Min.X) || !VoxelMath::IsFinite((float)VoxelBox.Min.Y)
|| !FMath::IsFinite((float)VoxelBox.Min.Z) || !VoxelMath::IsFinite((float)VoxelBox.Min.Z)
|| !FMath::IsFinite((float)VoxelBox.Max.X) || !FMath::IsFinite((float)VoxelBox.Max.Y) || !VoxelMath::IsFinite((float)VoxelBox.Max.X) || !VoxelMath::IsFinite((float)VoxelBox.Max.Y)
|| !FMath::IsFinite((float)VoxelBox.Max.Z) || !VoxelMath::IsFinite((float)VoxelBox.Max.Z)
|| VoxelBox.Min.X > VoxelBox.Max.X || VoxelBox.Min.Y > VoxelBox.Max.Y || VoxelBox.Min.X > VoxelBox.Max.X || VoxelBox.Min.Y > VoxelBox.Max.Y
|| VoxelBox.Min.Z > VoxelBox.Max.Z || VoxelBox.Min.Z > VoxelBox.Max.Z
|| !FMath::IsFinite(P.ShaftSpacing) || P.ShaftSpacing <= 0.0f) || !VoxelMath::IsFinite(P.ShaftSpacing) || P.ShaftSpacing <= 0.0f)
{ {
InOut.SetUnknown(); InOut.SetUnknown();
return; return;
@@ -3021,16 +3021,16 @@ namespace
void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox& VoxelBox, void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox& VoxelBox,
const FVoxelOpContext&) const override const FVoxelOpContext&) const override
{ {
if (!FMath::IsFinite((float)VoxelBox.Min.X) || !FMath::IsFinite((float)VoxelBox.Min.Y) if (!VoxelMath::IsFinite((float)VoxelBox.Min.X) || !VoxelMath::IsFinite((float)VoxelBox.Min.Y)
|| !FMath::IsFinite((float)VoxelBox.Min.Z) || !VoxelMath::IsFinite((float)VoxelBox.Min.Z)
|| !FMath::IsFinite((float)VoxelBox.Max.X) || !FMath::IsFinite((float)VoxelBox.Max.Y) || !VoxelMath::IsFinite((float)VoxelBox.Max.X) || !VoxelMath::IsFinite((float)VoxelBox.Max.Y)
|| !FMath::IsFinite((float)VoxelBox.Max.Z) || !VoxelMath::IsFinite((float)VoxelBox.Max.Z)
|| VoxelBox.Min.X > VoxelBox.Max.X || VoxelBox.Min.Y > VoxelBox.Max.Y || VoxelBox.Min.X > VoxelBox.Max.X || VoxelBox.Min.Y > VoxelBox.Max.Y
|| VoxelBox.Min.Z > VoxelBox.Max.Z || VoxelBox.Min.Z > VoxelBox.Max.Z
|| !FMath::IsFinite(P.IslandSpacing) || !FMath::IsFinite(P.IslandDensity) || !VoxelMath::IsFinite(P.IslandSpacing) || !VoxelMath::IsFinite(P.IslandDensity)
|| !FMath::IsFinite(P.IslandMinRadius) || !FMath::IsFinite(P.IslandMaxRadius) || !VoxelMath::IsFinite(P.IslandMinRadius) || !VoxelMath::IsFinite(P.IslandMaxRadius)
|| !FMath::IsFinite(P.ThicknessRatio) || !FMath::IsFinite(P.VerticalJitter) || !VoxelMath::IsFinite(P.ThicknessRatio) || !VoxelMath::IsFinite(P.VerticalJitter)
|| !FMath::IsFinite(P.TopFlatten) || !FMath::IsFinite(P.SDFBlendRadius) || !VoxelMath::IsFinite(P.TopFlatten) || !VoxelMath::IsFinite(P.SDFBlendRadius)
|| P.IslandDensity < 0.0f) || P.IslandDensity < 0.0f)
{ {
InOut.SetUnknown(); InOut.SetUnknown();
@@ -4389,7 +4389,7 @@ namespace
{ {
const float StructuralFloorMinimumDensity = const float StructuralFloorMinimumDensity =
FMath::Max(P.BaseDensity * 2.0f, 1.0f); FMath::Max(P.BaseDensity * 2.0f, 1.0f);
if (FMath::IsFinite(StructuralFloorMinimumDensity) if (VoxelMath::IsFinite(StructuralFloorMinimumDensity)
&& StructuralFloorMinimumDensity > 0.0f) && StructuralFloorMinimumDensity > 0.0f)
{ {
InOut.bProtectedStructuralFloor = true; InOut.bProtectedStructuralFloor = true;
@@ -4629,7 +4629,7 @@ namespace
float Supremum = 0.0f; float Supremum = 0.0f;
for (const FCachedColumn& Column : GetBoxCache().Columns) for (const FCachedColumn& Column : GetBoxCache().Columns)
{ {
if (!FMath::IsFinite(Column.BaseDensity) || Column.BaseDensity < 0.0f) if (!VoxelMath::IsFinite(Column.BaseDensity) || Column.BaseDensity < 0.0f)
{ {
// Eval multiplies by BaseDensity. A negative authored value reverses the // Eval multiplies by BaseDensity. A negative authored value reverses the
// declared FillOnly direction, so the state-aware caller must fall back to // declared FillOnly direction, so the state-aware caller must fall back to
@@ -4637,7 +4637,7 @@ namespace
return FLT_MAX; return FLT_MAX;
} }
const float Contribution = Column.BaseDensity * 1.5f; const float Contribution = Column.BaseDensity * 1.5f;
if (!FMath::IsFinite(Contribution) if (!VoxelMath::IsFinite(Contribution)
|| Supremum > FLT_MAX - Contribution) || Supremum > FLT_MAX - Contribution)
{ {
return FLT_MAX; return FLT_MAX;
@@ -4658,13 +4658,13 @@ namespace
// room wins the nearest-SDF query, and is finite without assuming a global room height. // room wins the nearest-SDF query, and is finite without assuming a global room height.
float Supremum = 0.0f; float Supremum = 0.0f;
const float BoxMinZ = static_cast<float>(B.KeyBox.Min.Z); const float BoxMinZ = static_cast<float>(B.KeyBox.Min.Z);
if (!FMath::IsFinite(BoxMinZ)) { return FLT_MAX; } if (!VoxelMath::IsFinite(BoxMinZ)) { return FLT_MAX; }
for (const FCachedRoom& Room : GetBoxCache().Rooms) for (const FCachedRoom& Room : GetBoxCache().Rooms)
{ {
const float CenterZ = static_cast<float>(Room.Center.Z); const float CenterZ = static_cast<float>(Room.Center.Z);
const float RadiusZ = Room.RadiusZ; const float RadiusZ = Room.RadiusZ;
if (!FMath::IsFinite(CenterZ) || !FMath::IsFinite(RadiusZ) if (!VoxelMath::IsFinite(CenterZ) || !VoxelMath::IsFinite(RadiusZ)
|| !FMath::IsFinite(P.FloorBias) || P.FloorBias < 0.0f) || !VoxelMath::IsFinite(P.FloorBias) || P.FloorBias < 0.0f)
{ {
return FLT_MAX; return FLT_MAX;
} }
@@ -4672,7 +4672,7 @@ namespace
const float Below = FMath::Max(CenterZ - BoxMinZ, 0.0f); const float Below = FMath::Max(CenterZ - BoxMinZ, 0.0f);
const float Normalized = Below / Denominator; const float Normalized = Below / Denominator;
const float Contribution = Normalized * Normalized * P.FloorBias; const float Contribution = Normalized * Normalized * P.FloorBias;
if (!FMath::IsFinite(Contribution)) { return FLT_MAX; } if (!VoxelMath::IsFinite(Contribution)) { return FLT_MAX; }
Supremum = FMath::Max(Supremum, Contribution); Supremum = FMath::Max(Supremum, Contribution);
} }
return Supremum; return Supremum;
@@ -4745,7 +4745,7 @@ namespace
B.SdfInterval.SetUnknown(); B.SdfInterval.SetUnknown();
InOut.SetUnknown(); InOut.SetUnknown();
}; };
auto Finite = [](float V) { return FMath::IsFinite(V); }; auto Finite = [](float V) { return VoxelMath::IsFinite(V); };
if (ManagerLifetimeId != 0 && LiveManager == nullptr) if (ManagerLifetimeId != 0 && LiveManager == nullptr)
{ {
@@ -6262,7 +6262,7 @@ namespace
}; };
const float K = P.SDFBlendRadius; const float K = P.SDFBlendRadius;
const float WormThreshold = FMath::IsFinite(P.WormNetworkRange) const float WormThreshold = VoxelMath::IsFinite(P.WormNetworkRange)
? FMath::Max(3.0f * K, P.WormNetworkRange) : FLT_MAX; ? FMath::Max(3.0f * K, P.WormNetworkRange) : FLT_MAX;
const float ThresholdWithBlend = VF_SaturatingAdd(WormThreshold, K); const float ThresholdWithBlend = VF_SaturatingAdd(WormThreshold, K);
float Lower = FLT_MAX; float Lower = FLT_MAX;
@@ -6803,7 +6803,7 @@ namespace
static_cast<float>(World.Z), GetBoxCache(), SupportColumn, static_cast<float>(World.Z), GetBoxCache(), SupportColumn,
VoxelGenLOD::ShouldUseSpatialIndex(false)); VoxelGenLOD::ShouldUseSpatialIndex(false));
++B.ExactTailEvaluated; ++B.ExactTailEvaluated;
if (!FMath::IsFinite(Evaluation.SDF)) if (!VoxelMath::IsFinite(Evaluation.SDF))
{ {
bExactTailUnknown = true; bExactTailUnknown = true;
if (CachedTailState != nullptr) { *CachedTailState = 0x84u; } if (CachedTailState != nullptr) { *CachedTailState = 0x84u; }
@@ -6941,7 +6941,7 @@ namespace
FORCEINLINE bool VF_CaveBoxIsFar(const FVoxelBoxHypotheses& H, float SDFBlendRadius) FORCEINLINE bool VF_CaveBoxIsFar(const FVoxelBoxHypotheses& H, float SDFBlendRadius)
{ {
const float Threshold = SDFBlendRadius * 3.0f; const float Threshold = SDFBlendRadius * 3.0f;
return FMath::IsFinite(Threshold) && H.Sdf.IsKnown() && H.Sdf.Min >= Threshold; return VoxelMath::IsFinite(Threshold) && H.Sdf.IsKnown() && H.Sdf.Min >= Threshold;
} }
FORCEINLINE EVoxelOpEffect VF_CaveDetailEffect(const FRoomGraphSource* Rooms, FORCEINLINE EVoxelOpEffect VF_CaveDetailEffect(const FRoomGraphSource* Rooms,
@@ -7179,7 +7179,7 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.SurfaceRoughness > 0.0f)) { return 0.0f; } if (!(P.SurfaceRoughness > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.SurfaceRoughness)) { return FLT_MAX; } if (!VoxelMath::IsFinite(P.SurfaceRoughness)) { return FLT_MAX; }
float NoiseBound = VF_PerlinAbsBound; float NoiseBound = VF_PerlinAbsBound;
switch (P.RoughnessNoiseType) switch (P.RoughnessNoiseType)
@@ -7200,14 +7200,14 @@ namespace
} }
const float Result = 1.4f * NoiseBound * P.SurfaceRoughness * VOXEL_NOISE_SCALE; const float Result = 1.4f * NoiseBound * P.SurfaceRoughness * VOXEL_NOISE_SCALE;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
bool IsInactiveFromSdf(const FVoxelBoxHypotheses& H) const bool IsInactiveFromSdf(const FVoxelBoxHypotheses& H) const
{ {
if (VF_CaveBoxIsFar(H, P.SDFBlendRadius)) { return true; } if (VF_CaveBoxIsFar(H, P.SDFBlendRadius)) { return true; }
if (!(P.SurfaceRoughness > 0.0f) || !FMath::IsFinite(P.SurfaceRoughness)) if (!(P.SurfaceRoughness > 0.0f) || !VoxelMath::IsFinite(P.SurfaceRoughness))
{ {
return P.SurfaceRoughness <= 0.0f; return P.SurfaceRoughness <= 0.0f;
} }
@@ -7215,7 +7215,7 @@ namespace
// Eval's second gate is abs(CaveSDF) < SurfaceRoughness*2. A known positive // Eval's second gate is abs(CaveSDF) < SurfaceRoughness*2. A known positive
// lower endpoint at or beyond that depth therefore proves the op is an identity even // lower endpoint at or beyond that depth therefore proves the op is an identity even
// when the broader shared near-surface gate (SDFBlendRadius*3) remains open. // when the broader shared near-surface gate (SDFBlendRadius*3) remains open.
return FMath::IsFinite(RoughnessDepth) && H.Sdf.IsKnown() return VoxelMath::IsFinite(RoughnessDepth) && H.Sdf.IsKnown()
&& H.Sdf.Min >= RoughnessDepth; && H.Sdf.Min >= RoughnessDepth;
} }
@@ -7372,8 +7372,8 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
return (P.TerraceStepHeight > 0.0f return (P.TerraceStepHeight > 0.0f
&& FMath::IsFinite(P.TerraceStepHeight) && VoxelMath::IsFinite(P.TerraceStepHeight)
&& FMath::IsFinite(P.TerraceHardness) && VoxelMath::IsFinite(P.TerraceHardness)
&& P.TerraceHardness >= 0.0f && P.TerraceHardness <= 1.0f) && P.TerraceHardness >= 0.0f && P.TerraceHardness <= 1.0f)
? P.TerraceStepHeight : (P.TerraceStepHeight > 0.0f ? FLT_MAX : 0.0f); ? P.TerraceStepHeight : (P.TerraceStepHeight > 0.0f ? FLT_MAX : 0.0f);
} }
@@ -7473,7 +7473,7 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.LayerLineSpacing > 0.0f)) { return 0.0f; } if (!(P.LayerLineSpacing > 0.0f)) { return 0.0f; }
return FMath::IsFinite(P.LayerLineDepth) return VoxelMath::IsFinite(P.LayerLineDepth)
? FMath::Max(P.LayerLineDepth, 0.0f) : FLT_MAX; ? FMath::Max(P.LayerLineDepth, 0.0f) : FLT_MAX;
} }
@@ -7571,7 +7571,7 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.RibbingSpacing > 0.0f)) { return 0.0f; } if (!(P.RibbingSpacing > 0.0f)) { return 0.0f; }
return FMath::IsFinite(P.RibbingDepth) return VoxelMath::IsFinite(P.RibbingDepth)
? FMath::Max(P.RibbingDepth, 0.0f) : FLT_MAX; ? FMath::Max(P.RibbingDepth, 0.0f) : FLT_MAX;
} }
@@ -7675,14 +7675,14 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.OverhangStrength > 0.0f && P.OverhangDepth > 0.0f)) { return 0.0f; } if (!(P.OverhangStrength > 0.0f && P.OverhangDepth > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.OverhangDepth) if (!VoxelMath::IsFinite(P.OverhangDepth)
|| !FMath::IsFinite(P.OverhangStrength)) || !VoxelMath::IsFinite(P.OverhangStrength))
{ {
return FLT_MAX; return FLT_MAX;
} }
const float Result = VOXEL_NOISE_SCALE * VF_PerlinAbsBound const float Result = VOXEL_NOISE_SCALE * VF_PerlinAbsBound
* P.OverhangDepth * P.OverhangStrength; * P.OverhangDepth * P.OverhangStrength;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
@@ -7801,10 +7801,10 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.CliffStrength > 0.0f)) { return 0.0f; } if (!(P.CliffStrength > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.CliffStrength)) { return FLT_MAX; } if (!VoxelMath::IsFinite(P.CliffStrength)) { return FLT_MAX; }
const float Result = 8.0f * 3.0f * VOXEL_NOISE_SCALE const float Result = 8.0f * 3.0f * VOXEL_NOISE_SCALE
* VF_PerlinAbsBound * P.CliffStrength; * VF_PerlinAbsBound * P.CliffStrength;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
@@ -7908,9 +7908,9 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.ScallopStrength > 0.0f)) { return 0.0f; } if (!(P.ScallopStrength > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.ScallopStrength)) { return FLT_MAX; } if (!VoxelMath::IsFinite(P.ScallopStrength)) { return FLT_MAX; }
const float Result = VF_CellularAbsBound * P.ScallopStrength; const float Result = VF_CellularAbsBound * P.ScallopStrength;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
@@ -8037,9 +8037,9 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.ArchDensity > 0.0f)) { return 0.0f; } if (!(P.ArchDensity > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.BaseDensity)) { return FLT_MAX; } if (!VoxelMath::IsFinite(P.BaseDensity)) { return FLT_MAX; }
const float Result = FMath::Abs(P.BaseDensity) * 3.0f * 1.5f; const float Result = FMath::Abs(P.BaseDensity) * 3.0f * 1.5f;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
@@ -8130,7 +8130,7 @@ namespace
} }
const float Bound = Rooms->RoomColumnFillSupremumForLastBox(); const float Bound = Rooms->RoomColumnFillSupremumForLastBox();
if (!(Bound > 0.0f)) { return EVoxelOpEffect::Identity; } if (!(Bound > 0.0f)) { return EVoxelOpEffect::Identity; }
return FMath::IsFinite(Bound) ? EVoxelOpEffect::FillOnly : EVoxelOpEffect::Both; return VoxelMath::IsFinite(Bound) ? EVoxelOpEffect::FillOnly : EVoxelOpEffect::Both;
} }
float MaxCarveOverBox(const FBox&, const FVoxelOpContext&) const override { return 0.0f; } float MaxCarveOverBox(const FBox&, const FVoxelOpContext&) const override { return 0.0f; }
@@ -8145,7 +8145,7 @@ namespace
{ {
if (Rooms == nullptr || VF_CaveBoxIsFar(H, P.SDFBlendRadius)) { return 0.0f; } if (Rooms == nullptr || VF_CaveBoxIsFar(H, P.SDFBlendRadius)) { return 0.0f; }
const float Bound = Rooms->RoomColumnFillSupremumForLastBox(); const float Bound = Rooms->RoomColumnFillSupremumForLastBox();
return FMath::IsFinite(Bound) ? 0.0f : Bound; return VoxelMath::IsFinite(Bound) ? 0.0f : Bound;
} }
float MaxFillOverBox(const FBox&, const FVoxelOpContext&, float MaxFillOverBox(const FBox&, const FVoxelOpContext&,
@@ -8293,9 +8293,9 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.DomeDensity > 0.0f)) { return 0.0f; } if (!(P.DomeDensity > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.BaseDensity)) { return FLT_MAX; } if (!VoxelMath::IsFinite(P.BaseDensity)) { return FLT_MAX; }
const float Result = FMath::Abs(P.BaseDensity) * 2.0f * 1.5f; const float Result = FMath::Abs(P.BaseDensity) * 2.0f * 1.5f;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
@@ -8415,9 +8415,9 @@ namespace
float MaxAmplitude() const float MaxAmplitude() const
{ {
if (!(P.PinchDensity > 0.0f)) { return 0.0f; } if (!(P.PinchDensity > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.BaseDensity)) { return FLT_MAX; } if (!VoxelMath::IsFinite(P.BaseDensity)) { return FLT_MAX; }
const float Result = FMath::Abs(P.BaseDensity) * 3.0f * 1.5f; const float Result = FMath::Abs(P.BaseDensity) * 3.0f * 1.5f;
return FMath::IsFinite(Result) ? Result : FLT_MAX; return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
} }
private: private:
@@ -8504,7 +8504,7 @@ namespace
float MaxFillOverBox(const FBox&, const FVoxelOpContext&) const override float MaxFillOverBox(const FBox&, const FVoxelOpContext&) const override
{ {
return FMath::IsFinite(P.FloorBias) && P.FloorBias >= 0.0f return VoxelMath::IsFinite(P.FloorBias) && P.FloorBias >= 0.0f
? P.FloorBias : (P.FloorBias < 0.0f ? 0.0f : FLT_MAX); ? P.FloorBias : (P.FloorBias < 0.0f ? 0.0f : FLT_MAX);
} }
@@ -8646,12 +8646,12 @@ namespace
const FVoxelBoxHypotheses& H) const override const FVoxelBoxHypotheses& H) const override
{ {
const float Strength = MaxCarveOverBox(VoxelBox, Ctx); const float Strength = MaxCarveOverBox(VoxelBox, Ctx);
if (!(Strength > 0.0f) || !FMath::IsFinite(Strength)) if (!(Strength > 0.0f) || !VoxelMath::IsFinite(Strength))
{ {
return Strength; return Strength;
} }
if (!(P.WormNetworkRange > 0.0f) || !FMath::IsFinite(P.WormNetworkRange) if (!(P.WormNetworkRange > 0.0f) || !VoxelMath::IsFinite(P.WormNetworkRange)
|| !H.Sdf.IsKnown() || !FMath::IsFinite(H.Sdf.Min)) || !H.Sdf.IsKnown() || !VoxelMath::IsFinite(H.Sdf.Min))
{ {
return Strength; return Strength;
} }
@@ -8664,11 +8664,11 @@ namespace
// interval's worst case, so this never assumes a room value that the preceding source // interval's worst case, so this never assumes a room value that the preceding source
// did not prove. // did not prove.
if (Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1 if (Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1
&& FMath::IsFinite(P.WormFrequency) && VoxelMath::IsFinite(P.WormFrequency)
&& FMath::IsFinite(P.WormHorizontalBias) && VoxelMath::IsFinite(P.WormHorizontalBias)
&& FMath::IsFinite(P.WormThreshold) && VoxelMath::IsFinite(P.WormThreshold)
&& P.WormThreshold > 0.0f && P.WormThreshold > 0.0f
&& FMath::IsFinite(P.VerticalScale)) && VoxelMath::IsFinite(P.VerticalScale))
{ {
const int32 Step = FMath::Max(Ctx.Step, 1); const int32 Step = FMath::Max(Ctx.Step, 1);
const float OriginX = static_cast<float>(Ctx.LatticeOriginVoxels.X); const float OriginX = static_cast<float>(Ctx.LatticeOriginVoxels.X);
@@ -8774,7 +8774,7 @@ namespace
float MaxCarveAmplitude() const float MaxCarveAmplitude() const
{ {
if (!(P.WormStrength > 0.0f && P.WormThreshold > 0.0f)) { return 0.0f; } if (!(P.WormStrength > 0.0f && P.WormThreshold > 0.0f)) { return 0.0f; }
return FMath::IsFinite(P.WormStrength) ? P.WormStrength : FLT_MAX; return VoxelMath::IsFinite(P.WormStrength) ? P.WormStrength : FLT_MAX;
} }
const TCHAR* DebugName() const override { return TEXT("WormFieldSource"); } const TCHAR* DebugName() const override { return TEXT("WormFieldSource"); }
@@ -9200,7 +9200,7 @@ void FVoxelOpStack::DiagnoseBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx
Entry.Op->Eval(static_cast<float>(X), static_cast<float>(Y), Entry.Op->Eval(static_cast<float>(X), static_cast<float>(Y),
static_cast<float>(Z), Sample); static_cast<float>(Z), Sample);
const float DensityDelta = Sample.Density - DensityBefore; const float DensityDelta = Sample.Density - DensityBefore;
if (FMath::IsFinite(DensityDelta)) if (VoxelMath::IsFinite(DensityDelta))
{ {
Diagnostic.bHasDensityDelta = true; Diagnostic.bHasDensityDelta = true;
Diagnostic.ActualDensityDeltaMin = Diagnostic.ActualDensityDeltaMin =
@@ -9219,12 +9219,12 @@ void FVoxelOpStack::DiagnoseBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx
* FMath::Max(1.0f, FMath::Abs(Diagnostic.MaxCarve)); * FMath::Max(1.0f, FMath::Abs(Diagnostic.MaxCarve));
const float FillEpsilon = BoundEpsilon const float FillEpsilon = BoundEpsilon
* FMath::Max(1.0f, FMath::Abs(Diagnostic.MaxFill)); * FMath::Max(1.0f, FMath::Abs(Diagnostic.MaxFill));
if (FMath::IsFinite(Diagnostic.MaxCarve) if (VoxelMath::IsFinite(Diagnostic.MaxCarve)
&& DensityDelta < -Diagnostic.MaxCarve - CarveEpsilon) && DensityDelta < -Diagnostic.MaxCarve - CarveEpsilon)
{ {
Diagnostic.bCarveBoundViolated = true; Diagnostic.bCarveBoundViolated = true;
} }
if (FMath::IsFinite(Diagnostic.MaxFill) if (VoxelMath::IsFinite(Diagnostic.MaxFill)
&& DensityDelta > Diagnostic.MaxFill + FillEpsilon) && DensityDelta > Diagnostic.MaxFill + FillEpsilon)
{ {
Diagnostic.bFillBoundViolated = true; Diagnostic.bFillBoundViolated = true;
@@ -9232,7 +9232,7 @@ void FVoxelOpStack::DiagnoseBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx
} }
} }
if (Diagnostic.bWritesSdf && FMath::IsFinite(Sample.Sdf)) if (Diagnostic.bWritesSdf && VoxelMath::IsFinite(Sample.Sdf))
{ {
Diagnostic.bHasSdfValue = true; Diagnostic.bHasSdfValue = true;
Diagnostic.ActualSdfMin = FMath::Min( Diagnostic.ActualSdfMin = FMath::Min(
@@ -10338,8 +10338,8 @@ bool VF_BuildStackFromRecipe(const FVoxelOpStackRecipe& Recipe,
const float Bottom = VoxelStrateRecipePrivate::Bottom(Params, Recipe.StructuralParamBlock); const float Bottom = VoxelStrateRecipePrivate::Bottom(Params, Recipe.StructuralParamBlock);
const float Seal = VoxelStrateRecipePrivate::BoundarySeal(Params, Recipe.StructuralParamBlock); const float Seal = VoxelStrateRecipePrivate::BoundarySeal(Params, Recipe.StructuralParamBlock);
const float Base = VoxelStrateRecipePrivate::BaseDensity(Params, Recipe.StructuralParamBlock); const float Base = VoxelStrateRecipePrivate::BaseDensity(Params, Recipe.StructuralParamBlock);
if (!FMath::IsFinite(Top) || !FMath::IsFinite(Bottom) || Top <= Bottom if (!VoxelMath::IsFinite(Top) || !VoxelMath::IsFinite(Bottom) || Top <= Bottom
|| !FMath::IsFinite(Seal) || !FMath::IsFinite(Base)) || !VoxelMath::IsFinite(Seal) || !VoxelMath::IsFinite(Base))
{ {
return Fail(TEXT("Recipe structural parameters do not define a finite positive strate.")); return Fail(TEXT("Recipe structural parameters do not define a finite positive strate."));
} }
@@ -10574,9 +10574,9 @@ bool VF_BuildStrateRegionStack(
? Manifest.BoundarySealThickness : VF_RegionSeal(FirstParams, GlobalBlock); ? Manifest.BoundarySealThickness : VF_RegionSeal(FirstParams, GlobalBlock);
float Base = Manifest.bHasGlobalStructuralParams float Base = Manifest.bHasGlobalStructuralParams
? Manifest.BaseDensity : VF_RegionBase(FirstParams, GlobalBlock); ? Manifest.BaseDensity : VF_RegionBase(FirstParams, GlobalBlock);
if (!FMath::IsFinite(Top) || !FMath::IsFinite(Bottom) || !(Top > Bottom) if (!VoxelMath::IsFinite(Top) || !VoxelMath::IsFinite(Bottom) || !(Top > Bottom)
|| !FMath::IsFinite(Seal) || Seal < 0.0f || !VoxelMath::IsFinite(Seal) || Seal < 0.0f
|| !FMath::IsFinite(Base) || !(Base > 0.0f)) || !VoxelMath::IsFinite(Base) || !(Base > 0.0f))
{ {
return Fail(TEXT("lateral region structural parameters are not a finite positive strate")); return Fail(TEXT("lateral region structural parameters are not a finite positive strate"));
} }
+55 -24
View File
@@ -29,8 +29,37 @@
#include <atomic> #include <atomic>
namespace VoxelMath
{
VOXELFORGE_API int32 GFastIsFinite = 1;
}
namespace namespace
{ {
// The default-on branch uses VoxelMath::IsFiniteFast, while 0 retains the original
// FMath::IsFinite call for a real within-round A/B and sampler comparison.
FAutoConsoleVariableRef CVarVoxelForgeFastIsFinite(
TEXT("voxel.FastIsFinite"),
VoxelMath::GFastIsFinite,
TEXT("Use the exact inline IEEE-754 bit test instead of the CRT-backed FMath::IsFinite."));
bool GVoxelForgeFastIsFiniteSwitchParsed = false;
void VF_ParseFastIsFiniteSwitch()
{
if (GVoxelForgeFastIsFiniteSwitchParsed)
{
return;
}
GVoxelForgeFastIsFiniteSwitchParsed = true;
int32 CommandLineValue = VoxelMath::GFastIsFinite;
if (FParse::Value(
FCommandLine::Get(), TEXT("voxel.FastIsFinite="), CommandLineValue))
{
VoxelMath::GFastIsFinite = CommandLineValue;
}
VoxelMath::GFastIsFinite = VoxelMath::GFastIsFinite != 0 ? 1 : 0;
}
// The canonical native TunnelNetwork/Underwater graph has a hand-lowered evaluator. Keep a // The canonical native TunnelNetwork/Underwater graph has a hand-lowered evaluator. Keep a
// command-line switch so every change can be A/B'd against the existing interpreted/block // command-line switch so every change can be A/B'd against the existing interpreted/block
// path without changing the authored graph or rebuilding a different world definition. // path without changing the authored graph or rebuilding a different world definition.
@@ -861,7 +890,7 @@ static FORCEINLINE bool VF_DisturbanceBandTouchesBox(
{ {
const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness; const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness;
const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness; const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness;
if (!FMath::IsFinite(InnerTop) || !FMath::IsFinite(InnerBot)) if (!VoxelMath::IsFinite(InnerTop) || !VoxelMath::IsFinite(InnerBot))
{ {
return true; // Unknown boundary placement must not discharge a proof. return true; // Unknown boundary placement must not discharge a proof.
} }
@@ -929,16 +958,16 @@ static bool VF_AnyChasmCanTouchLattice(
{ {
return false; return false;
} }
if (!FMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f if (!VoxelMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f
|| D.ChasmDensity > 1.0f || !FMath::IsFinite(D.ChasmSpacing) || D.ChasmDensity > 1.0f || !VoxelMath::IsFinite(D.ChasmSpacing)
|| !FMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f || !VoxelMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f
|| D.ChasmRadius < 0.0f) || D.ChasmRadius < 0.0f)
{ {
return true; return true;
} }
const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness; const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness;
const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness; const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness;
if (!FMath::IsFinite(InnerTop) || !FMath::IsFinite(InnerBot)) if (!VoxelMath::IsFinite(InnerTop) || !VoxelMath::IsFinite(InnerBot))
{ {
return true; return true;
} }
@@ -987,16 +1016,16 @@ static bool VF_AnyBridgeCanTouchLattice(
{ {
return false; return false;
} }
if (!FMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f if (!VoxelMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f
|| D.BridgeDensity > 1.0f || !FMath::IsFinite(D.BridgeSpacing) || D.BridgeDensity > 1.0f || !VoxelMath::IsFinite(D.BridgeSpacing)
|| !FMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f || !VoxelMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f
|| D.BridgeRadius < 0.0f) || D.BridgeRadius < 0.0f)
{ {
return true; return true;
} }
const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness; const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness;
const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness; const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness;
if (!FMath::IsFinite(InnerTop) || !FMath::IsFinite(InnerBot)) if (!VoxelMath::IsFinite(InnerTop) || !VoxelMath::IsFinite(InnerBot))
{ {
return true; return true;
} }
@@ -1055,16 +1084,16 @@ static bool VF_AnyRidgeCanTouchLattice(
{ {
return false; return false;
} }
if (!FMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f if (!VoxelMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f
|| D.RidgeDensity > 1.0f || !FMath::IsFinite(D.RidgeSpacing) || D.RidgeDensity > 1.0f || !VoxelMath::IsFinite(D.RidgeSpacing)
|| !FMath::IsFinite(D.RidgeHeight) || !FMath::IsFinite(D.RidgeThickness) || !VoxelMath::IsFinite(D.RidgeHeight) || !VoxelMath::IsFinite(D.RidgeThickness)
|| D.RidgeSpacing <= 0.0f || D.RidgeHeight <= 0.0f || D.RidgeThickness < 0.0f) || D.RidgeSpacing <= 0.0f || D.RidgeHeight <= 0.0f || D.RidgeThickness < 0.0f)
{ {
return true; return true;
} }
const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness; const float InnerTop = D.StrateTopWorldZ - D.BoundarySealThickness;
const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness; const float InnerBot = D.StrateBottomWorldZ + D.BoundarySealThickness;
if (!FMath::IsFinite(InnerTop) || !FMath::IsFinite(InnerBot)) if (!VoxelMath::IsFinite(InnerTop) || !VoxelMath::IsFinite(InnerBot))
{ {
return true; return true;
} }
@@ -1124,9 +1153,9 @@ static bool VF_AnyChasmCanTouchBox(
{ {
return false; return false;
} }
if (!FMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f if (!VoxelMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f
|| D.ChasmDensity > 1.0f || !FMath::IsFinite(D.ChasmSpacing) || D.ChasmDensity > 1.0f || !VoxelMath::IsFinite(D.ChasmSpacing)
|| !FMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f || !VoxelMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f
|| D.ChasmRadius < 0.0f) || D.ChasmRadius < 0.0f)
{ {
return true; return true;
@@ -1171,9 +1200,9 @@ static bool VF_AnyBridgeCanTouchBox(
{ {
return false; return false;
} }
if (!FMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f if (!VoxelMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f
|| D.BridgeDensity > 1.0f || !FMath::IsFinite(D.BridgeSpacing) || D.BridgeDensity > 1.0f || !VoxelMath::IsFinite(D.BridgeSpacing)
|| !FMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f || !VoxelMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f
|| D.BridgeRadius < 0.0f) || D.BridgeRadius < 0.0f)
{ {
return true; return true;
@@ -1224,9 +1253,9 @@ static bool VF_AnyRidgeCanTouchBox(
{ {
return false; return false;
} }
if (!FMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f if (!VoxelMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f
|| D.RidgeDensity > 1.0f || !FMath::IsFinite(D.RidgeSpacing) || D.RidgeDensity > 1.0f || !VoxelMath::IsFinite(D.RidgeSpacing)
|| !FMath::IsFinite(D.RidgeHeight) || !FMath::IsFinite(D.RidgeThickness) || !VoxelMath::IsFinite(D.RidgeHeight) || !VoxelMath::IsFinite(D.RidgeThickness)
|| D.RidgeSpacing <= 0.0f || D.RidgeHeight <= 0.0f || D.RidgeThickness < 0.0f) || D.RidgeSpacing <= 0.0f || D.RidgeHeight <= 0.0f || D.RidgeThickness < 0.0f)
{ {
return true; return true;
@@ -1758,6 +1787,7 @@ UVoxelGenerator::UVoxelGenerator()
void UVoxelGenerator::InitializeSettings(const UVoxelSettings* Settings) void UVoxelGenerator::InitializeSettings(const UVoxelSettings* Settings)
{ {
VF_ParseFastIsFiniteSwitch();
// Les paramètres globaux sont copiés ici une seule fois : le chemin voxel ne doit pas // Les paramètres globaux sont copiés ici une seule fois : le chemin voxel ne doit pas
// déréférencer l'asset de settings. // déréférencer l'asset de settings.
Seed = Settings ? Settings->GetEffectiveWorldSeed() : 0; Seed = Settings ? Settings->GetEffectiveWorldSeed() : 0;
@@ -1780,6 +1810,7 @@ void UVoxelGenerator::EndDensityBlock() const
float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) const float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) const
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_GetDensityAt); TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_GetDensityAt);
VF_ParseFastIsFiniteSwitch();
VF_ParseFusedEvaluatorSwitch(); VF_ParseFusedEvaluatorSwitch();
VoxelDensityProfile::FScopedTimer DensityProfileTimer( VoxelDensityProfile::FScopedTimer DensityProfileTimer(
VoxelDensityProfile::EBucket::GetDensityAt); VoxelDensityProfile::EBucket::GetDensityAt);
@@ -5009,7 +5040,7 @@ static EVoxelTileClass VF_ClassifyBoxRefined(const FVoxelOpStack& Stack,
for (const int32 IX : Xs) for (const int32 IX : Xs)
{ {
const float Density = EvaluateExactLatticeValue(IX, IY, IZ, bUseFinalField); const float Density = EvaluateExactLatticeValue(IX, IY, IZ, bUseFinalField);
if (!FMath::IsFinite(Density) || Density == 0.0f) if (!VoxelMath::IsFinite(Density) || Density == 0.0f)
{ {
return false; return false;
} }
@@ -5053,7 +5084,7 @@ static EVoxelTileClass VF_ClassifyBoxRefined(const FVoxelOpStack& Stack,
for (int32 IX = IX0; IX <= IX1; ++IX) for (int32 IX = IX0; IX <= IX1; ++IX)
{ {
const float Density = EvaluateExactLatticeValue(IX, IY, IZ, bUseFinalField); const float Density = EvaluateExactLatticeValue(IX, IY, IZ, bUseFinalField);
if (!FMath::IsFinite(Density) || Density == 0.0f) if (!VoxelMath::IsFinite(Density) || Density == 0.0f)
{ {
++ZeroOrInvalidCount; ++ZeroOrInvalidCount;
IZ = IZ1; IZ = IZ1;
@@ -459,7 +459,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
BlockOrigin.X + X * Step, BlockOrigin.X + X * Step,
BlockOrigin.Y + Y * Step, BlockOrigin.Y + Y * Step,
BlockOrigin.Z + Z * Step); BlockOrigin.Z + Z * Step);
if (!FMath::IsFinite(Density) || Density == 0.0f) if (!VoxelMath::IsFinite(Density) || Density == 0.0f)
{ {
bAllSolid = false; bAllSolid = false;
bAllAir = false; bAllAir = false;
@@ -646,7 +646,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
{ {
const float Density = DensityGrid[ const float Density = DensityGrid[
((Z + 1) * MDim + (Y + 1)) * MDim + (X + 1)]; ((Z + 1) * MDim + (Y + 1)) * MDim + (X + 1)];
if (!FMath::IsFinite(Density) if (!VoxelMath::IsFinite(Density)
|| Density == 0.0f || Density == 0.0f
|| (Candidate == 1 ? Density >= 0.0f : Density <= 0.0f)) || (Candidate == 1 ? Density >= 0.0f : Density <= 0.0f))
{ {
+166 -166
View File
@@ -56,7 +56,7 @@ namespace
Result.bSurfaceRoughness = FParse::Value( Result.bSurfaceRoughness = FParse::Value(
*CommandLine, TEXT("voxel.surfaceroughness="), Result.SurfaceRoughness); *CommandLine, TEXT("voxel.surfaceroughness="), Result.SurfaceRoughness);
if (Result.bSurfaceRoughness if (Result.bSurfaceRoughness
&& (!FMath::IsFinite(Result.SurfaceRoughness) || Result.SurfaceRoughness < 0.0f)) && (!VoxelMath::IsFinite(Result.SurfaceRoughness) || Result.SurfaceRoughness < 0.0f))
{ {
Result.bSurfaceRoughness = false; Result.bSurfaceRoughness = false;
} }
@@ -64,7 +64,7 @@ namespace
Result.bFrequency = FParse::Value( Result.bFrequency = FParse::Value(
*CommandLine, TEXT("voxel.roughnessfrequency="), Result.Frequency); *CommandLine, TEXT("voxel.roughnessfrequency="), Result.Frequency);
if (Result.bFrequency if (Result.bFrequency
&& (!FMath::IsFinite(Result.Frequency) || Result.Frequency <= 0.0f)) && (!VoxelMath::IsFinite(Result.Frequency) || Result.Frequency <= 0.0f))
{ {
Result.bFrequency = false; Result.bFrequency = false;
} }
@@ -423,14 +423,14 @@ namespace
const FVoxelPassage& Passage, double X, double Y) const FVoxelPassage& Passage, double X, double Y)
{ {
if (!(Passage.NativeFloorReliefStrength > 0.0f) if (!(Passage.NativeFloorReliefStrength > 0.0f)
|| !FMath::IsFinite(Passage.NativeFloorReliefStrength) || !VoxelMath::IsFinite(Passage.NativeFloorReliefStrength)
|| !FMath::IsFinite(Passage.NativeFloorReliefFrequency) || !VoxelMath::IsFinite(Passage.NativeFloorReliefFrequency)
|| !(FMath::Abs(Passage.NativeFloorReliefFrequency) > KINDA_SMALL_NUMBER)) || !(FMath::Abs(Passage.NativeFloorReliefFrequency) > KINDA_SMALL_NUMBER))
{ {
return 0.0f; return 0.0f;
} }
const bool bInteger = FMath::IsFinite(X) && FMath::IsFinite(Y) const bool bInteger = VoxelMath::IsFinite(X) && VoxelMath::IsFinite(Y)
&& FMath::FloorToDouble(X) == X && FMath::FloorToDouble(Y) == Y && FMath::FloorToDouble(X) == X && FMath::FloorToDouble(Y) == Y
&& X >= static_cast<double>(MIN_int32) && X <= static_cast<double>(MAX_int32) && X >= static_cast<double>(MIN_int32) && X <= static_cast<double>(MAX_int32)
&& Y >= static_cast<double>(MIN_int32) && Y <= static_cast<double>(MAX_int32); && Y >= static_cast<double>(MIN_int32) && Y <= static_cast<double>(MAX_int32);
@@ -487,10 +487,10 @@ namespace
float Strength, float Frequency) float Strength, float Frequency)
{ {
if (!(Strength > 0.0f) if (!(Strength > 0.0f)
|| !FMath::IsFinite(Strength) || !VoxelMath::IsFinite(Strength)
|| !FMath::IsFinite(Frequency) || !VoxelMath::IsFinite(Frequency)
|| !(FMath::Abs(Frequency) > KINDA_SMALL_NUMBER) || !(FMath::Abs(Frequency) > KINDA_SMALL_NUMBER)
|| !FMath::IsFinite(BaseGradient) || !VoxelMath::IsFinite(BaseGradient)
|| BaseGradient < 0.0f) || BaseGradient < 0.0f)
{ {
return 0.0f; return 0.0f;
@@ -521,7 +521,7 @@ namespace
const float ReliefGradientBound = const float ReliefGradientBound =
NoiseGradientBound + EnvelopeDerivativeBound; NoiseGradientBound + EnvelopeDerivativeBound;
if (!(ReliefGradientBound > KINDA_SMALL_NUMBER) if (!(ReliefGradientBound > KINDA_SMALL_NUMBER)
|| !FMath::IsFinite(ReliefGradientBound) || !VoxelMath::IsFinite(ReliefGradientBound)
|| !(HorizontalRun > KINDA_SMALL_NUMBER)) || !(HorizontalRun > KINDA_SMALL_NUMBER))
{ {
return 0.0f; return 0.0f;
@@ -648,8 +648,8 @@ namespace
* VOXEL_NOISE_SCALE * Passage.NativeFloorReliefStrength * VOXEL_NOISE_SCALE * Passage.NativeFloorReliefStrength
* Envelope * ReliefScale; * Envelope * ReliefScale;
OutSupportRadius = BestSupportRadius; OutSupportRadius = BestSupportRadius;
return FMath::IsFinite(OutFloorZ) return VoxelMath::IsFinite(OutFloorZ)
&& FMath::IsFinite(OutSupportRadius) && VoxelMath::IsFinite(OutSupportRadius)
&& OutSupportRadius > 0.0f; && OutSupportRadius > 0.0f;
} }
@@ -784,7 +784,7 @@ static void VF_AuthorNativePassageFloor(
const float Radius = FMath::Abs(Passage.ControlRadii[PointIndex]); const float Radius = FMath::Abs(Passage.ControlRadii[PointIndex]);
const float FloorZ = VoxelPassageGeometry::TunnelFloorZ( const float FloorZ = VoxelPassageGeometry::TunnelFloorZ(
Passage.ControlPoints[PointIndex], Radius); Passage.ControlPoints[PointIndex], Radius);
if (!FMath::IsFinite(FloorZ)) if (!VoxelMath::IsFinite(FloorZ))
{ {
Passage.NativeFloorProfileZ.Reset(); Passage.NativeFloorProfileZ.Reset();
return; return;
@@ -1867,11 +1867,11 @@ void UVoxelStrateManager::GeneratePassages()
const float UpperSealThickness = BoundarySealThicknessFor(*UpperDef); const float UpperSealThickness = BoundarySealThicknessFor(*UpperDef);
const float InnerBottomZ = UpperBottomZ + UpperSealThickness; const float InnerBottomZ = UpperBottomZ + UpperSealThickness;
const float InnerTopZ = UpperTopZ - UpperSealThickness; const float InnerTopZ = UpperTopZ - UpperSealThickness;
if (FMath::IsFinite(SuggestedUpperPoint.X) if (VoxelMath::IsFinite(SuggestedUpperPoint.X)
&& FMath::IsFinite(SuggestedUpperPoint.Y) && VoxelMath::IsFinite(SuggestedUpperPoint.Y)
&& FMath::IsFinite(SuggestedUpperPoint.Z) && VoxelMath::IsFinite(SuggestedUpperPoint.Z)
&& FMath::IsFinite(InnerBottomZ) && VoxelMath::IsFinite(InnerBottomZ)
&& FMath::IsFinite(InnerTopZ) && VoxelMath::IsFinite(InnerTopZ)
&& InnerBottomZ < InnerTopZ) && InnerBottomZ < InnerTopZ)
{ {
// VF_SuggestLandingPoint already guarantees a strict interior answer. Keep a // VF_SuggestLandingPoint already guarantees a strict interior answer. Keep a
@@ -1894,11 +1894,11 @@ void UVoxelStrateManager::GeneratePassages()
const float LowerBottomZ = (float)(Lower.BottomChunkZ) * CHUNK_SIZE; const float LowerBottomZ = (float)(Lower.BottomChunkZ) * CHUNK_SIZE;
const float InnerBottomZ = LowerBottomZ + LowerSealThickness; const float InnerBottomZ = LowerBottomZ + LowerSealThickness;
const float InnerTopZ = LowerTopZ - LowerSealThickness; const float InnerTopZ = LowerTopZ - LowerSealThickness;
if (FMath::IsFinite(SuggestedLowerPoint.X) if (VoxelMath::IsFinite(SuggestedLowerPoint.X)
&& FMath::IsFinite(SuggestedLowerPoint.Y) && VoxelMath::IsFinite(SuggestedLowerPoint.Y)
&& FMath::IsFinite(SuggestedLowerPoint.Z) && VoxelMath::IsFinite(SuggestedLowerPoint.Z)
&& FMath::IsFinite(InnerBottomZ) && VoxelMath::IsFinite(InnerBottomZ)
&& FMath::IsFinite(InnerTopZ) && VoxelMath::IsFinite(InnerTopZ)
&& InnerBottomZ < InnerTopZ) && InnerBottomZ < InnerTopZ)
{ {
// VF_SuggestLandingPoint already guarantees a strict interior answer. Keep a // VF_SuggestLandingPoint already guarantees a strict interior answer. Keep a
@@ -2724,9 +2724,9 @@ void UVoxelStrateManager::ApplyPassageLandingFloorMC(
static bool VF_IsPassageRoomFloor( static bool VF_IsPassageRoomFloor(
const FVector& Position, const FVoxelPassageLanding& Landing) const FVector& Position, const FVoxelPassageLanding& Landing)
{ {
if (!FMath::IsFinite(Position.X) || !FMath::IsFinite(Position.Y) if (!VoxelMath::IsFinite(Position.X) || !VoxelMath::IsFinite(Position.Y)
|| !FMath::IsFinite(Position.Z) || !FMath::IsFinite(Landing.FloorZ) || !VoxelMath::IsFinite(Position.Z) || !VoxelMath::IsFinite(Landing.FloorZ)
|| !FMath::IsFinite(Landing.FloorThickness) || !VoxelMath::IsFinite(Landing.FloorThickness)
|| Landing.FloorThickness <= 0.0f || Landing.HalfWidth <= 0.0f) || Landing.FloorThickness <= 0.0f || Landing.HalfWidth <= 0.0f)
{ {
return false; return false;
@@ -3035,8 +3035,8 @@ namespace
float Min, float Max, float Origin, int32 Step, float Min, float Max, float Origin, int32 Step,
int32& OutFirst, int32& OutLast) int32& OutFirst, int32& OutLast)
{ {
if (Step <= 0 || !FMath::IsFinite(Min) || !FMath::IsFinite(Max) if (Step <= 0 || !VoxelMath::IsFinite(Min) || !VoxelMath::IsFinite(Max)
|| !FMath::IsFinite(Origin) || Min > Max) || !VoxelMath::IsFinite(Origin) || Min > Max)
{ {
return false; return false;
} }
@@ -3065,9 +3065,9 @@ namespace
auto AddDomain = [&](const FVector& Min, const FVector& Max) -> bool auto AddDomain = [&](const FVector& Min, const FVector& Max) -> bool
{ {
if (!FMath::IsFinite(Min.X) || !FMath::IsFinite(Min.Y) if (!VoxelMath::IsFinite(Min.X) || !VoxelMath::IsFinite(Min.Y)
|| !FMath::IsFinite(Min.Z) || !FMath::IsFinite(Max.X) || !VoxelMath::IsFinite(Min.Z) || !VoxelMath::IsFinite(Max.X)
|| !FMath::IsFinite(Max.Y) || !FMath::IsFinite(Max.Z) || !VoxelMath::IsFinite(Max.Y) || !VoxelMath::IsFinite(Max.Z)
|| Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z) || Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z)
{ {
return false; return false;
@@ -3078,11 +3078,11 @@ namespace
for (const FVoxelPassage& Passage : Passages) for (const FVoxelPassage& Passage : Passages)
{ {
if (!FMath::IsFinite(Passage.BoundCenter.X) if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y) || !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z) || !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius) || !VoxelMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq) || !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f) || Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{ {
// Invalid generated geometry is an unknown, not an empty passage set. // Invalid generated geometry is an unknown, not an empty passage set.
@@ -3096,7 +3096,7 @@ namespace
return false; return false;
} }
const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num(); const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num();
if (!bTaper && !FMath::IsFinite(Passage.Radius)) if (!bTaper && !VoxelMath::IsFinite(Passage.Radius))
{ {
return false; return false;
} }
@@ -3104,12 +3104,12 @@ namespace
PointIndex < Passage.ControlPoints.Num(); ++PointIndex) PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{ {
const FVector& Point = Passage.ControlPoints[PointIndex]; const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y) if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z)) || !VoxelMath::IsFinite(Point.Z))
{ {
return false; return false;
} }
if (bTaper && !FMath::IsFinite(Passage.ControlRadii[PointIndex])) if (bTaper && !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex]))
{ {
return false; return false;
} }
@@ -3125,7 +3125,7 @@ namespace
const float RadiusB = bTaper const float RadiusB = bTaper
? Passage.ControlRadii[SegmentIndex + 1] : Passage.Radius; ? Passage.ControlRadii[SegmentIndex + 1] : Passage.Radius;
const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB)); const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB));
if (!FMath::IsFinite(Radius)) if (!VoxelMath::IsFinite(Radius))
{ {
return false; return false;
} }
@@ -3143,13 +3143,13 @@ namespace
} }
else else
{ {
if (!FMath::IsFinite(Passage.UpperPoint.X) if (!VoxelMath::IsFinite(Passage.UpperPoint.X)
|| !FMath::IsFinite(Passage.UpperPoint.Y) || !VoxelMath::IsFinite(Passage.UpperPoint.Y)
|| !FMath::IsFinite(Passage.UpperPoint.Z) || !VoxelMath::IsFinite(Passage.UpperPoint.Z)
|| !FMath::IsFinite(Passage.LowerPoint.X) || !VoxelMath::IsFinite(Passage.LowerPoint.X)
|| !FMath::IsFinite(Passage.LowerPoint.Y) || !VoxelMath::IsFinite(Passage.LowerPoint.Y)
|| !FMath::IsFinite(Passage.LowerPoint.Z) || !VoxelMath::IsFinite(Passage.LowerPoint.Z)
|| !FMath::IsFinite(Passage.Radius)) || !VoxelMath::IsFinite(Passage.Radius))
{ {
return false; return false;
} }
@@ -3170,11 +3170,11 @@ namespace
&Passage.UpperLanding, &Passage.LowerLanding }; &Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings) for (const FVoxelPassageLanding* Landing : Landings)
{ {
if (!FMath::IsFinite(Landing->StandingPoint.X) if (!VoxelMath::IsFinite(Landing->StandingPoint.X)
|| !FMath::IsFinite(Landing->StandingPoint.Y) || !VoxelMath::IsFinite(Landing->StandingPoint.Y)
|| !FMath::IsFinite(Landing->FloorZ) || !VoxelMath::IsFinite(Landing->FloorZ)
|| !FMath::IsFinite(Landing->CeilingZ) || !VoxelMath::IsFinite(Landing->CeilingZ)
|| !FMath::IsFinite(Landing->HalfWidth)) || !VoxelMath::IsFinite(Landing->HalfWidth))
{ {
// The canonical evaluator returns FLT_MAX for this landing. Treating it as // The canonical evaluator returns FLT_MAX for this landing. Treating it as
// unknown is safer for future evaluator changes and only gives up a skip. // unknown is safer for future evaluator changes and only gives up a skip.
@@ -3238,7 +3238,7 @@ namespace
const float SmoothDip = static_cast<float>(DomainCount - 1) const float SmoothDip = static_cast<float>(DomainCount - 1)
* (SmoothMinK / 6.0f); * (SmoothMinK / 6.0f);
const float Padding = CarveThreshold + SmoothDip; const float Padding = CarveThreshold + SmoothDip;
if (!FMath::IsFinite(Padding) || Padding < 0.0f) if (!VoxelMath::IsFinite(Padding) || Padding < 0.0f)
{ {
return true; return true;
} }
@@ -3273,8 +3273,8 @@ namespace
const TArray<FVoxelPassage>& Passages, const TArray<FVoxelPassage>& Passages,
const FVector& Position) const FVector& Position)
{ {
if (!FMath::IsFinite(Position.X) || !FMath::IsFinite(Position.Y) if (!VoxelMath::IsFinite(Position.X) || !VoxelMath::IsFinite(Position.Y)
|| !FMath::IsFinite(Position.Z)) || !VoxelMath::IsFinite(Position.Z))
{ {
return true; return true;
} }
@@ -3285,11 +3285,11 @@ namespace
float ModifierLowerBound = FLT_MAX; float ModifierLowerBound = FLT_MAX;
for (const FVoxelPassage& Passage : Passages) for (const FVoxelPassage& Passage : Passages)
{ {
if (!FMath::IsFinite(Passage.BoundCenter.X) if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y) || !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z) || !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius) || !VoxelMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq) || !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f) || Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{ {
return true; return true;
@@ -3307,7 +3307,7 @@ namespace
return true; return true;
} }
const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num(); const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num();
if (!bTaper && !FMath::IsFinite(Passage.Radius)) if (!bTaper && !VoxelMath::IsFinite(Passage.Radius))
{ {
return true; return true;
} }
@@ -3315,12 +3315,12 @@ namespace
PointIndex < Passage.ControlPoints.Num(); ++PointIndex) PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{ {
const FVector& Point = Passage.ControlPoints[PointIndex]; const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y) if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z)) || !VoxelMath::IsFinite(Point.Z))
{ {
return true; return true;
} }
if (bTaper && !FMath::IsFinite(Passage.ControlRadii[PointIndex])) if (bTaper && !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex]))
{ {
return true; return true;
} }
@@ -3337,7 +3337,7 @@ namespace
const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB)); const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB));
const float SegmentLowerBound = VF_DistanceToSegmentLowerBound( const float SegmentLowerBound = VF_DistanceToSegmentLowerBound(
Position, A, B, Radius); Position, A, B, Radius);
if (!FMath::IsFinite(SegmentLowerBound)) if (!VoxelMath::IsFinite(SegmentLowerBound))
{ {
return true; return true;
} }
@@ -3347,20 +3347,20 @@ namespace
} }
else else
{ {
if (!FMath::IsFinite(Passage.UpperPoint.X) if (!VoxelMath::IsFinite(Passage.UpperPoint.X)
|| !FMath::IsFinite(Passage.UpperPoint.Y) || !VoxelMath::IsFinite(Passage.UpperPoint.Y)
|| !FMath::IsFinite(Passage.UpperPoint.Z) || !VoxelMath::IsFinite(Passage.UpperPoint.Z)
|| !FMath::IsFinite(Passage.LowerPoint.X) || !VoxelMath::IsFinite(Passage.LowerPoint.X)
|| !FMath::IsFinite(Passage.LowerPoint.Y) || !VoxelMath::IsFinite(Passage.LowerPoint.Y)
|| !FMath::IsFinite(Passage.LowerPoint.Z) || !VoxelMath::IsFinite(Passage.LowerPoint.Z)
|| !FMath::IsFinite(Passage.Radius)) || !VoxelMath::IsFinite(Passage.Radius))
{ {
return true; return true;
} }
PassageLowerBound = VF_DistanceToSegmentLowerBound( PassageLowerBound = VF_DistanceToSegmentLowerBound(
Position, Passage.UpperPoint, Passage.LowerPoint, Position, Passage.UpperPoint, Passage.LowerPoint,
FMath::Abs(Passage.Radius)); FMath::Abs(Passage.Radius));
if (!FMath::IsFinite(PassageLowerBound)) if (!VoxelMath::IsFinite(PassageLowerBound))
{ {
return true; return true;
} }
@@ -3370,11 +3370,11 @@ namespace
&Passage.UpperLanding, &Passage.LowerLanding }; &Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings) for (const FVoxelPassageLanding* Landing : Landings)
{ {
if (!FMath::IsFinite(Landing->StandingPoint.X) if (!VoxelMath::IsFinite(Landing->StandingPoint.X)
|| !FMath::IsFinite(Landing->StandingPoint.Y) || !VoxelMath::IsFinite(Landing->StandingPoint.Y)
|| !FMath::IsFinite(Landing->FloorZ) || !VoxelMath::IsFinite(Landing->FloorZ)
|| !FMath::IsFinite(Landing->CeilingZ) || !VoxelMath::IsFinite(Landing->CeilingZ)
|| !FMath::IsFinite(Landing->HalfWidth)) || !VoxelMath::IsFinite(Landing->HalfWidth))
{ {
return true; return true;
} }
@@ -3384,7 +3384,7 @@ namespace
continue; continue;
} }
const float LandingSDF = VF_EvaluatePassageLandingSDF(Position, *Landing); const float LandingSDF = VF_EvaluatePassageLandingSDF(Position, *Landing);
if (!FMath::IsFinite(LandingSDF)) if (!VoxelMath::IsFinite(LandingSDF))
{ {
return true; return true;
} }
@@ -3395,7 +3395,7 @@ namespace
ModifierLowerBound = VoxelSDF::SmoothMin( ModifierLowerBound = VoxelSDF::SmoothMin(
ModifierLowerBound, PassageLowerBound, BlendK); ModifierLowerBound, PassageLowerBound, BlendK);
} }
return !FMath::IsFinite(ModifierLowerBound) return !VoxelMath::IsFinite(ModifierLowerBound)
|| ModifierLowerBound < CarveThreshold + NumericalSafetyMargin; || ModifierLowerBound < CarveThreshold + NumericalSafetyMargin;
} }
@@ -3419,8 +3419,8 @@ namespace
static bool VF_SegmentDistanceToBox( static bool VF_SegmentDistanceToBox(
const FVector& A, const FVector& B, const FBox& Box, float& OutDistance) const FVector& A, const FVector& B, const FBox& Box, float& OutDistance)
{ {
if (!FMath::IsFinite(A.X) || !FMath::IsFinite(A.Y) || !FMath::IsFinite(A.Z) if (!VoxelMath::IsFinite(A.X) || !VoxelMath::IsFinite(A.Y) || !VoxelMath::IsFinite(A.Z)
|| !FMath::IsFinite(B.X) || !FMath::IsFinite(B.Y) || !FMath::IsFinite(B.Z) || !VoxelMath::IsFinite(B.X) || !VoxelMath::IsFinite(B.Y) || !VoxelMath::IsFinite(B.Z)
|| !Box.IsValid) || !Box.IsValid)
{ {
return false; return false;
@@ -3508,22 +3508,22 @@ namespace
MinimumDistanceSquared = FMath::Min( MinimumDistanceSquared = FMath::Min(
MinimumDistanceSquared, DistanceSquared); MinimumDistanceSquared, DistanceSquared);
} }
if (!FMath::IsFinite(MinimumDistanceSquared)) if (!VoxelMath::IsFinite(MinimumDistanceSquared))
{ {
return false; return false;
} }
OutDistance = FMath::Sqrt(MinimumDistanceSquared); OutDistance = FMath::Sqrt(MinimumDistanceSquared);
return FMath::IsFinite(OutDistance); return VoxelMath::IsFinite(OutDistance);
} }
static bool VF_LandingLowerBoundOverBox( static bool VF_LandingLowerBoundOverBox(
const FVoxelPassageLanding& Landing, const FBox& Box, float& OutLowerBound) const FVoxelPassageLanding& Landing, const FBox& Box, float& OutLowerBound)
{ {
if (!FMath::IsFinite(Landing.StandingPoint.X) if (!VoxelMath::IsFinite(Landing.StandingPoint.X)
|| !FMath::IsFinite(Landing.StandingPoint.Y) || !VoxelMath::IsFinite(Landing.StandingPoint.Y)
|| !FMath::IsFinite(Landing.FloorZ) || !VoxelMath::IsFinite(Landing.FloorZ)
|| !FMath::IsFinite(Landing.CeilingZ) || !VoxelMath::IsFinite(Landing.CeilingZ)
|| !FMath::IsFinite(Landing.HalfWidth) || !VoxelMath::IsFinite(Landing.HalfWidth)
|| !Box.IsValid) || !Box.IsValid)
{ {
return false; return false;
@@ -3555,7 +3555,7 @@ namespace
FMath::Max(HalfExtent.Y, HalfExtent.Z)) - RoomRounding; FMath::Max(HalfExtent.Y, HalfExtent.Z)) - RoomRounding;
OutLowerBound = FMath::Max( OutLowerBound = FMath::Max(
RoundedBoxLower, Landing.FloorZ - (float)Box.Max.Z); RoundedBoxLower, Landing.FloorZ - (float)Box.Max.Z);
return FMath::IsFinite(OutLowerBound); return VoxelMath::IsFinite(OutLowerBound);
} }
static bool VF_PassageModifierLowerBoundOverBox( static bool VF_PassageModifierLowerBoundOverBox(
@@ -3573,11 +3573,11 @@ namespace
const FVector BoxMax((float)Box.Max.X, (float)Box.Max.Y, (float)Box.Max.Z); const FVector BoxMax((float)Box.Max.X, (float)Box.Max.Y, (float)Box.Max.Z);
for (const FVoxelPassage& Passage : Passages) for (const FVoxelPassage& Passage : Passages)
{ {
if (!FMath::IsFinite(Passage.BoundCenter.X) if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y) || !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z) || !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius) || !VoxelMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq) || !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f) || Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{ {
return false; return false;
@@ -3600,7 +3600,7 @@ namespace
return false; return false;
} }
const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num(); const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num();
if (!bTaper && !FMath::IsFinite(Passage.Radius)) if (!bTaper && !VoxelMath::IsFinite(Passage.Radius))
{ {
return false; return false;
} }
@@ -3608,9 +3608,9 @@ namespace
PointIndex < Passage.ControlPoints.Num(); ++PointIndex) PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{ {
const FVector& Point = Passage.ControlPoints[PointIndex]; const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y) if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z) || !VoxelMath::IsFinite(Point.Z)
|| (bTaper && !FMath::IsFinite(Passage.ControlRadii[PointIndex]))) || (bTaper && !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex])))
{ {
return false; return false;
} }
@@ -3624,7 +3624,7 @@ namespace
? Passage.ControlRadii[SegmentIndex + 1] : Passage.Radius; ? Passage.ControlRadii[SegmentIndex + 1] : Passage.Radius;
const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB)); const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB));
float SegmentDistance = 0.0f; float SegmentDistance = 0.0f;
if (!FMath::IsFinite(Radius) if (!VoxelMath::IsFinite(Radius)
|| !VF_SegmentDistanceToBox( || !VF_SegmentDistanceToBox(
Passage.ControlPoints[SegmentIndex], Passage.ControlPoints[SegmentIndex],
Passage.ControlPoints[SegmentIndex + 1], Box, SegmentDistance)) Passage.ControlPoints[SegmentIndex + 1], Box, SegmentDistance))
@@ -3637,13 +3637,13 @@ namespace
} }
else else
{ {
if (!FMath::IsFinite(Passage.UpperPoint.X) if (!VoxelMath::IsFinite(Passage.UpperPoint.X)
|| !FMath::IsFinite(Passage.UpperPoint.Y) || !VoxelMath::IsFinite(Passage.UpperPoint.Y)
|| !FMath::IsFinite(Passage.UpperPoint.Z) || !VoxelMath::IsFinite(Passage.UpperPoint.Z)
|| !FMath::IsFinite(Passage.LowerPoint.X) || !VoxelMath::IsFinite(Passage.LowerPoint.X)
|| !FMath::IsFinite(Passage.LowerPoint.Y) || !VoxelMath::IsFinite(Passage.LowerPoint.Y)
|| !FMath::IsFinite(Passage.LowerPoint.Z) || !VoxelMath::IsFinite(Passage.LowerPoint.Z)
|| !FMath::IsFinite(Passage.Radius)) || !VoxelMath::IsFinite(Passage.Radius))
{ {
return false; return false;
} }
@@ -3673,7 +3673,7 @@ namespace
ModifierLowerBound, PassageLowerBound, BlendK); ModifierLowerBound, PassageLowerBound, BlendK);
} }
OutLowerBound = ModifierLowerBound; OutLowerBound = ModifierLowerBound;
return FMath::IsFinite(OutLowerBound); return VoxelMath::IsFinite(OutLowerBound);
} }
// MaxPassageCarveFactorNearLattice is queried once for the root and once for every refined // MaxPassageCarveFactorNearLattice is queried once for the root and once for every refined
@@ -3819,7 +3819,7 @@ bool UVoxelStrateManager::AnyPassageNearLattice(
VoxelBox, LatticeOrigin, Step); VoxelBox, LatticeOrigin, Step);
// Invalid input deliberately returns 1.0 from the exact helper. A non-finite result is also // Invalid input deliberately returns 1.0 from the exact helper. A non-finite result is also
// retained as a candidate rather than becoming an identity proof. // retained as a candidate rather than becoming an identity proof.
return !FMath::IsFinite(MaxFactor) || MaxFactor > 0.0f; return !VoxelMath::IsFinite(MaxFactor) || MaxFactor > 0.0f;
} }
bool UVoxelStrateManager::AnyPassageAirPostNearLattice( bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
@@ -3835,8 +3835,8 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
{ {
return true; return true;
} }
if (!FMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f) if (!VoxelMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f)
|| !FMath::IsFinite(SealThickness) || SealThickness < 0.0f) || !VoxelMath::IsFinite(SealThickness) || SealThickness < 0.0f)
{ {
return true; return true;
} }
@@ -3887,9 +3887,9 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
PointIndex < Passage.ControlPoints.Num(); ++PointIndex) PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{ {
const FVector& Point = Passage.ControlPoints[PointIndex]; const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y) if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z) || !VoxelMath::IsFinite(Point.Z)
|| !FMath::IsFinite(Passage.ControlRadii[PointIndex])) || !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex]))
{ {
return true; return true;
} }
@@ -3952,9 +3952,9 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
float MinX, float MaxX, float MinY, float MaxY, float MinX, float MaxX, float MinY, float MaxY,
float MinZ, float MaxZ, bool& bTouches) -> bool float MinZ, float MaxZ, bool& bTouches) -> bool
{ {
if (!FMath::IsFinite(MinX) || !FMath::IsFinite(MaxX) if (!VoxelMath::IsFinite(MinX) || !VoxelMath::IsFinite(MaxX)
|| !FMath::IsFinite(MinY) || !FMath::IsFinite(MaxY) || !VoxelMath::IsFinite(MinY) || !VoxelMath::IsFinite(MaxY)
|| !FMath::IsFinite(MinZ) || !FMath::IsFinite(MaxZ) || !VoxelMath::IsFinite(MinZ) || !VoxelMath::IsFinite(MaxZ)
|| MinX > MaxX || MinY > MaxY || MinZ > MaxZ) || MinX > MaxX || MinY > MaxY || MinZ > MaxZ)
{ {
return false; return false;
@@ -3980,11 +3980,11 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
for (int32 PassageIndex = 0; PassageIndex < Passages.Num(); ++PassageIndex) for (int32 PassageIndex = 0; PassageIndex < Passages.Num(); ++PassageIndex)
{ {
const FVoxelPassage& Passage = Passages[PassageIndex]; const FVoxelPassage& Passage = Passages[PassageIndex];
if (!FMath::IsFinite(Passage.BoundCenter.X) if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y) || !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z) || !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius) || !VoxelMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq) || !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f) || Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{ {
return true; return true;
@@ -4002,11 +4002,11 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
// not part of this validity check: the landing-air writer reads the SDF fields even // not part of this validity check: the landing-air writer reads the SDF fields even
// when a separate floor descriptor is degenerate. // when a separate floor descriptor is degenerate.
const bool bLandingSdfValid = const bool bLandingSdfValid =
FMath::IsFinite(Landing->StandingPoint.X) VoxelMath::IsFinite(Landing->StandingPoint.X)
&& FMath::IsFinite(Landing->StandingPoint.Y) && VoxelMath::IsFinite(Landing->StandingPoint.Y)
&& FMath::IsFinite(Landing->FloorZ) && VoxelMath::IsFinite(Landing->FloorZ)
&& FMath::IsFinite(Landing->CeilingZ) && VoxelMath::IsFinite(Landing->CeilingZ)
&& FMath::IsFinite(Landing->HalfWidth) && VoxelMath::IsFinite(Landing->HalfWidth)
&& Landing->HalfWidth > 0.0f && Landing->HalfWidth > 0.0f
&& Landing->CeilingZ > Landing->FloorZ; && Landing->CeilingZ > Landing->FloorZ;
if (bLandingSdfValid) if (bLandingSdfValid)
@@ -4065,7 +4065,7 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
} }
const float AirTarget = -(BaseDensity * 2.0f + SealThickness + 4.0f); const float AirTarget = -(BaseDensity * 2.0f + SealThickness + 4.0f);
if (!FMath::IsFinite(AirTarget)) if (!VoxelMath::IsFinite(AirTarget))
{ {
return true; return true;
} }
@@ -4111,7 +4111,7 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
Position, Passage.UpperLanding); Position, Passage.UpperLanding);
const float LowerSDF = VF_EvaluatePassageLandingSDF( const float LowerSDF = VF_EvaluatePassageLandingSDF(
Position, Passage.LowerLanding); Position, Passage.LowerLanding);
if (!FMath::IsFinite(UpperSDF) || !FMath::IsFinite(LowerSDF)) if (!VoxelMath::IsFinite(UpperSDF) || !VoxelMath::IsFinite(LowerSDF))
{ {
// A malformed landing is an unknown post, never an identity proof. // A malformed landing is an unknown post, never an identity proof.
return true; return true;
@@ -4134,7 +4134,7 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
CarveFactor = SmoothStep01(CarveFactor); CarveFactor = SmoothStep01(CarveFactor);
const float LandingThreshold = FMath::Lerp( const float LandingThreshold = FMath::Lerp(
BaseDensity, AirTarget, CarveFactor); BaseDensity, AirTarget, CarveFactor);
if (!FMath::IsFinite(LandingThreshold) if (!VoxelMath::IsFinite(LandingThreshold)
|| LandingThreshold <= 0.0f) || LandingThreshold <= 0.0f)
{ {
// Zero is not solid under the mesher's sign convention, so it is part of // Zero is not solid under the mesher's sign convention, so it is part of
@@ -4219,7 +4219,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
* (SmoothMinK / 6.0f); * (SmoothMinK / 6.0f);
const float Padding = PassageCarveThreshold + SmoothDip; const float Padding = PassageCarveThreshold + SmoothDip;
ModifierDomainPadding = Padding; ModifierDomainPadding = Padding;
if (!FMath::IsFinite(Padding) || Padding < 0.0f) if (!VoxelMath::IsFinite(Padding) || Padding < 0.0f)
{ {
bKnownModifierDomains = false; bKnownModifierDomains = false;
} }
@@ -4323,7 +4323,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
return; return;
} }
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z); const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
const float CarveFactor = FMath::IsFinite(ModifierSDF) const float CarveFactor = VoxelMath::IsFinite(ModifierSDF)
? CarveFactorFromSDF(ModifierSDF) : 1.0f; ? CarveFactorFromSDF(ModifierSDF) : 1.0f;
Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor; Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor;
MaxCarveFactor = FMath::Max(MaxCarveFactor, CarveFactor); MaxCarveFactor = FMath::Max(MaxCarveFactor, CarveFactor);
@@ -4421,9 +4421,9 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
CandidateMaxZ = FMath::Max(CandidateMaxZ, CandidateMaxZ = FMath::Max(CandidateMaxZ,
Domain.Max.Z + ModifierDomainPadding); Domain.Max.Z + ModifierDomainPadding);
} }
if (!FMath::IsFinite(CandidateMinX) || !FMath::IsFinite(CandidateMinY) if (!VoxelMath::IsFinite(CandidateMinX) || !VoxelMath::IsFinite(CandidateMinY)
|| !FMath::IsFinite(CandidateMinZ) || !FMath::IsFinite(CandidateMaxX) || !VoxelMath::IsFinite(CandidateMinZ) || !VoxelMath::IsFinite(CandidateMaxX)
|| !FMath::IsFinite(CandidateMaxY) || !FMath::IsFinite(CandidateMaxZ)) || !VoxelMath::IsFinite(CandidateMaxY) || !VoxelMath::IsFinite(CandidateMaxZ))
{ {
bKnownModifierDomains = false; bKnownModifierDomains = false;
} }
@@ -4486,7 +4486,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
if (MayEvaluatePoint(Position)) if (MayEvaluatePoint(Position))
{ {
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z); const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
CarveFactor = FMath::IsFinite(ModifierSDF) CarveFactor = VoxelMath::IsFinite(ModifierSDF)
? CarveFactorFromSDF(ModifierSDF) : 1.0f; ? CarveFactorFromSDF(ModifierSDF) : 1.0f;
} }
Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor; Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor;
@@ -4517,7 +4517,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
{ {
const float RemainingSDF = EvaluateModifierSDF( const float RemainingSDF = EvaluateModifierSDF(
RemainingWorldX, RemainingWorldY, RemainingWorldZ); RemainingWorldX, RemainingWorldY, RemainingWorldZ);
RemainingFactor = FMath::IsFinite(RemainingSDF) RemainingFactor = VoxelMath::IsFinite(RemainingSDF)
? CarveFactorFromSDF(RemainingSDF) : 1.0f; ? CarveFactorFromSDF(RemainingSDF) : 1.0f;
} }
Cache.Factors[Cache.Index(RemainingX, RemainingY, RemainingZ)] = Cache.Factors[Cache.Index(RemainingX, RemainingY, RemainingZ)] =
@@ -4552,7 +4552,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
continue; continue;
} }
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z); const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
if (!FMath::IsFinite(ModifierSDF)) if (!VoxelMath::IsFinite(ModifierSDF))
{ {
return 1.0f; return 1.0f;
} }
@@ -4581,11 +4581,11 @@ bool UVoxelStrateManager::AnyPassageLandingFloorNearLattice(
&Passage.UpperLanding, &Passage.LowerLanding }; &Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings) for (const FVoxelPassageLanding* Landing : Landings)
{ {
if (!FMath::IsFinite(Landing->StandingPoint.X) if (!VoxelMath::IsFinite(Landing->StandingPoint.X)
|| !FMath::IsFinite(Landing->StandingPoint.Y) || !VoxelMath::IsFinite(Landing->StandingPoint.Y)
|| !FMath::IsFinite(Landing->FloorZ) || !VoxelMath::IsFinite(Landing->FloorZ)
|| !FMath::IsFinite(Landing->HalfWidth) || !VoxelMath::IsFinite(Landing->HalfWidth)
|| !FMath::IsFinite(Landing->FloorThickness)) || !VoxelMath::IsFinite(Landing->FloorThickness))
{ {
return true; return true;
} }
@@ -4620,11 +4620,11 @@ bool UVoxelStrateManager::AnyPassageLandingFloorNearLattice(
{ {
const FVector& A = Passage.ControlPoints[SegmentIndex]; const FVector& A = Passage.ControlPoints[SegmentIndex];
const FVector& B = Passage.ControlPoints[SegmentIndex + 1]; const FVector& B = Passage.ControlPoints[SegmentIndex + 1];
if (!FMath::IsFinite(A.X) || !FMath::IsFinite(A.Y) if (!VoxelMath::IsFinite(A.X) || !VoxelMath::IsFinite(A.Y)
|| !FMath::IsFinite(A.Z) || !FMath::IsFinite(B.X) || !VoxelMath::IsFinite(A.Z) || !VoxelMath::IsFinite(B.X)
|| !FMath::IsFinite(B.Y) || !FMath::IsFinite(B.Z) || !VoxelMath::IsFinite(B.Y) || !VoxelMath::IsFinite(B.Z)
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex]) || !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex])
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1])) || !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1]))
{ {
return true; return true;
} }
@@ -4696,11 +4696,11 @@ bool UVoxelStrateManager::AnyLandingFloorAtLattice(
auto HasAnyLandingSample = [&](const FVoxelPassageLanding& Landing) -> bool auto HasAnyLandingSample = [&](const FVoxelPassageLanding& Landing) -> bool
{ {
if (!FMath::IsFinite(Landing.StandingPoint.X) if (!VoxelMath::IsFinite(Landing.StandingPoint.X)
|| !FMath::IsFinite(Landing.StandingPoint.Y) || !VoxelMath::IsFinite(Landing.StandingPoint.Y)
|| !FMath::IsFinite(Landing.FloorZ) || !VoxelMath::IsFinite(Landing.FloorZ)
|| !FMath::IsFinite(Landing.HalfWidth) || !VoxelMath::IsFinite(Landing.HalfWidth)
|| !FMath::IsFinite(Landing.FloorThickness) || !VoxelMath::IsFinite(Landing.FloorThickness)
|| Landing.HalfWidth <= 0.0f || Landing.FloorThickness <= 0.0f) || Landing.HalfWidth <= 0.0f || Landing.FloorThickness <= 0.0f)
{ {
// This function gates an AllAir proof. Invalid authored floor data is an unknown // This function gates an AllAir proof. Invalid authored floor data is an unknown
@@ -4755,11 +4755,11 @@ bool UVoxelStrateManager::AnyLandingFloorAtLattice(
{ {
const FVector& A = Passage.ControlPoints[SegmentIndex]; const FVector& A = Passage.ControlPoints[SegmentIndex];
const FVector& B = Passage.ControlPoints[SegmentIndex + 1]; const FVector& B = Passage.ControlPoints[SegmentIndex + 1];
if (!FMath::IsFinite(A.X) || !FMath::IsFinite(A.Y) if (!VoxelMath::IsFinite(A.X) || !VoxelMath::IsFinite(A.Y)
|| !FMath::IsFinite(A.Z) || !FMath::IsFinite(B.X) || !VoxelMath::IsFinite(A.Z) || !VoxelMath::IsFinite(B.X)
|| !FMath::IsFinite(B.Y) || !FMath::IsFinite(B.Z) || !VoxelMath::IsFinite(B.Y) || !VoxelMath::IsFinite(B.Z)
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex]) || !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex])
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1])) || !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1]))
{ {
return true; return true;
} }
@@ -4779,9 +4779,9 @@ bool UVoxelStrateManager::AnyLandingFloorAtLattice(
const float MinZ = FMath::Min(FloorA, FloorB) const float MinZ = FMath::Min(FloorA, FloorB)
- VoxelPassageGeometry::LandingFloorThicknessVoxels - Pad; - VoxelPassageGeometry::LandingFloorThicknessVoxels - Pad;
const float MaxZ = FMath::Max(FloorA, FloorB) + Pad; const float MaxZ = FMath::Max(FloorA, FloorB) + Pad;
if (!FMath::IsFinite(MinX) || !FMath::IsFinite(MaxX) if (!VoxelMath::IsFinite(MinX) || !VoxelMath::IsFinite(MaxX)
|| !FMath::IsFinite(MinY) || !FMath::IsFinite(MaxY) || !VoxelMath::IsFinite(MinY) || !VoxelMath::IsFinite(MaxY)
|| !FMath::IsFinite(MinZ) || !FMath::IsFinite(MaxZ)) || !VoxelMath::IsFinite(MinZ) || !VoxelMath::IsFinite(MaxZ))
{ {
return true; return true;
} }
@@ -4926,13 +4926,13 @@ bool UVoxelStrateManager::AnyOriginLandingAirNearLattice(
{ {
return true; return true;
} }
if (!FMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f) if (!VoxelMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f)
|| !FMath::IsFinite(SealThickness) || SealThickness < 0.0f) || !VoxelMath::IsFinite(SealThickness) || SealThickness < 0.0f)
{ {
return true; return true;
} }
const float AirTarget = -(BaseDensity * 2.0f + SealThickness + 4.0f); const float AirTarget = -(BaseDensity * 2.0f + SealThickness + 4.0f);
if (!FMath::IsFinite(AirTarget)) if (!VoxelMath::IsFinite(AirTarget))
{ {
return true; return true;
} }
@@ -4989,7 +4989,7 @@ bool UVoxelStrateManager::AnyOriginLandingAirNearLattice(
(float)LatticeOrigin.Z + (float)(IZ * Step)); (float)LatticeOrigin.Z + (float)(IZ * Step));
const float RoomSDF = VoxelPassageGeometry::OriginLandingRoomSDF( const float RoomSDF = VoxelPassageGeometry::OriginLandingRoomSDF(
Position, Geometry); Position, Geometry);
if (!FMath::IsFinite(RoomSDF)) if (!VoxelMath::IsFinite(RoomSDF))
{ {
return true; return true;
} }
@@ -5002,7 +5002,7 @@ bool UVoxelStrateManager::AnyOriginLandingAirNearLattice(
CarveFactor = SmoothStep01(CarveFactor); CarveFactor = SmoothStep01(CarveFactor);
const float LandingThreshold = FMath::Lerp( const float LandingThreshold = FMath::Lerp(
BaseDensity, AirTarget, CarveFactor); BaseDensity, AirTarget, CarveFactor);
if (!FMath::IsFinite(LandingThreshold) if (!VoxelMath::IsFinite(LandingThreshold)
|| LandingThreshold <= 0.0f) || LandingThreshold <= 0.0f)
{ {
return true; return true;
+5 -5
View File
@@ -436,7 +436,7 @@ namespace
++OutMismatches; ++OutMismatches;
} }
const float Delta = (FMath::IsFinite(Live) && FMath::IsFinite(Reference)) const float Delta = (VoxelMath::IsFinite(Live) && VoxelMath::IsFinite(Reference))
? FMath::Abs(Live - Reference) : FLT_MAX; ? FMath::Abs(Live - Reference) : FLT_MAX;
OutMaxDelta = FMath::Max(OutMaxDelta, Delta); OutMaxDelta = FMath::Max(OutMaxDelta, Delta);
++OutSamples; ++OutSamples;
@@ -1720,8 +1720,8 @@ bool AVoxelWorld::TryGetPlayerPosition(FVector& OutPosition, APawn** OutPawn) co
} }
const FVector Position = Pawn->GetActorLocation(); const FVector Position = Pawn->GetActorLocation();
if (!FMath::IsFinite(Position.X) || !FMath::IsFinite(Position.Y) if (!VoxelMath::IsFinite(Position.X) || !VoxelMath::IsFinite(Position.Y)
|| !FMath::IsFinite(Position.Z)) || !VoxelMath::IsFinite(Position.Z))
{ {
return false; return false;
} }
@@ -1766,7 +1766,7 @@ bool AVoxelWorld::GetPlayerSupportTile(APawn* Pawn, const FVector& PlayerPositio
Pawn->GetActorBounds(/*bOnlyCollidingComponents*/ true, BoundsOrigin, BoundsExtent); Pawn->GetActorBounds(/*bOnlyCollidingComponents*/ true, BoundsOrigin, BoundsExtent);
HalfHeightCm = FMath::Max(0.0f, BoundsExtent.Z); HalfHeightCm = FMath::Max(0.0f, BoundsExtent.Z);
} }
if (!FMath::IsFinite(HalfHeightCm)) if (!VoxelMath::IsFinite(HalfHeightCm))
{ {
return false; return false;
} }
@@ -4060,7 +4060,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector
OriginVoxels.Y + Y * ValidationStep, OriginVoxels.Y + Y * ValidationStep,
OriginVoxels.Z + Z * ValidationStep); OriginVoxels.Z + Z * ValidationStep);
++Result.ValidationDensityCalls; ++Result.ValidationDensityCalls;
const bool bSampleAgrees = FMath::IsFinite(Density) && Density != 0.0f const bool bSampleAgrees = VoxelMath::IsFinite(Density) && Density != 0.0f
&& (Verdict != EVoxelTileClass::AllSolid || Density < 0.0f) && (Verdict != EVoxelTileClass::AllSolid || Density < 0.0f)
&& (Verdict != EVoxelTileClass::AllAir || Density > 0.0f); && (Verdict != EVoxelTileClass::AllAir || Density > 0.0f);
if (!bSampleAgrees) if (!bSampleAgrees)
+1 -1
View File
@@ -415,7 +415,7 @@ struct FVoxelBoxSdfInterval
void Set(float InMin, float InMax) void Set(float InMin, float InMax)
{ {
if (!FMath::IsFinite(InMin) || !FMath::IsFinite(InMax) || InMin > InMax) if (!VoxelMath::IsFinite(InMin) || !VoxelMath::IsFinite(InMax) || InMin > InMax)
{ {
SetUnknown(); SetUnknown();
return; return;
@@ -222,9 +222,9 @@ FORCEINLINE void VF_ApplyXYEdgeSeal(float& Density, float WorldX, float WorldY,
float WorldRadiusVoxels, float Thickness, float BaseDensity) float WorldRadiusVoxels, float Thickness, float BaseDensity)
{ {
if (!(WorldRadiusVoxels > 0.0f) || !(Thickness > 0.0f) || !(BaseDensity > 0.0f)) return; if (!(WorldRadiusVoxels > 0.0f) || !(Thickness > 0.0f) || !(BaseDensity > 0.0f)) return;
if (!FMath::IsFinite(WorldX) || !FMath::IsFinite(WorldY) if (!VoxelMath::IsFinite(WorldX) || !VoxelMath::IsFinite(WorldY)
|| !FMath::IsFinite(WorldRadiusVoxels) || !FMath::IsFinite(Thickness) || !VoxelMath::IsFinite(WorldRadiusVoxels) || !VoxelMath::IsFinite(Thickness)
|| !FMath::IsFinite(BaseDensity)) return; || !VoxelMath::IsFinite(BaseDensity)) return;
const float InnerRadius = WorldRadiusVoxels - Thickness; const float InnerRadius = WorldRadiusVoxels - Thickness;
const float InnerRadiusSq = InnerRadius * InnerRadius; const float InnerRadiusSq = InnerRadius * InnerRadius;
@@ -282,10 +282,10 @@ FORCEINLINE bool VF_IsValidXYEdgeSealProofInput(const FBox& VoxelBox,
float WorldRadiusVoxels, float Thickness, float BaseDensity) float WorldRadiusVoxels, float Thickness, float BaseDensity)
{ {
return VoxelBox.IsValid return VoxelBox.IsValid
&& FMath::IsFinite(VoxelBox.Min.X) && FMath::IsFinite(VoxelBox.Min.Y) && VoxelMath::IsFinite(VoxelBox.Min.X) && VoxelMath::IsFinite(VoxelBox.Min.Y)
&& FMath::IsFinite(VoxelBox.Max.X) && FMath::IsFinite(VoxelBox.Max.Y) && VoxelMath::IsFinite(VoxelBox.Max.X) && VoxelMath::IsFinite(VoxelBox.Max.Y)
&& FMath::IsFinite(WorldRadiusVoxels) && FMath::IsFinite(Thickness) && VoxelMath::IsFinite(WorldRadiusVoxels) && VoxelMath::IsFinite(Thickness)
&& FMath::IsFinite(BaseDensity) && VoxelMath::IsFinite(BaseDensity)
&& WorldRadiusVoxels > 0.0f && Thickness > 0.0f && BaseDensity > 0.0f; && WorldRadiusVoxels > 0.0f && Thickness > 0.0f && BaseDensity > 0.0f;
} }
@@ -344,7 +344,7 @@ FORCEINLINE bool VF_XYEdgeSealBoxTouchesBand(const FBox& VoxelBox,
float WorldRadiusVoxels, float Thickness) float WorldRadiusVoxels, float Thickness)
{ {
if (!(WorldRadiusVoxels > 0.0f) || !(Thickness > 0.0f) if (!(WorldRadiusVoxels > 0.0f) || !(Thickness > 0.0f)
|| !FMath::IsFinite(WorldRadiusVoxels) || !FMath::IsFinite(Thickness)) return false; || !VoxelMath::IsFinite(WorldRadiusVoxels) || !VoxelMath::IsFinite(Thickness)) return false;
const float InnerRadius = WorldRadiusVoxels - Thickness; const float InnerRadius = WorldRadiusVoxels - Thickness;
return VF_XYEdgeFarthestRadiusSq(VoxelBox) > InnerRadius * InnerRadius; return VF_XYEdgeFarthestRadiusSq(VoxelBox) > InnerRadius * InnerRadius;
+33 -32
View File
@@ -7,6 +7,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "VoxelTypes.h"
namespace VoxelPassageGeometry namespace VoxelPassageGeometry
{ {
@@ -85,13 +86,13 @@ namespace VoxelPassageGeometry
+ FloorThickness + SealSafetyMarginVoxels; + FloorThickness + SealSafetyMarginVoxels;
const float MaximumFloor = InteriorTopZ const float MaximumFloor = InteriorTopZ
- PlayerHeightVoxels - SealSafetyMarginVoxels; - PlayerHeightVoxels - SealSafetyMarginVoxels;
if (!FMath::IsFinite(StrateBottomZ) if (!VoxelMath::IsFinite(StrateBottomZ)
|| !FMath::IsFinite(InteriorBottomZ) || !VoxelMath::IsFinite(InteriorBottomZ)
|| !FMath::IsFinite(InteriorTopZ) || !VoxelMath::IsFinite(InteriorTopZ)
|| !FMath::IsFinite(LedgeSpacing) || !VoxelMath::IsFinite(LedgeSpacing)
|| !FMath::IsFinite(LedgeDepth) || !VoxelMath::IsFinite(LedgeDepth)
|| !FMath::IsFinite(MinimumFloor) || !VoxelMath::IsFinite(MinimumFloor)
|| !FMath::IsFinite(MaximumFloor) || !VoxelMath::IsFinite(MaximumFloor)
|| !(MaximumFloor > MinimumFloor)) || !(MaximumFloor > MinimumFloor))
{ {
return 0.5f * (InteriorBottomZ + InteriorTopZ); return 0.5f * (InteriorBottomZ + InteriorTopZ);
@@ -153,12 +154,12 @@ namespace VoxelPassageGeometry
const float FloorRadius = FMath::Max(0.5f, SafeRadius - 0.5f); const float FloorRadius = FMath::Max(0.5f, SafeRadius - 0.5f);
if (!(SafeRadius > 0.0f) if (!(SafeRadius > 0.0f)
|| !(BaseDensity > 0.0f) || !(BaseDensity > 0.0f)
|| !FMath::IsFinite(WorldX) || !VoxelMath::IsFinite(WorldX)
|| !FMath::IsFinite(WorldY) || !VoxelMath::IsFinite(WorldY)
|| !FMath::IsFinite(WorldZ) || !VoxelMath::IsFinite(WorldZ)
|| !FMath::IsFinite(FloorZ) || !VoxelMath::IsFinite(FloorZ)
|| !FMath::IsFinite(Start.X) || !FMath::IsFinite(Start.Y) || !VoxelMath::IsFinite(Start.X) || !VoxelMath::IsFinite(Start.Y)
|| !FMath::IsFinite(End.X) || !FMath::IsFinite(End.Y)) || !VoxelMath::IsFinite(End.X) || !VoxelMath::IsFinite(End.Y))
{ {
return; return;
} }
@@ -218,14 +219,14 @@ namespace VoxelPassageGeometry
const float CoreRadius = FMath::Max(0.5f, SafeRadius - 1.0f); const float CoreRadius = FMath::Max(0.5f, SafeRadius - 1.0f);
if (!(SafeRadius > 0.0f) if (!(SafeRadius > 0.0f)
|| !(BaseDensity > 0.0f) || !(BaseDensity > 0.0f)
|| !FMath::IsFinite(WorldX) || !VoxelMath::IsFinite(WorldX)
|| !FMath::IsFinite(WorldY) || !VoxelMath::IsFinite(WorldY)
|| !FMath::IsFinite(WorldZ) || !VoxelMath::IsFinite(WorldZ)
|| !FMath::IsFinite(FloorZ) || !VoxelMath::IsFinite(FloorZ)
|| !FMath::IsFinite(Start.X) || !FMath::IsFinite(Start.Y) || !VoxelMath::IsFinite(Start.X) || !VoxelMath::IsFinite(Start.Y)
|| !FMath::IsFinite(Start.Z) || !VoxelMath::IsFinite(Start.Z)
|| !FMath::IsFinite(End.X) || !FMath::IsFinite(End.Y) || !VoxelMath::IsFinite(End.X) || !VoxelMath::IsFinite(End.Y)
|| !FMath::IsFinite(End.Z)) || !VoxelMath::IsFinite(End.Z))
{ {
return; return;
} }
@@ -360,8 +361,8 @@ namespace VoxelPassageGeometry
} }
return bFoundSegment return bFoundSegment
&& FMath::IsFinite(OutFloorZ) && VoxelMath::IsFinite(OutFloorZ)
&& FMath::IsFinite(OutSupportRadius) && VoxelMath::IsFinite(OutSupportRadius)
&& OutSupportRadius > 0.0f && OutSupportRadius > 0.0f
&& BestDistanceSquared <= FMath::Square(OutSupportRadius); && BestDistanceSquared <= FMath::Square(OutSupportRadius);
} }
@@ -405,10 +406,10 @@ namespace VoxelPassageGeometry
{ {
FOriginLandingGeometry Result; FOriginLandingGeometry Result;
if (!(OriginRadius > 0.0f) if (!(OriginRadius > 0.0f)
|| !FMath::IsFinite(StrateTopZ) || !VoxelMath::IsFinite(StrateTopZ)
|| !FMath::IsFinite(StrateBottomZ) || !VoxelMath::IsFinite(StrateBottomZ)
|| !FMath::IsFinite(SealThickness) || !VoxelMath::IsFinite(SealThickness)
|| !FMath::IsFinite(OriginRadius)) || !VoxelMath::IsFinite(OriginRadius))
{ {
return Result; return Result;
} }
@@ -429,10 +430,10 @@ namespace VoxelPassageGeometry
+ Result.FloorThickness + SealSafetyMarginVoxels; + Result.FloorThickness + SealSafetyMarginVoxels;
const float MaximumFloor = InnerTop const float MaximumFloor = InnerTop
- DesiredHeight - SealSafetyMarginVoxels; - DesiredHeight - SealSafetyMarginVoxels;
if (!FMath::IsFinite(InnerBottom) || !FMath::IsFinite(InnerTop) if (!VoxelMath::IsFinite(InnerBottom) || !VoxelMath::IsFinite(InnerTop)
|| !(InnerTop > InnerBottom) || !(InnerTop > InnerBottom)
|| !FMath::IsFinite(MinimumFloor) || !VoxelMath::IsFinite(MinimumFloor)
|| !FMath::IsFinite(MaximumFloor) || !VoxelMath::IsFinite(MaximumFloor)
|| MaximumFloor < MinimumFloor) || MaximumFloor < MinimumFloor)
{ {
Result.HalfWidth = 0.0f; Result.HalfWidth = 0.0f;
@@ -455,8 +456,8 @@ namespace VoxelPassageGeometry
FORCEINLINE bool LatticeAxisHasSampleInInterval( FORCEINLINE bool LatticeAxisHasSampleInInterval(
float Min, float Max, float Origin, int32 Step) float Min, float Max, float Origin, int32 Step)
{ {
if (Step <= 0 || !FMath::IsFinite(Min) || !FMath::IsFinite(Max) if (Step <= 0 || !VoxelMath::IsFinite(Min) || !VoxelMath::IsFinite(Max)
|| !FMath::IsFinite(Origin) || Min > Max) || !VoxelMath::IsFinite(Origin) || Min > Max)
{ {
return false; return false;
} }
+45
View File
@@ -8,6 +8,51 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
//=============================================================================
// EXACT FINITE PREDICATE / PREDICAT FINI EXACT
//=============================================================================
// The CRT-backed FMath::IsFinite is an out-of-line call on the MSVC game path. A finite
// IEEE-754 value is identified entirely by its exponent bits, so this helper has the same
// boolean result for every bit pattern without doing a floating-point comparison.
namespace VoxelMath
{
// Runtime policy switch. The fast helper below is deliberately independent of this value so
// the equivalence test can compare it directly with FMath::IsFinite. IsFinite() is the A/B
// entry point used by generation code.
VOXELFORGE_API extern int32 GFastIsFinite;
FORCEINLINE bool IsFiniteFast(float Value)
{
static_assert(sizeof(float) == sizeof(uint32), "VoxelMath::IsFiniteFast requires IEEE float");
uint32 Bits = 0;
FMemory::Memcpy(&Bits, &Value, sizeof(Bits));
constexpr uint32 ExponentMask = 0x7F800000u;
return (Bits & ExponentMask) != ExponentMask;
}
FORCEINLINE bool IsFiniteFast(double Value)
{
static_assert(sizeof(double) == sizeof(uint64), "VoxelMath::IsFiniteFast requires IEEE double");
uint64 Bits = 0;
FMemory::Memcpy(&Bits, &Value, sizeof(Bits));
constexpr uint64 ExponentMask = 0x7FF0000000000000ull;
return (Bits & ExponentMask) != ExponentMask;
}
// Keep the switch at the call site while keeping the exact bit test separate and directly
// testable. In the default-on game path this inlines to the bit load/mask/branch; the 0 path
// is retained for within-round performance and sampler A/B runs.
FORCEINLINE bool IsFinite(float Value)
{
return GFastIsFinite != 0 ? IsFiniteFast(Value) : FMath::IsFinite(Value);
}
FORCEINLINE bool IsFinite(double Value)
{
return GFastIsFinite != 0 ? IsFiniteFast(Value) : FMath::IsFinite(Value);
}
}
//============================================================================= //=============================================================================
// CHUNK CONSTANTS // CHUNK CONSTANTS
//============================================================================= //=============================================================================