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(
const FVector3f& InMin, const FVector3f& InMax)
{
if (!FMath::IsFinite(InMin.X) || !FMath::IsFinite(InMin.Y)
|| !FMath::IsFinite(InMin.Z) || !FMath::IsFinite(InMax.X)
|| !FMath::IsFinite(InMax.Y) || !FMath::IsFinite(InMax.Z)
if (!VoxelMath::IsFinite(InMin.X) || !VoxelMath::IsFinite(InMin.Y)
|| !VoxelMath::IsFinite(InMin.Z) || !VoxelMath::IsFinite(InMax.X)
|| !VoxelMath::IsFinite(InMax.Y) || !VoxelMath::IsFinite(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.Y) > 1000000.0f || FMath::Abs(InMax.Y) > 1000000.0f
@@ -279,7 +279,7 @@ namespace
ValueMax += Contribution.Max;
}
if (!FMath::IsFinite(ValueMin) || !FMath::IsFinite(ValueMax))
if (!VoxelMath::IsFinite(ValueMin) || !VoxelMath::IsFinite(ValueMax))
{
return VF_PerlinAbsBound;
}
@@ -420,8 +420,8 @@ namespace
FORCEINLINE float VF_LatticeAxisDistanceToPoint(
float BoxMin, float BoxMax, float Origin, float Step, float Target, float Extra)
{
if (!(Step > 0.0f) || !FMath::IsFinite(BoxMin) || !FMath::IsFinite(BoxMax)
|| !FMath::IsFinite(Origin) || !FMath::IsFinite(Target)
if (!(Step > 0.0f) || !VoxelMath::IsFinite(BoxMin) || !VoxelMath::IsFinite(BoxMax)
|| !VoxelMath::IsFinite(Origin) || !VoxelMath::IsFinite(Target)
|| BoxMin > BoxMax)
{
return FLT_MAX;
@@ -451,7 +451,7 @@ namespace
float BoxMin, float BoxMax, float Origin, float Step,
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)
{
return FLT_MAX;
@@ -483,7 +483,7 @@ namespace
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; }
return A + B;
@@ -603,7 +603,7 @@ namespace
void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox&,
const FVoxelOpContext&) const override
{
if (!FMath::IsFinite(CellSize) || !FMath::IsFinite(CorridorRadius)
if (!VoxelMath::IsFinite(CellSize) || !VoxelMath::IsFinite(CorridorRadius)
|| CellSize <= 0.0f || CorridorRadius < 0.0f)
{
InOut.SetUnknown();
@@ -1575,8 +1575,8 @@ namespace
const FVoxelOpContext&) const override
{
if (!InOut.IsKnown()) { return; }
if (!FMath::IsFinite(Strength) || !FMath::IsFinite(Frequency)
|| !FMath::IsFinite(ApplyWithin) || BaseOctaves <= 0)
if (!VoxelMath::IsFinite(Strength) || !VoxelMath::IsFinite(Frequency)
|| !VoxelMath::IsFinite(ApplyWithin) || BaseOctaves <= 0)
{
InOut.SetUnknown();
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.Y), FMath::Abs((float)VoxelBox.Max.Y)),
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();
return;
@@ -1806,8 +1806,8 @@ namespace
EVoxelOpEffect EffectOverBox(const FBox&, const FVoxelOpContext&) const override
{
const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient) || !FMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f)
if (!VoxelMath::IsFinite(Coefficient) || !VoxelMath::IsFinite(Blend)
|| !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{
return EVoxelOpEffect::Both;
}
@@ -1831,8 +1831,8 @@ namespace
float MaxCarveOverBox(const FBox&, const FVoxelOpContext&) const override
{
const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient) || !FMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f)
if (!VoxelMath::IsFinite(Coefficient) || !VoxelMath::IsFinite(Blend)
|| !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{
return FLT_MAX;
}
@@ -1842,8 +1842,8 @@ namespace
float MaxFillOverBox(const FBox&, const FVoxelOpContext&) const override
{
const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient) || !FMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f)
if (!VoxelMath::IsFinite(Coefficient) || !VoxelMath::IsFinite(Blend)
|| !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{
return FLT_MAX;
}
@@ -1854,8 +1854,8 @@ namespace
const FVoxelBoxHypotheses& H) const override
{
const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient)) { return FLT_MAX; }
if (!FMath::IsFinite(Blend) || !FMath::IsFinite(MinDivisor) || Blend <= 0.0f)
if (!VoxelMath::IsFinite(Coefficient)) { return FLT_MAX; }
if (!VoxelMath::IsFinite(Blend) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{
return FLT_MAX;
}
@@ -1867,8 +1867,8 @@ namespace
const FVoxelBoxHypotheses& H) const override
{
const float Coefficient = Sign * BaseDensity * 2.0f;
if (!FMath::IsFinite(Coefficient)) { return FLT_MAX; }
if (!FMath::IsFinite(Blend) || !FMath::IsFinite(MinDivisor) || Blend <= 0.0f)
if (!VoxelMath::IsFinite(Coefficient)) { return FLT_MAX; }
if (!VoxelMath::IsFinite(Blend) || !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{
return FLT_MAX;
}
@@ -1891,14 +1891,14 @@ namespace
float MaxFactor(const FVoxelBoxHypotheses& H) const
{
if (!H.Sdf.IsKnown() || !FMath::IsFinite(Blend)
|| !FMath::IsFinite(MinDivisor) || Blend <= 0.0f)
if (!H.Sdf.IsKnown() || !VoxelMath::IsFinite(Blend)
|| !VoxelMath::IsFinite(MinDivisor) || Blend <= 0.0f)
{
return 1.0f;
}
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);
return SmoothStep01(T);
@@ -2223,18 +2223,18 @@ namespace
const float MaxFactor = LiveManager->MaxPassageCarveFactorNearLattice(
VoxelBox, Ctx.LatticeOriginVoxels, Ctx.Step);
if (!(MaxFactor > 0.0f)) { return 0.0f; }
if (!(H.SolidMargin > 0.0f) || !FMath::IsFinite(H.SolidMargin)
|| !FMath::IsFinite(Base) || !FMath::IsFinite(Seal))
if (!(H.SolidMargin > 0.0f) || !VoxelMath::IsFinite(H.SolidMargin)
|| !VoxelMath::IsFinite(Base) || !VoxelMath::IsFinite(Seal))
{
return FLT_MAX;
}
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(
H.SolidMargin,
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);
}
@@ -2355,13 +2355,13 @@ namespace
void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox& VoxelBox,
const FVoxelOpContext&) const override
{
if (!FMath::IsFinite((float)VoxelBox.Min.X) || !FMath::IsFinite((float)VoxelBox.Min.Y)
|| !FMath::IsFinite((float)VoxelBox.Min.Z)
|| !FMath::IsFinite((float)VoxelBox.Max.X) || !FMath::IsFinite((float)VoxelBox.Max.Y)
|| !FMath::IsFinite((float)VoxelBox.Max.Z)
if (!VoxelMath::IsFinite((float)VoxelBox.Min.X) || !VoxelMath::IsFinite((float)VoxelBox.Min.Y)
|| !VoxelMath::IsFinite((float)VoxelBox.Min.Z)
|| !VoxelMath::IsFinite((float)VoxelBox.Max.X) || !VoxelMath::IsFinite((float)VoxelBox.Max.Y)
|| !VoxelMath::IsFinite((float)VoxelBox.Max.Z)
|| VoxelBox.Min.X > VoxelBox.Max.X || VoxelBox.Min.Y > VoxelBox.Max.Y
|| VoxelBox.Min.Z > VoxelBox.Max.Z
|| !FMath::IsFinite(P.ShaftSpacing) || P.ShaftSpacing <= 0.0f)
|| !VoxelMath::IsFinite(P.ShaftSpacing) || P.ShaftSpacing <= 0.0f)
{
InOut.SetUnknown();
return;
@@ -3021,16 +3021,16 @@ namespace
void PropagateSdfOverBox(FVoxelBoxSdfInterval& InOut, const FBox& VoxelBox,
const FVoxelOpContext&) const override
{
if (!FMath::IsFinite((float)VoxelBox.Min.X) || !FMath::IsFinite((float)VoxelBox.Min.Y)
|| !FMath::IsFinite((float)VoxelBox.Min.Z)
|| !FMath::IsFinite((float)VoxelBox.Max.X) || !FMath::IsFinite((float)VoxelBox.Max.Y)
|| !FMath::IsFinite((float)VoxelBox.Max.Z)
if (!VoxelMath::IsFinite((float)VoxelBox.Min.X) || !VoxelMath::IsFinite((float)VoxelBox.Min.Y)
|| !VoxelMath::IsFinite((float)VoxelBox.Min.Z)
|| !VoxelMath::IsFinite((float)VoxelBox.Max.X) || !VoxelMath::IsFinite((float)VoxelBox.Max.Y)
|| !VoxelMath::IsFinite((float)VoxelBox.Max.Z)
|| VoxelBox.Min.X > VoxelBox.Max.X || VoxelBox.Min.Y > VoxelBox.Max.Y
|| VoxelBox.Min.Z > VoxelBox.Max.Z
|| !FMath::IsFinite(P.IslandSpacing) || !FMath::IsFinite(P.IslandDensity)
|| !FMath::IsFinite(P.IslandMinRadius) || !FMath::IsFinite(P.IslandMaxRadius)
|| !FMath::IsFinite(P.ThicknessRatio) || !FMath::IsFinite(P.VerticalJitter)
|| !FMath::IsFinite(P.TopFlatten) || !FMath::IsFinite(P.SDFBlendRadius)
|| !VoxelMath::IsFinite(P.IslandSpacing) || !VoxelMath::IsFinite(P.IslandDensity)
|| !VoxelMath::IsFinite(P.IslandMinRadius) || !VoxelMath::IsFinite(P.IslandMaxRadius)
|| !VoxelMath::IsFinite(P.ThicknessRatio) || !VoxelMath::IsFinite(P.VerticalJitter)
|| !VoxelMath::IsFinite(P.TopFlatten) || !VoxelMath::IsFinite(P.SDFBlendRadius)
|| P.IslandDensity < 0.0f)
{
InOut.SetUnknown();
@@ -4389,7 +4389,7 @@ namespace
{
const float StructuralFloorMinimumDensity =
FMath::Max(P.BaseDensity * 2.0f, 1.0f);
if (FMath::IsFinite(StructuralFloorMinimumDensity)
if (VoxelMath::IsFinite(StructuralFloorMinimumDensity)
&& StructuralFloorMinimumDensity > 0.0f)
{
InOut.bProtectedStructuralFloor = true;
@@ -4629,7 +4629,7 @@ namespace
float Supremum = 0.0f;
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
// declared FillOnly direction, so the state-aware caller must fall back to
@@ -4637,7 +4637,7 @@ namespace
return FLT_MAX;
}
const float Contribution = Column.BaseDensity * 1.5f;
if (!FMath::IsFinite(Contribution)
if (!VoxelMath::IsFinite(Contribution)
|| Supremum > FLT_MAX - Contribution)
{
return FLT_MAX;
@@ -4658,13 +4658,13 @@ namespace
// room wins the nearest-SDF query, and is finite without assuming a global room height.
float Supremum = 0.0f;
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)
{
const float CenterZ = static_cast<float>(Room.Center.Z);
const float RadiusZ = Room.RadiusZ;
if (!FMath::IsFinite(CenterZ) || !FMath::IsFinite(RadiusZ)
|| !FMath::IsFinite(P.FloorBias) || P.FloorBias < 0.0f)
if (!VoxelMath::IsFinite(CenterZ) || !VoxelMath::IsFinite(RadiusZ)
|| !VoxelMath::IsFinite(P.FloorBias) || P.FloorBias < 0.0f)
{
return FLT_MAX;
}
@@ -4672,7 +4672,7 @@ namespace
const float Below = FMath::Max(CenterZ - BoxMinZ, 0.0f);
const float Normalized = Below / Denominator;
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);
}
return Supremum;
@@ -4745,7 +4745,7 @@ namespace
B.SdfInterval.SetUnknown();
InOut.SetUnknown();
};
auto Finite = [](float V) { return FMath::IsFinite(V); };
auto Finite = [](float V) { return VoxelMath::IsFinite(V); };
if (ManagerLifetimeId != 0 && LiveManager == nullptr)
{
@@ -6262,7 +6262,7 @@ namespace
};
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;
const float ThresholdWithBlend = VF_SaturatingAdd(WormThreshold, K);
float Lower = FLT_MAX;
@@ -6803,7 +6803,7 @@ namespace
static_cast<float>(World.Z), GetBoxCache(), SupportColumn,
VoxelGenLOD::ShouldUseSpatialIndex(false));
++B.ExactTailEvaluated;
if (!FMath::IsFinite(Evaluation.SDF))
if (!VoxelMath::IsFinite(Evaluation.SDF))
{
bExactTailUnknown = true;
if (CachedTailState != nullptr) { *CachedTailState = 0x84u; }
@@ -6941,7 +6941,7 @@ namespace
FORCEINLINE bool VF_CaveBoxIsFar(const FVoxelBoxHypotheses& H, float SDFBlendRadius)
{
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,
@@ -7179,7 +7179,7 @@ namespace
float MaxAmplitude() const
{
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;
switch (P.RoughnessNoiseType)
@@ -7200,14 +7200,14 @@ namespace
}
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:
bool IsInactiveFromSdf(const FVoxelBoxHypotheses& H) const
{
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;
}
@@ -7215,7 +7215,7 @@ namespace
// 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
// 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;
}
@@ -7372,8 +7372,8 @@ namespace
float MaxAmplitude() const
{
return (P.TerraceStepHeight > 0.0f
&& FMath::IsFinite(P.TerraceStepHeight)
&& FMath::IsFinite(P.TerraceHardness)
&& VoxelMath::IsFinite(P.TerraceStepHeight)
&& VoxelMath::IsFinite(P.TerraceHardness)
&& P.TerraceHardness >= 0.0f && P.TerraceHardness <= 1.0f)
? P.TerraceStepHeight : (P.TerraceStepHeight > 0.0f ? FLT_MAX : 0.0f);
}
@@ -7473,7 +7473,7 @@ namespace
float MaxAmplitude() const
{
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;
}
@@ -7571,7 +7571,7 @@ namespace
float MaxAmplitude() const
{
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;
}
@@ -7675,14 +7675,14 @@ namespace
float MaxAmplitude() const
{
if (!(P.OverhangStrength > 0.0f && P.OverhangDepth > 0.0f)) { return 0.0f; }
if (!FMath::IsFinite(P.OverhangDepth)
|| !FMath::IsFinite(P.OverhangStrength))
if (!VoxelMath::IsFinite(P.OverhangDepth)
|| !VoxelMath::IsFinite(P.OverhangStrength))
{
return FLT_MAX;
}
const float Result = VOXEL_NOISE_SCALE * VF_PerlinAbsBound
* P.OverhangDepth * P.OverhangStrength;
return FMath::IsFinite(Result) ? Result : FLT_MAX;
return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
}
private:
@@ -7801,10 +7801,10 @@ namespace
float MaxAmplitude() const
{
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
* VF_PerlinAbsBound * P.CliffStrength;
return FMath::IsFinite(Result) ? Result : FLT_MAX;
return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
}
private:
@@ -7908,9 +7908,9 @@ namespace
float MaxAmplitude() const
{
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;
return FMath::IsFinite(Result) ? Result : FLT_MAX;
return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
}
private:
@@ -8037,9 +8037,9 @@ namespace
float MaxAmplitude() const
{
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;
return FMath::IsFinite(Result) ? Result : FLT_MAX;
return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
}
private:
@@ -8130,7 +8130,7 @@ namespace
}
const float Bound = Rooms->RoomColumnFillSupremumForLastBox();
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; }
@@ -8145,7 +8145,7 @@ namespace
{
if (Rooms == nullptr || VF_CaveBoxIsFar(H, P.SDFBlendRadius)) { return 0.0f; }
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&,
@@ -8293,9 +8293,9 @@ namespace
float MaxAmplitude() const
{
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;
return FMath::IsFinite(Result) ? Result : FLT_MAX;
return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
}
private:
@@ -8415,9 +8415,9 @@ namespace
float MaxAmplitude() const
{
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;
return FMath::IsFinite(Result) ? Result : FLT_MAX;
return VoxelMath::IsFinite(Result) ? Result : FLT_MAX;
}
private:
@@ -8504,7 +8504,7 @@ namespace
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);
}
@@ -8646,12 +8646,12 @@ namespace
const FVoxelBoxHypotheses& H) const override
{
const float Strength = MaxCarveOverBox(VoxelBox, Ctx);
if (!(Strength > 0.0f) || !FMath::IsFinite(Strength))
if (!(Strength > 0.0f) || !VoxelMath::IsFinite(Strength))
{
return Strength;
}
if (!(P.WormNetworkRange > 0.0f) || !FMath::IsFinite(P.WormNetworkRange)
|| !H.Sdf.IsKnown() || !FMath::IsFinite(H.Sdf.Min))
if (!(P.WormNetworkRange > 0.0f) || !VoxelMath::IsFinite(P.WormNetworkRange)
|| !H.Sdf.IsKnown() || !VoxelMath::IsFinite(H.Sdf.Min))
{
return Strength;
}
@@ -8664,11 +8664,11 @@ namespace
// interval's worst case, so this never assumes a room value that the preceding source
// did not prove.
if (Ctx.bUseLatticeProof && Ctx.bTightenWarpProof && Ctx.Step >= 1
&& FMath::IsFinite(P.WormFrequency)
&& FMath::IsFinite(P.WormHorizontalBias)
&& FMath::IsFinite(P.WormThreshold)
&& VoxelMath::IsFinite(P.WormFrequency)
&& VoxelMath::IsFinite(P.WormHorizontalBias)
&& VoxelMath::IsFinite(P.WormThreshold)
&& P.WormThreshold > 0.0f
&& FMath::IsFinite(P.VerticalScale))
&& VoxelMath::IsFinite(P.VerticalScale))
{
const int32 Step = FMath::Max(Ctx.Step, 1);
const float OriginX = static_cast<float>(Ctx.LatticeOriginVoxels.X);
@@ -8774,7 +8774,7 @@ namespace
float MaxCarveAmplitude() const
{
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"); }
@@ -9200,7 +9200,7 @@ void FVoxelOpStack::DiagnoseBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx
Entry.Op->Eval(static_cast<float>(X), static_cast<float>(Y),
static_cast<float>(Z), Sample);
const float DensityDelta = Sample.Density - DensityBefore;
if (FMath::IsFinite(DensityDelta))
if (VoxelMath::IsFinite(DensityDelta))
{
Diagnostic.bHasDensityDelta = true;
Diagnostic.ActualDensityDeltaMin =
@@ -9219,12 +9219,12 @@ void FVoxelOpStack::DiagnoseBox(const FBox& VoxelBox, const FVoxelOpContext& Ctx
* FMath::Max(1.0f, FMath::Abs(Diagnostic.MaxCarve));
const float FillEpsilon = BoundEpsilon
* FMath::Max(1.0f, FMath::Abs(Diagnostic.MaxFill));
if (FMath::IsFinite(Diagnostic.MaxCarve)
if (VoxelMath::IsFinite(Diagnostic.MaxCarve)
&& DensityDelta < -Diagnostic.MaxCarve - CarveEpsilon)
{
Diagnostic.bCarveBoundViolated = true;
}
if (FMath::IsFinite(Diagnostic.MaxFill)
if (VoxelMath::IsFinite(Diagnostic.MaxFill)
&& DensityDelta > Diagnostic.MaxFill + FillEpsilon)
{
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.ActualSdfMin = FMath::Min(
@@ -10338,8 +10338,8 @@ bool VF_BuildStackFromRecipe(const FVoxelOpStackRecipe& Recipe,
const float Bottom = VoxelStrateRecipePrivate::Bottom(Params, Recipe.StructuralParamBlock);
const float Seal = VoxelStrateRecipePrivate::BoundarySeal(Params, Recipe.StructuralParamBlock);
const float Base = VoxelStrateRecipePrivate::BaseDensity(Params, Recipe.StructuralParamBlock);
if (!FMath::IsFinite(Top) || !FMath::IsFinite(Bottom) || Top <= Bottom
|| !FMath::IsFinite(Seal) || !FMath::IsFinite(Base))
if (!VoxelMath::IsFinite(Top) || !VoxelMath::IsFinite(Bottom) || Top <= Bottom
|| !VoxelMath::IsFinite(Seal) || !VoxelMath::IsFinite(Base))
{
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);
float Base = Manifest.bHasGlobalStructuralParams
? Manifest.BaseDensity : VF_RegionBase(FirstParams, GlobalBlock);
if (!FMath::IsFinite(Top) || !FMath::IsFinite(Bottom) || !(Top > Bottom)
|| !FMath::IsFinite(Seal) || Seal < 0.0f
|| !FMath::IsFinite(Base) || !(Base > 0.0f))
if (!VoxelMath::IsFinite(Top) || !VoxelMath::IsFinite(Bottom) || !(Top > Bottom)
|| !VoxelMath::IsFinite(Seal) || Seal < 0.0f
|| !VoxelMath::IsFinite(Base) || !(Base > 0.0f))
{
return Fail(TEXT("lateral region structural parameters are not a finite positive strate"));
}
+55 -24
View File
@@ -29,8 +29,37 @@
#include <atomic>
namespace VoxelMath
{
VOXELFORGE_API int32 GFastIsFinite = 1;
}
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
// 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.
@@ -861,7 +890,7 @@ static FORCEINLINE bool VF_DisturbanceBandTouchesBox(
{
const float InnerTop = D.StrateTopWorldZ - 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.
}
@@ -929,16 +958,16 @@ static bool VF_AnyChasmCanTouchLattice(
{
return false;
}
if (!FMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f
|| D.ChasmDensity > 1.0f || !FMath::IsFinite(D.ChasmSpacing)
|| !FMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f
if (!VoxelMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f
|| D.ChasmDensity > 1.0f || !VoxelMath::IsFinite(D.ChasmSpacing)
|| !VoxelMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f
|| D.ChasmRadius < 0.0f)
{
return true;
}
const float InnerTop = D.StrateTopWorldZ - 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;
}
@@ -987,16 +1016,16 @@ static bool VF_AnyBridgeCanTouchLattice(
{
return false;
}
if (!FMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f
|| D.BridgeDensity > 1.0f || !FMath::IsFinite(D.BridgeSpacing)
|| !FMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f
if (!VoxelMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f
|| D.BridgeDensity > 1.0f || !VoxelMath::IsFinite(D.BridgeSpacing)
|| !VoxelMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f
|| D.BridgeRadius < 0.0f)
{
return true;
}
const float InnerTop = D.StrateTopWorldZ - 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;
}
@@ -1055,16 +1084,16 @@ static bool VF_AnyRidgeCanTouchLattice(
{
return false;
}
if (!FMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f
|| D.RidgeDensity > 1.0f || !FMath::IsFinite(D.RidgeSpacing)
|| !FMath::IsFinite(D.RidgeHeight) || !FMath::IsFinite(D.RidgeThickness)
if (!VoxelMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f
|| D.RidgeDensity > 1.0f || !VoxelMath::IsFinite(D.RidgeSpacing)
|| !VoxelMath::IsFinite(D.RidgeHeight) || !VoxelMath::IsFinite(D.RidgeThickness)
|| D.RidgeSpacing <= 0.0f || D.RidgeHeight <= 0.0f || D.RidgeThickness < 0.0f)
{
return true;
}
const float InnerTop = D.StrateTopWorldZ - 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;
}
@@ -1124,9 +1153,9 @@ static bool VF_AnyChasmCanTouchBox(
{
return false;
}
if (!FMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f
|| D.ChasmDensity > 1.0f || !FMath::IsFinite(D.ChasmSpacing)
|| !FMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f
if (!VoxelMath::IsFinite(D.ChasmDensity) || D.ChasmDensity < 0.0f
|| D.ChasmDensity > 1.0f || !VoxelMath::IsFinite(D.ChasmSpacing)
|| !VoxelMath::IsFinite(D.ChasmRadius) || D.ChasmSpacing <= 0.0f
|| D.ChasmRadius < 0.0f)
{
return true;
@@ -1171,9 +1200,9 @@ static bool VF_AnyBridgeCanTouchBox(
{
return false;
}
if (!FMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f
|| D.BridgeDensity > 1.0f || !FMath::IsFinite(D.BridgeSpacing)
|| !FMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f
if (!VoxelMath::IsFinite(D.BridgeDensity) || D.BridgeDensity < 0.0f
|| D.BridgeDensity > 1.0f || !VoxelMath::IsFinite(D.BridgeSpacing)
|| !VoxelMath::IsFinite(D.BridgeRadius) || D.BridgeSpacing <= 0.0f
|| D.BridgeRadius < 0.0f)
{
return true;
@@ -1224,9 +1253,9 @@ static bool VF_AnyRidgeCanTouchBox(
{
return false;
}
if (!FMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f
|| D.RidgeDensity > 1.0f || !FMath::IsFinite(D.RidgeSpacing)
|| !FMath::IsFinite(D.RidgeHeight) || !FMath::IsFinite(D.RidgeThickness)
if (!VoxelMath::IsFinite(D.RidgeDensity) || D.RidgeDensity < 0.0f
|| D.RidgeDensity > 1.0f || !VoxelMath::IsFinite(D.RidgeSpacing)
|| !VoxelMath::IsFinite(D.RidgeHeight) || !VoxelMath::IsFinite(D.RidgeThickness)
|| D.RidgeSpacing <= 0.0f || D.RidgeHeight <= 0.0f || D.RidgeThickness < 0.0f)
{
return true;
@@ -1758,6 +1787,7 @@ UVoxelGenerator::UVoxelGenerator()
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
// déréférencer l'asset de settings.
Seed = Settings ? Settings->GetEffectiveWorldSeed() : 0;
@@ -1780,6 +1810,7 @@ void UVoxelGenerator::EndDensityBlock() const
float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) const
{
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_GetDensityAt);
VF_ParseFastIsFiniteSwitch();
VF_ParseFusedEvaluatorSwitch();
VoxelDensityProfile::FScopedTimer DensityProfileTimer(
VoxelDensityProfile::EBucket::GetDensityAt);
@@ -5009,7 +5040,7 @@ static EVoxelTileClass VF_ClassifyBoxRefined(const FVoxelOpStack& Stack,
for (const int32 IX : Xs)
{
const float Density = EvaluateExactLatticeValue(IX, IY, IZ, bUseFinalField);
if (!FMath::IsFinite(Density) || Density == 0.0f)
if (!VoxelMath::IsFinite(Density) || Density == 0.0f)
{
return false;
}
@@ -5053,7 +5084,7 @@ static EVoxelTileClass VF_ClassifyBoxRefined(const FVoxelOpStack& Stack,
for (int32 IX = IX0; IX <= IX1; ++IX)
{
const float Density = EvaluateExactLatticeValue(IX, IY, IZ, bUseFinalField);
if (!FMath::IsFinite(Density) || Density == 0.0f)
if (!VoxelMath::IsFinite(Density) || Density == 0.0f)
{
++ZeroOrInvalidCount;
IZ = IZ1;
@@ -459,7 +459,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
BlockOrigin.X + X * Step,
BlockOrigin.Y + Y * Step,
BlockOrigin.Z + Z * Step);
if (!FMath::IsFinite(Density) || Density == 0.0f)
if (!VoxelMath::IsFinite(Density) || Density == 0.0f)
{
bAllSolid = false;
bAllAir = false;
@@ -646,7 +646,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
{
const float Density = DensityGrid[
((Z + 1) * MDim + (Y + 1)) * MDim + (X + 1)];
if (!FMath::IsFinite(Density)
if (!VoxelMath::IsFinite(Density)
|| Density == 0.0f
|| (Candidate == 1 ? Density >= 0.0f : Density <= 0.0f))
{
+166 -166
View File
@@ -56,7 +56,7 @@ namespace
Result.bSurfaceRoughness = FParse::Value(
*CommandLine, TEXT("voxel.surfaceroughness="), Result.SurfaceRoughness);
if (Result.bSurfaceRoughness
&& (!FMath::IsFinite(Result.SurfaceRoughness) || Result.SurfaceRoughness < 0.0f))
&& (!VoxelMath::IsFinite(Result.SurfaceRoughness) || Result.SurfaceRoughness < 0.0f))
{
Result.bSurfaceRoughness = false;
}
@@ -64,7 +64,7 @@ namespace
Result.bFrequency = FParse::Value(
*CommandLine, TEXT("voxel.roughnessfrequency="), Result.Frequency);
if (Result.bFrequency
&& (!FMath::IsFinite(Result.Frequency) || Result.Frequency <= 0.0f))
&& (!VoxelMath::IsFinite(Result.Frequency) || Result.Frequency <= 0.0f))
{
Result.bFrequency = false;
}
@@ -423,14 +423,14 @@ namespace
const FVoxelPassage& Passage, double X, double Y)
{
if (!(Passage.NativeFloorReliefStrength > 0.0f)
|| !FMath::IsFinite(Passage.NativeFloorReliefStrength)
|| !FMath::IsFinite(Passage.NativeFloorReliefFrequency)
|| !VoxelMath::IsFinite(Passage.NativeFloorReliefStrength)
|| !VoxelMath::IsFinite(Passage.NativeFloorReliefFrequency)
|| !(FMath::Abs(Passage.NativeFloorReliefFrequency) > KINDA_SMALL_NUMBER))
{
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
&& X >= static_cast<double>(MIN_int32) && X <= 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)
{
if (!(Strength > 0.0f)
|| !FMath::IsFinite(Strength)
|| !FMath::IsFinite(Frequency)
|| !VoxelMath::IsFinite(Strength)
|| !VoxelMath::IsFinite(Frequency)
|| !(FMath::Abs(Frequency) > KINDA_SMALL_NUMBER)
|| !FMath::IsFinite(BaseGradient)
|| !VoxelMath::IsFinite(BaseGradient)
|| BaseGradient < 0.0f)
{
return 0.0f;
@@ -521,7 +521,7 @@ namespace
const float ReliefGradientBound =
NoiseGradientBound + EnvelopeDerivativeBound;
if (!(ReliefGradientBound > KINDA_SMALL_NUMBER)
|| !FMath::IsFinite(ReliefGradientBound)
|| !VoxelMath::IsFinite(ReliefGradientBound)
|| !(HorizontalRun > KINDA_SMALL_NUMBER))
{
return 0.0f;
@@ -648,8 +648,8 @@ namespace
* VOXEL_NOISE_SCALE * Passage.NativeFloorReliefStrength
* Envelope * ReliefScale;
OutSupportRadius = BestSupportRadius;
return FMath::IsFinite(OutFloorZ)
&& FMath::IsFinite(OutSupportRadius)
return VoxelMath::IsFinite(OutFloorZ)
&& VoxelMath::IsFinite(OutSupportRadius)
&& OutSupportRadius > 0.0f;
}
@@ -784,7 +784,7 @@ static void VF_AuthorNativePassageFloor(
const float Radius = FMath::Abs(Passage.ControlRadii[PointIndex]);
const float FloorZ = VoxelPassageGeometry::TunnelFloorZ(
Passage.ControlPoints[PointIndex], Radius);
if (!FMath::IsFinite(FloorZ))
if (!VoxelMath::IsFinite(FloorZ))
{
Passage.NativeFloorProfileZ.Reset();
return;
@@ -1867,11 +1867,11 @@ void UVoxelStrateManager::GeneratePassages()
const float UpperSealThickness = BoundarySealThicknessFor(*UpperDef);
const float InnerBottomZ = UpperBottomZ + UpperSealThickness;
const float InnerTopZ = UpperTopZ - UpperSealThickness;
if (FMath::IsFinite(SuggestedUpperPoint.X)
&& FMath::IsFinite(SuggestedUpperPoint.Y)
&& FMath::IsFinite(SuggestedUpperPoint.Z)
&& FMath::IsFinite(InnerBottomZ)
&& FMath::IsFinite(InnerTopZ)
if (VoxelMath::IsFinite(SuggestedUpperPoint.X)
&& VoxelMath::IsFinite(SuggestedUpperPoint.Y)
&& VoxelMath::IsFinite(SuggestedUpperPoint.Z)
&& VoxelMath::IsFinite(InnerBottomZ)
&& VoxelMath::IsFinite(InnerTopZ)
&& InnerBottomZ < InnerTopZ)
{
// 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 InnerBottomZ = LowerBottomZ + LowerSealThickness;
const float InnerTopZ = LowerTopZ - LowerSealThickness;
if (FMath::IsFinite(SuggestedLowerPoint.X)
&& FMath::IsFinite(SuggestedLowerPoint.Y)
&& FMath::IsFinite(SuggestedLowerPoint.Z)
&& FMath::IsFinite(InnerBottomZ)
&& FMath::IsFinite(InnerTopZ)
if (VoxelMath::IsFinite(SuggestedLowerPoint.X)
&& VoxelMath::IsFinite(SuggestedLowerPoint.Y)
&& VoxelMath::IsFinite(SuggestedLowerPoint.Z)
&& VoxelMath::IsFinite(InnerBottomZ)
&& VoxelMath::IsFinite(InnerTopZ)
&& InnerBottomZ < InnerTopZ)
{
// VF_SuggestLandingPoint already guarantees a strict interior answer. Keep a
@@ -2724,9 +2724,9 @@ void UVoxelStrateManager::ApplyPassageLandingFloorMC(
static bool VF_IsPassageRoomFloor(
const FVector& Position, const FVoxelPassageLanding& Landing)
{
if (!FMath::IsFinite(Position.X) || !FMath::IsFinite(Position.Y)
|| !FMath::IsFinite(Position.Z) || !FMath::IsFinite(Landing.FloorZ)
|| !FMath::IsFinite(Landing.FloorThickness)
if (!VoxelMath::IsFinite(Position.X) || !VoxelMath::IsFinite(Position.Y)
|| !VoxelMath::IsFinite(Position.Z) || !VoxelMath::IsFinite(Landing.FloorZ)
|| !VoxelMath::IsFinite(Landing.FloorThickness)
|| Landing.FloorThickness <= 0.0f || Landing.HalfWidth <= 0.0f)
{
return false;
@@ -3035,8 +3035,8 @@ namespace
float Min, float Max, float Origin, int32 Step,
int32& OutFirst, int32& OutLast)
{
if (Step <= 0 || !FMath::IsFinite(Min) || !FMath::IsFinite(Max)
|| !FMath::IsFinite(Origin) || Min > Max)
if (Step <= 0 || !VoxelMath::IsFinite(Min) || !VoxelMath::IsFinite(Max)
|| !VoxelMath::IsFinite(Origin) || Min > Max)
{
return false;
}
@@ -3065,9 +3065,9 @@ namespace
auto AddDomain = [&](const FVector& Min, const FVector& Max) -> bool
{
if (!FMath::IsFinite(Min.X) || !FMath::IsFinite(Min.Y)
|| !FMath::IsFinite(Min.Z) || !FMath::IsFinite(Max.X)
|| !FMath::IsFinite(Max.Y) || !FMath::IsFinite(Max.Z)
if (!VoxelMath::IsFinite(Min.X) || !VoxelMath::IsFinite(Min.Y)
|| !VoxelMath::IsFinite(Min.Z) || !VoxelMath::IsFinite(Max.X)
|| !VoxelMath::IsFinite(Max.Y) || !VoxelMath::IsFinite(Max.Z)
|| Min.X > Max.X || Min.Y > Max.Y || Min.Z > Max.Z)
{
return false;
@@ -3078,11 +3078,11 @@ namespace
for (const FVoxelPassage& Passage : Passages)
{
if (!FMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq)
if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !VoxelMath::IsFinite(Passage.BoundRadius)
|| !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{
// Invalid generated geometry is an unknown, not an empty passage set.
@@ -3096,7 +3096,7 @@ namespace
return false;
}
const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num();
if (!bTaper && !FMath::IsFinite(Passage.Radius))
if (!bTaper && !VoxelMath::IsFinite(Passage.Radius))
{
return false;
}
@@ -3104,12 +3104,12 @@ namespace
PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{
const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z))
if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !VoxelMath::IsFinite(Point.Z))
{
return false;
}
if (bTaper && !FMath::IsFinite(Passage.ControlRadii[PointIndex]))
if (bTaper && !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex]))
{
return false;
}
@@ -3125,7 +3125,7 @@ namespace
const float RadiusB = bTaper
? Passage.ControlRadii[SegmentIndex + 1] : Passage.Radius;
const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB));
if (!FMath::IsFinite(Radius))
if (!VoxelMath::IsFinite(Radius))
{
return false;
}
@@ -3143,13 +3143,13 @@ namespace
}
else
{
if (!FMath::IsFinite(Passage.UpperPoint.X)
|| !FMath::IsFinite(Passage.UpperPoint.Y)
|| !FMath::IsFinite(Passage.UpperPoint.Z)
|| !FMath::IsFinite(Passage.LowerPoint.X)
|| !FMath::IsFinite(Passage.LowerPoint.Y)
|| !FMath::IsFinite(Passage.LowerPoint.Z)
|| !FMath::IsFinite(Passage.Radius))
if (!VoxelMath::IsFinite(Passage.UpperPoint.X)
|| !VoxelMath::IsFinite(Passage.UpperPoint.Y)
|| !VoxelMath::IsFinite(Passage.UpperPoint.Z)
|| !VoxelMath::IsFinite(Passage.LowerPoint.X)
|| !VoxelMath::IsFinite(Passage.LowerPoint.Y)
|| !VoxelMath::IsFinite(Passage.LowerPoint.Z)
|| !VoxelMath::IsFinite(Passage.Radius))
{
return false;
}
@@ -3170,11 +3170,11 @@ namespace
&Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings)
{
if (!FMath::IsFinite(Landing->StandingPoint.X)
|| !FMath::IsFinite(Landing->StandingPoint.Y)
|| !FMath::IsFinite(Landing->FloorZ)
|| !FMath::IsFinite(Landing->CeilingZ)
|| !FMath::IsFinite(Landing->HalfWidth))
if (!VoxelMath::IsFinite(Landing->StandingPoint.X)
|| !VoxelMath::IsFinite(Landing->StandingPoint.Y)
|| !VoxelMath::IsFinite(Landing->FloorZ)
|| !VoxelMath::IsFinite(Landing->CeilingZ)
|| !VoxelMath::IsFinite(Landing->HalfWidth))
{
// 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.
@@ -3238,7 +3238,7 @@ namespace
const float SmoothDip = static_cast<float>(DomainCount - 1)
* (SmoothMinK / 6.0f);
const float Padding = CarveThreshold + SmoothDip;
if (!FMath::IsFinite(Padding) || Padding < 0.0f)
if (!VoxelMath::IsFinite(Padding) || Padding < 0.0f)
{
return true;
}
@@ -3273,8 +3273,8 @@ namespace
const TArray<FVoxelPassage>& Passages,
const FVector& Position)
{
if (!FMath::IsFinite(Position.X) || !FMath::IsFinite(Position.Y)
|| !FMath::IsFinite(Position.Z))
if (!VoxelMath::IsFinite(Position.X) || !VoxelMath::IsFinite(Position.Y)
|| !VoxelMath::IsFinite(Position.Z))
{
return true;
}
@@ -3285,11 +3285,11 @@ namespace
float ModifierLowerBound = FLT_MAX;
for (const FVoxelPassage& Passage : Passages)
{
if (!FMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq)
if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !VoxelMath::IsFinite(Passage.BoundRadius)
|| !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{
return true;
@@ -3307,7 +3307,7 @@ namespace
return true;
}
const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num();
if (!bTaper && !FMath::IsFinite(Passage.Radius))
if (!bTaper && !VoxelMath::IsFinite(Passage.Radius))
{
return true;
}
@@ -3315,12 +3315,12 @@ namespace
PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{
const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z))
if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !VoxelMath::IsFinite(Point.Z))
{
return true;
}
if (bTaper && !FMath::IsFinite(Passage.ControlRadii[PointIndex]))
if (bTaper && !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex]))
{
return true;
}
@@ -3337,7 +3337,7 @@ namespace
const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB));
const float SegmentLowerBound = VF_DistanceToSegmentLowerBound(
Position, A, B, Radius);
if (!FMath::IsFinite(SegmentLowerBound))
if (!VoxelMath::IsFinite(SegmentLowerBound))
{
return true;
}
@@ -3347,20 +3347,20 @@ namespace
}
else
{
if (!FMath::IsFinite(Passage.UpperPoint.X)
|| !FMath::IsFinite(Passage.UpperPoint.Y)
|| !FMath::IsFinite(Passage.UpperPoint.Z)
|| !FMath::IsFinite(Passage.LowerPoint.X)
|| !FMath::IsFinite(Passage.LowerPoint.Y)
|| !FMath::IsFinite(Passage.LowerPoint.Z)
|| !FMath::IsFinite(Passage.Radius))
if (!VoxelMath::IsFinite(Passage.UpperPoint.X)
|| !VoxelMath::IsFinite(Passage.UpperPoint.Y)
|| !VoxelMath::IsFinite(Passage.UpperPoint.Z)
|| !VoxelMath::IsFinite(Passage.LowerPoint.X)
|| !VoxelMath::IsFinite(Passage.LowerPoint.Y)
|| !VoxelMath::IsFinite(Passage.LowerPoint.Z)
|| !VoxelMath::IsFinite(Passage.Radius))
{
return true;
}
PassageLowerBound = VF_DistanceToSegmentLowerBound(
Position, Passage.UpperPoint, Passage.LowerPoint,
FMath::Abs(Passage.Radius));
if (!FMath::IsFinite(PassageLowerBound))
if (!VoxelMath::IsFinite(PassageLowerBound))
{
return true;
}
@@ -3370,11 +3370,11 @@ namespace
&Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings)
{
if (!FMath::IsFinite(Landing->StandingPoint.X)
|| !FMath::IsFinite(Landing->StandingPoint.Y)
|| !FMath::IsFinite(Landing->FloorZ)
|| !FMath::IsFinite(Landing->CeilingZ)
|| !FMath::IsFinite(Landing->HalfWidth))
if (!VoxelMath::IsFinite(Landing->StandingPoint.X)
|| !VoxelMath::IsFinite(Landing->StandingPoint.Y)
|| !VoxelMath::IsFinite(Landing->FloorZ)
|| !VoxelMath::IsFinite(Landing->CeilingZ)
|| !VoxelMath::IsFinite(Landing->HalfWidth))
{
return true;
}
@@ -3384,7 +3384,7 @@ namespace
continue;
}
const float LandingSDF = VF_EvaluatePassageLandingSDF(Position, *Landing);
if (!FMath::IsFinite(LandingSDF))
if (!VoxelMath::IsFinite(LandingSDF))
{
return true;
}
@@ -3395,7 +3395,7 @@ namespace
ModifierLowerBound = VoxelSDF::SmoothMin(
ModifierLowerBound, PassageLowerBound, BlendK);
}
return !FMath::IsFinite(ModifierLowerBound)
return !VoxelMath::IsFinite(ModifierLowerBound)
|| ModifierLowerBound < CarveThreshold + NumericalSafetyMargin;
}
@@ -3419,8 +3419,8 @@ namespace
static bool VF_SegmentDistanceToBox(
const FVector& A, const FVector& B, const FBox& Box, float& OutDistance)
{
if (!FMath::IsFinite(A.X) || !FMath::IsFinite(A.Y) || !FMath::IsFinite(A.Z)
|| !FMath::IsFinite(B.X) || !FMath::IsFinite(B.Y) || !FMath::IsFinite(B.Z)
if (!VoxelMath::IsFinite(A.X) || !VoxelMath::IsFinite(A.Y) || !VoxelMath::IsFinite(A.Z)
|| !VoxelMath::IsFinite(B.X) || !VoxelMath::IsFinite(B.Y) || !VoxelMath::IsFinite(B.Z)
|| !Box.IsValid)
{
return false;
@@ -3508,22 +3508,22 @@ namespace
MinimumDistanceSquared = FMath::Min(
MinimumDistanceSquared, DistanceSquared);
}
if (!FMath::IsFinite(MinimumDistanceSquared))
if (!VoxelMath::IsFinite(MinimumDistanceSquared))
{
return false;
}
OutDistance = FMath::Sqrt(MinimumDistanceSquared);
return FMath::IsFinite(OutDistance);
return VoxelMath::IsFinite(OutDistance);
}
static bool VF_LandingLowerBoundOverBox(
const FVoxelPassageLanding& Landing, const FBox& Box, float& OutLowerBound)
{
if (!FMath::IsFinite(Landing.StandingPoint.X)
|| !FMath::IsFinite(Landing.StandingPoint.Y)
|| !FMath::IsFinite(Landing.FloorZ)
|| !FMath::IsFinite(Landing.CeilingZ)
|| !FMath::IsFinite(Landing.HalfWidth)
if (!VoxelMath::IsFinite(Landing.StandingPoint.X)
|| !VoxelMath::IsFinite(Landing.StandingPoint.Y)
|| !VoxelMath::IsFinite(Landing.FloorZ)
|| !VoxelMath::IsFinite(Landing.CeilingZ)
|| !VoxelMath::IsFinite(Landing.HalfWidth)
|| !Box.IsValid)
{
return false;
@@ -3555,7 +3555,7 @@ namespace
FMath::Max(HalfExtent.Y, HalfExtent.Z)) - RoomRounding;
OutLowerBound = FMath::Max(
RoundedBoxLower, Landing.FloorZ - (float)Box.Max.Z);
return FMath::IsFinite(OutLowerBound);
return VoxelMath::IsFinite(OutLowerBound);
}
static bool VF_PassageModifierLowerBoundOverBox(
@@ -3573,11 +3573,11 @@ namespace
const FVector BoxMax((float)Box.Max.X, (float)Box.Max.Y, (float)Box.Max.Z);
for (const FVoxelPassage& Passage : Passages)
{
if (!FMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq)
if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !VoxelMath::IsFinite(Passage.BoundRadius)
|| !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{
return false;
@@ -3600,7 +3600,7 @@ namespace
return false;
}
const bool bTaper = Passage.ControlRadii.Num() == Passage.ControlPoints.Num();
if (!bTaper && !FMath::IsFinite(Passage.Radius))
if (!bTaper && !VoxelMath::IsFinite(Passage.Radius))
{
return false;
}
@@ -3608,9 +3608,9 @@ namespace
PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{
const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z)
|| (bTaper && !FMath::IsFinite(Passage.ControlRadii[PointIndex])))
if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !VoxelMath::IsFinite(Point.Z)
|| (bTaper && !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex])))
{
return false;
}
@@ -3624,7 +3624,7 @@ namespace
? Passage.ControlRadii[SegmentIndex + 1] : Passage.Radius;
const float Radius = FMath::Max(FMath::Abs(RadiusA), FMath::Abs(RadiusB));
float SegmentDistance = 0.0f;
if (!FMath::IsFinite(Radius)
if (!VoxelMath::IsFinite(Radius)
|| !VF_SegmentDistanceToBox(
Passage.ControlPoints[SegmentIndex],
Passage.ControlPoints[SegmentIndex + 1], Box, SegmentDistance))
@@ -3637,13 +3637,13 @@ namespace
}
else
{
if (!FMath::IsFinite(Passage.UpperPoint.X)
|| !FMath::IsFinite(Passage.UpperPoint.Y)
|| !FMath::IsFinite(Passage.UpperPoint.Z)
|| !FMath::IsFinite(Passage.LowerPoint.X)
|| !FMath::IsFinite(Passage.LowerPoint.Y)
|| !FMath::IsFinite(Passage.LowerPoint.Z)
|| !FMath::IsFinite(Passage.Radius))
if (!VoxelMath::IsFinite(Passage.UpperPoint.X)
|| !VoxelMath::IsFinite(Passage.UpperPoint.Y)
|| !VoxelMath::IsFinite(Passage.UpperPoint.Z)
|| !VoxelMath::IsFinite(Passage.LowerPoint.X)
|| !VoxelMath::IsFinite(Passage.LowerPoint.Y)
|| !VoxelMath::IsFinite(Passage.LowerPoint.Z)
|| !VoxelMath::IsFinite(Passage.Radius))
{
return false;
}
@@ -3673,7 +3673,7 @@ namespace
ModifierLowerBound, PassageLowerBound, BlendK);
}
OutLowerBound = ModifierLowerBound;
return FMath::IsFinite(OutLowerBound);
return VoxelMath::IsFinite(OutLowerBound);
}
// MaxPassageCarveFactorNearLattice is queried once for the root and once for every refined
@@ -3819,7 +3819,7 @@ bool UVoxelStrateManager::AnyPassageNearLattice(
VoxelBox, LatticeOrigin, Step);
// 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.
return !FMath::IsFinite(MaxFactor) || MaxFactor > 0.0f;
return !VoxelMath::IsFinite(MaxFactor) || MaxFactor > 0.0f;
}
bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
@@ -3835,8 +3835,8 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
{
return true;
}
if (!FMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f)
|| !FMath::IsFinite(SealThickness) || SealThickness < 0.0f)
if (!VoxelMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f)
|| !VoxelMath::IsFinite(SealThickness) || SealThickness < 0.0f)
{
return true;
}
@@ -3887,9 +3887,9 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
PointIndex < Passage.ControlPoints.Num(); ++PointIndex)
{
const FVector& Point = Passage.ControlPoints[PointIndex];
if (!FMath::IsFinite(Point.X) || !FMath::IsFinite(Point.Y)
|| !FMath::IsFinite(Point.Z)
|| !FMath::IsFinite(Passage.ControlRadii[PointIndex]))
if (!VoxelMath::IsFinite(Point.X) || !VoxelMath::IsFinite(Point.Y)
|| !VoxelMath::IsFinite(Point.Z)
|| !VoxelMath::IsFinite(Passage.ControlRadii[PointIndex]))
{
return true;
}
@@ -3952,9 +3952,9 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
float MinX, float MaxX, float MinY, float MaxY,
float MinZ, float MaxZ, bool& bTouches) -> bool
{
if (!FMath::IsFinite(MinX) || !FMath::IsFinite(MaxX)
|| !FMath::IsFinite(MinY) || !FMath::IsFinite(MaxY)
|| !FMath::IsFinite(MinZ) || !FMath::IsFinite(MaxZ)
if (!VoxelMath::IsFinite(MinX) || !VoxelMath::IsFinite(MaxX)
|| !VoxelMath::IsFinite(MinY) || !VoxelMath::IsFinite(MaxY)
|| !VoxelMath::IsFinite(MinZ) || !VoxelMath::IsFinite(MaxZ)
|| MinX > MaxX || MinY > MaxY || MinZ > MaxZ)
{
return false;
@@ -3980,11 +3980,11 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
for (int32 PassageIndex = 0; PassageIndex < Passages.Num(); ++PassageIndex)
{
const FVoxelPassage& Passage = Passages[PassageIndex];
if (!FMath::IsFinite(Passage.BoundCenter.X)
|| !FMath::IsFinite(Passage.BoundCenter.Y)
|| !FMath::IsFinite(Passage.BoundCenter.Z)
|| !FMath::IsFinite(Passage.BoundRadius)
|| !FMath::IsFinite(Passage.BoundRadiusSq)
if (!VoxelMath::IsFinite(Passage.BoundCenter.X)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Y)
|| !VoxelMath::IsFinite(Passage.BoundCenter.Z)
|| !VoxelMath::IsFinite(Passage.BoundRadius)
|| !VoxelMath::IsFinite(Passage.BoundRadiusSq)
|| Passage.BoundRadius < 0.0f || Passage.BoundRadiusSq < 0.0f)
{
return true;
@@ -4002,11 +4002,11 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
// not part of this validity check: the landing-air writer reads the SDF fields even
// when a separate floor descriptor is degenerate.
const bool bLandingSdfValid =
FMath::IsFinite(Landing->StandingPoint.X)
&& FMath::IsFinite(Landing->StandingPoint.Y)
&& FMath::IsFinite(Landing->FloorZ)
&& FMath::IsFinite(Landing->CeilingZ)
&& FMath::IsFinite(Landing->HalfWidth)
VoxelMath::IsFinite(Landing->StandingPoint.X)
&& VoxelMath::IsFinite(Landing->StandingPoint.Y)
&& VoxelMath::IsFinite(Landing->FloorZ)
&& VoxelMath::IsFinite(Landing->CeilingZ)
&& VoxelMath::IsFinite(Landing->HalfWidth)
&& Landing->HalfWidth > 0.0f
&& Landing->CeilingZ > Landing->FloorZ;
if (bLandingSdfValid)
@@ -4065,7 +4065,7 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
}
const float AirTarget = -(BaseDensity * 2.0f + SealThickness + 4.0f);
if (!FMath::IsFinite(AirTarget))
if (!VoxelMath::IsFinite(AirTarget))
{
return true;
}
@@ -4111,7 +4111,7 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
Position, Passage.UpperLanding);
const float LowerSDF = VF_EvaluatePassageLandingSDF(
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.
return true;
@@ -4134,7 +4134,7 @@ bool UVoxelStrateManager::AnyPassageAirPostNearLattice(
CarveFactor = SmoothStep01(CarveFactor);
const float LandingThreshold = FMath::Lerp(
BaseDensity, AirTarget, CarveFactor);
if (!FMath::IsFinite(LandingThreshold)
if (!VoxelMath::IsFinite(LandingThreshold)
|| LandingThreshold <= 0.0f)
{
// 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);
const float Padding = PassageCarveThreshold + SmoothDip;
ModifierDomainPadding = Padding;
if (!FMath::IsFinite(Padding) || Padding < 0.0f)
if (!VoxelMath::IsFinite(Padding) || Padding < 0.0f)
{
bKnownModifierDomains = false;
}
@@ -4323,7 +4323,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
return;
}
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
const float CarveFactor = FMath::IsFinite(ModifierSDF)
const float CarveFactor = VoxelMath::IsFinite(ModifierSDF)
? CarveFactorFromSDF(ModifierSDF) : 1.0f;
Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor;
MaxCarveFactor = FMath::Max(MaxCarveFactor, CarveFactor);
@@ -4421,9 +4421,9 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
CandidateMaxZ = FMath::Max(CandidateMaxZ,
Domain.Max.Z + ModifierDomainPadding);
}
if (!FMath::IsFinite(CandidateMinX) || !FMath::IsFinite(CandidateMinY)
|| !FMath::IsFinite(CandidateMinZ) || !FMath::IsFinite(CandidateMaxX)
|| !FMath::IsFinite(CandidateMaxY) || !FMath::IsFinite(CandidateMaxZ))
if (!VoxelMath::IsFinite(CandidateMinX) || !VoxelMath::IsFinite(CandidateMinY)
|| !VoxelMath::IsFinite(CandidateMinZ) || !VoxelMath::IsFinite(CandidateMaxX)
|| !VoxelMath::IsFinite(CandidateMaxY) || !VoxelMath::IsFinite(CandidateMaxZ))
{
bKnownModifierDomains = false;
}
@@ -4486,7 +4486,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
if (MayEvaluatePoint(Position))
{
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
CarveFactor = FMath::IsFinite(ModifierSDF)
CarveFactor = VoxelMath::IsFinite(ModifierSDF)
? CarveFactorFromSDF(ModifierSDF) : 1.0f;
}
Cache.Factors[Cache.Index(IX, IY, IZ)] = CarveFactor;
@@ -4517,7 +4517,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
{
const float RemainingSDF = EvaluateModifierSDF(
RemainingWorldX, RemainingWorldY, RemainingWorldZ);
RemainingFactor = FMath::IsFinite(RemainingSDF)
RemainingFactor = VoxelMath::IsFinite(RemainingSDF)
? CarveFactorFromSDF(RemainingSDF) : 1.0f;
}
Cache.Factors[Cache.Index(RemainingX, RemainingY, RemainingZ)] =
@@ -4552,7 +4552,7 @@ float UVoxelStrateManager::MaxPassageCarveFactorNearLattice(
continue;
}
const float ModifierSDF = EvaluateModifierSDF(X, Y, Z);
if (!FMath::IsFinite(ModifierSDF))
if (!VoxelMath::IsFinite(ModifierSDF))
{
return 1.0f;
}
@@ -4581,11 +4581,11 @@ bool UVoxelStrateManager::AnyPassageLandingFloorNearLattice(
&Passage.UpperLanding, &Passage.LowerLanding };
for (const FVoxelPassageLanding* Landing : Landings)
{
if (!FMath::IsFinite(Landing->StandingPoint.X)
|| !FMath::IsFinite(Landing->StandingPoint.Y)
|| !FMath::IsFinite(Landing->FloorZ)
|| !FMath::IsFinite(Landing->HalfWidth)
|| !FMath::IsFinite(Landing->FloorThickness))
if (!VoxelMath::IsFinite(Landing->StandingPoint.X)
|| !VoxelMath::IsFinite(Landing->StandingPoint.Y)
|| !VoxelMath::IsFinite(Landing->FloorZ)
|| !VoxelMath::IsFinite(Landing->HalfWidth)
|| !VoxelMath::IsFinite(Landing->FloorThickness))
{
return true;
}
@@ -4620,11 +4620,11 @@ bool UVoxelStrateManager::AnyPassageLandingFloorNearLattice(
{
const FVector& A = Passage.ControlPoints[SegmentIndex];
const FVector& B = Passage.ControlPoints[SegmentIndex + 1];
if (!FMath::IsFinite(A.X) || !FMath::IsFinite(A.Y)
|| !FMath::IsFinite(A.Z) || !FMath::IsFinite(B.X)
|| !FMath::IsFinite(B.Y) || !FMath::IsFinite(B.Z)
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex])
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1]))
if (!VoxelMath::IsFinite(A.X) || !VoxelMath::IsFinite(A.Y)
|| !VoxelMath::IsFinite(A.Z) || !VoxelMath::IsFinite(B.X)
|| !VoxelMath::IsFinite(B.Y) || !VoxelMath::IsFinite(B.Z)
|| !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex])
|| !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1]))
{
return true;
}
@@ -4696,11 +4696,11 @@ bool UVoxelStrateManager::AnyLandingFloorAtLattice(
auto HasAnyLandingSample = [&](const FVoxelPassageLanding& Landing) -> bool
{
if (!FMath::IsFinite(Landing.StandingPoint.X)
|| !FMath::IsFinite(Landing.StandingPoint.Y)
|| !FMath::IsFinite(Landing.FloorZ)
|| !FMath::IsFinite(Landing.HalfWidth)
|| !FMath::IsFinite(Landing.FloorThickness)
if (!VoxelMath::IsFinite(Landing.StandingPoint.X)
|| !VoxelMath::IsFinite(Landing.StandingPoint.Y)
|| !VoxelMath::IsFinite(Landing.FloorZ)
|| !VoxelMath::IsFinite(Landing.HalfWidth)
|| !VoxelMath::IsFinite(Landing.FloorThickness)
|| Landing.HalfWidth <= 0.0f || Landing.FloorThickness <= 0.0f)
{
// 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& B = Passage.ControlPoints[SegmentIndex + 1];
if (!FMath::IsFinite(A.X) || !FMath::IsFinite(A.Y)
|| !FMath::IsFinite(A.Z) || !FMath::IsFinite(B.X)
|| !FMath::IsFinite(B.Y) || !FMath::IsFinite(B.Z)
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex])
|| !FMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1]))
if (!VoxelMath::IsFinite(A.X) || !VoxelMath::IsFinite(A.Y)
|| !VoxelMath::IsFinite(A.Z) || !VoxelMath::IsFinite(B.X)
|| !VoxelMath::IsFinite(B.Y) || !VoxelMath::IsFinite(B.Z)
|| !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex])
|| !VoxelMath::IsFinite(Passage.ControlRadii[SegmentIndex + 1]))
{
return true;
}
@@ -4779,9 +4779,9 @@ bool UVoxelStrateManager::AnyLandingFloorAtLattice(
const float MinZ = FMath::Min(FloorA, FloorB)
- VoxelPassageGeometry::LandingFloorThicknessVoxels - Pad;
const float MaxZ = FMath::Max(FloorA, FloorB) + Pad;
if (!FMath::IsFinite(MinX) || !FMath::IsFinite(MaxX)
|| !FMath::IsFinite(MinY) || !FMath::IsFinite(MaxY)
|| !FMath::IsFinite(MinZ) || !FMath::IsFinite(MaxZ))
if (!VoxelMath::IsFinite(MinX) || !VoxelMath::IsFinite(MaxX)
|| !VoxelMath::IsFinite(MinY) || !VoxelMath::IsFinite(MaxY)
|| !VoxelMath::IsFinite(MinZ) || !VoxelMath::IsFinite(MaxZ))
{
return true;
}
@@ -4926,13 +4926,13 @@ bool UVoxelStrateManager::AnyOriginLandingAirNearLattice(
{
return true;
}
if (!FMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f)
|| !FMath::IsFinite(SealThickness) || SealThickness < 0.0f)
if (!VoxelMath::IsFinite(BaseDensity) || !(BaseDensity > 0.0f)
|| !VoxelMath::IsFinite(SealThickness) || SealThickness < 0.0f)
{
return true;
}
const float AirTarget = -(BaseDensity * 2.0f + SealThickness + 4.0f);
if (!FMath::IsFinite(AirTarget))
if (!VoxelMath::IsFinite(AirTarget))
{
return true;
}
@@ -4989,7 +4989,7 @@ bool UVoxelStrateManager::AnyOriginLandingAirNearLattice(
(float)LatticeOrigin.Z + (float)(IZ * Step));
const float RoomSDF = VoxelPassageGeometry::OriginLandingRoomSDF(
Position, Geometry);
if (!FMath::IsFinite(RoomSDF))
if (!VoxelMath::IsFinite(RoomSDF))
{
return true;
}
@@ -5002,7 +5002,7 @@ bool UVoxelStrateManager::AnyOriginLandingAirNearLattice(
CarveFactor = SmoothStep01(CarveFactor);
const float LandingThreshold = FMath::Lerp(
BaseDensity, AirTarget, CarveFactor);
if (!FMath::IsFinite(LandingThreshold)
if (!VoxelMath::IsFinite(LandingThreshold)
|| LandingThreshold <= 0.0f)
{
return true;
+5 -5
View File
@@ -436,7 +436,7 @@ namespace
++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;
OutMaxDelta = FMath::Max(OutMaxDelta, Delta);
++OutSamples;
@@ -1720,8 +1720,8 @@ bool AVoxelWorld::TryGetPlayerPosition(FVector& OutPosition, APawn** OutPawn) co
}
const FVector Position = Pawn->GetActorLocation();
if (!FMath::IsFinite(Position.X) || !FMath::IsFinite(Position.Y)
|| !FMath::IsFinite(Position.Z))
if (!VoxelMath::IsFinite(Position.X) || !VoxelMath::IsFinite(Position.Y)
|| !VoxelMath::IsFinite(Position.Z))
{
return false;
}
@@ -1766,7 +1766,7 @@ bool AVoxelWorld::GetPlayerSupportTile(APawn* Pawn, const FVector& PlayerPositio
Pawn->GetActorBounds(/*bOnlyCollidingComponents*/ true, BoundsOrigin, BoundsExtent);
HalfHeightCm = FMath::Max(0.0f, BoundsExtent.Z);
}
if (!FMath::IsFinite(HalfHeightCm))
if (!VoxelMath::IsFinite(HalfHeightCm))
{
return false;
}
@@ -4060,7 +4060,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector
OriginVoxels.Y + Y * ValidationStep,
OriginVoxels.Z + Z * ValidationStep);
++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::AllAir || Density > 0.0f);
if (!bSampleAgrees)
+1 -1
View File
@@ -415,7 +415,7 @@ struct FVoxelBoxSdfInterval
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();
return;
@@ -222,9 +222,9 @@ FORCEINLINE void VF_ApplyXYEdgeSeal(float& Density, float WorldX, float WorldY,
float WorldRadiusVoxels, float Thickness, float BaseDensity)
{
if (!(WorldRadiusVoxels > 0.0f) || !(Thickness > 0.0f) || !(BaseDensity > 0.0f)) return;
if (!FMath::IsFinite(WorldX) || !FMath::IsFinite(WorldY)
|| !FMath::IsFinite(WorldRadiusVoxels) || !FMath::IsFinite(Thickness)
|| !FMath::IsFinite(BaseDensity)) return;
if (!VoxelMath::IsFinite(WorldX) || !VoxelMath::IsFinite(WorldY)
|| !VoxelMath::IsFinite(WorldRadiusVoxels) || !VoxelMath::IsFinite(Thickness)
|| !VoxelMath::IsFinite(BaseDensity)) return;
const float InnerRadius = WorldRadiusVoxels - Thickness;
const float InnerRadiusSq = InnerRadius * InnerRadius;
@@ -282,10 +282,10 @@ FORCEINLINE bool VF_IsValidXYEdgeSealProofInput(const FBox& VoxelBox,
float WorldRadiusVoxels, float Thickness, float BaseDensity)
{
return VoxelBox.IsValid
&& FMath::IsFinite(VoxelBox.Min.X) && FMath::IsFinite(VoxelBox.Min.Y)
&& FMath::IsFinite(VoxelBox.Max.X) && FMath::IsFinite(VoxelBox.Max.Y)
&& FMath::IsFinite(WorldRadiusVoxels) && FMath::IsFinite(Thickness)
&& FMath::IsFinite(BaseDensity)
&& VoxelMath::IsFinite(VoxelBox.Min.X) && VoxelMath::IsFinite(VoxelBox.Min.Y)
&& VoxelMath::IsFinite(VoxelBox.Max.X) && VoxelMath::IsFinite(VoxelBox.Max.Y)
&& VoxelMath::IsFinite(WorldRadiusVoxels) && VoxelMath::IsFinite(Thickness)
&& VoxelMath::IsFinite(BaseDensity)
&& WorldRadiusVoxels > 0.0f && Thickness > 0.0f && BaseDensity > 0.0f;
}
@@ -344,7 +344,7 @@ FORCEINLINE bool VF_XYEdgeSealBoxTouchesBand(const FBox& VoxelBox,
float WorldRadiusVoxels, float Thickness)
{
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;
return VF_XYEdgeFarthestRadiusSq(VoxelBox) > InnerRadius * InnerRadius;
+33 -32
View File
@@ -7,6 +7,7 @@
#pragma once
#include "CoreMinimal.h"
#include "VoxelTypes.h"
namespace VoxelPassageGeometry
{
@@ -85,13 +86,13 @@ namespace VoxelPassageGeometry
+ FloorThickness + SealSafetyMarginVoxels;
const float MaximumFloor = InteriorTopZ
- PlayerHeightVoxels - SealSafetyMarginVoxels;
if (!FMath::IsFinite(StrateBottomZ)
|| !FMath::IsFinite(InteriorBottomZ)
|| !FMath::IsFinite(InteriorTopZ)
|| !FMath::IsFinite(LedgeSpacing)
|| !FMath::IsFinite(LedgeDepth)
|| !FMath::IsFinite(MinimumFloor)
|| !FMath::IsFinite(MaximumFloor)
if (!VoxelMath::IsFinite(StrateBottomZ)
|| !VoxelMath::IsFinite(InteriorBottomZ)
|| !VoxelMath::IsFinite(InteriorTopZ)
|| !VoxelMath::IsFinite(LedgeSpacing)
|| !VoxelMath::IsFinite(LedgeDepth)
|| !VoxelMath::IsFinite(MinimumFloor)
|| !VoxelMath::IsFinite(MaximumFloor)
|| !(MaximumFloor > MinimumFloor))
{
return 0.5f * (InteriorBottomZ + InteriorTopZ);
@@ -153,12 +154,12 @@ namespace VoxelPassageGeometry
const float FloorRadius = FMath::Max(0.5f, SafeRadius - 0.5f);
if (!(SafeRadius > 0.0f)
|| !(BaseDensity > 0.0f)
|| !FMath::IsFinite(WorldX)
|| !FMath::IsFinite(WorldY)
|| !FMath::IsFinite(WorldZ)
|| !FMath::IsFinite(FloorZ)
|| !FMath::IsFinite(Start.X) || !FMath::IsFinite(Start.Y)
|| !FMath::IsFinite(End.X) || !FMath::IsFinite(End.Y))
|| !VoxelMath::IsFinite(WorldX)
|| !VoxelMath::IsFinite(WorldY)
|| !VoxelMath::IsFinite(WorldZ)
|| !VoxelMath::IsFinite(FloorZ)
|| !VoxelMath::IsFinite(Start.X) || !VoxelMath::IsFinite(Start.Y)
|| !VoxelMath::IsFinite(End.X) || !VoxelMath::IsFinite(End.Y))
{
return;
}
@@ -218,14 +219,14 @@ namespace VoxelPassageGeometry
const float CoreRadius = FMath::Max(0.5f, SafeRadius - 1.0f);
if (!(SafeRadius > 0.0f)
|| !(BaseDensity > 0.0f)
|| !FMath::IsFinite(WorldX)
|| !FMath::IsFinite(WorldY)
|| !FMath::IsFinite(WorldZ)
|| !FMath::IsFinite(FloorZ)
|| !FMath::IsFinite(Start.X) || !FMath::IsFinite(Start.Y)
|| !FMath::IsFinite(Start.Z)
|| !FMath::IsFinite(End.X) || !FMath::IsFinite(End.Y)
|| !FMath::IsFinite(End.Z))
|| !VoxelMath::IsFinite(WorldX)
|| !VoxelMath::IsFinite(WorldY)
|| !VoxelMath::IsFinite(WorldZ)
|| !VoxelMath::IsFinite(FloorZ)
|| !VoxelMath::IsFinite(Start.X) || !VoxelMath::IsFinite(Start.Y)
|| !VoxelMath::IsFinite(Start.Z)
|| !VoxelMath::IsFinite(End.X) || !VoxelMath::IsFinite(End.Y)
|| !VoxelMath::IsFinite(End.Z))
{
return;
}
@@ -360,8 +361,8 @@ namespace VoxelPassageGeometry
}
return bFoundSegment
&& FMath::IsFinite(OutFloorZ)
&& FMath::IsFinite(OutSupportRadius)
&& VoxelMath::IsFinite(OutFloorZ)
&& VoxelMath::IsFinite(OutSupportRadius)
&& OutSupportRadius > 0.0f
&& BestDistanceSquared <= FMath::Square(OutSupportRadius);
}
@@ -405,10 +406,10 @@ namespace VoxelPassageGeometry
{
FOriginLandingGeometry Result;
if (!(OriginRadius > 0.0f)
|| !FMath::IsFinite(StrateTopZ)
|| !FMath::IsFinite(StrateBottomZ)
|| !FMath::IsFinite(SealThickness)
|| !FMath::IsFinite(OriginRadius))
|| !VoxelMath::IsFinite(StrateTopZ)
|| !VoxelMath::IsFinite(StrateBottomZ)
|| !VoxelMath::IsFinite(SealThickness)
|| !VoxelMath::IsFinite(OriginRadius))
{
return Result;
}
@@ -429,10 +430,10 @@ namespace VoxelPassageGeometry
+ Result.FloorThickness + SealSafetyMarginVoxels;
const float MaximumFloor = InnerTop
- DesiredHeight - SealSafetyMarginVoxels;
if (!FMath::IsFinite(InnerBottom) || !FMath::IsFinite(InnerTop)
if (!VoxelMath::IsFinite(InnerBottom) || !VoxelMath::IsFinite(InnerTop)
|| !(InnerTop > InnerBottom)
|| !FMath::IsFinite(MinimumFloor)
|| !FMath::IsFinite(MaximumFloor)
|| !VoxelMath::IsFinite(MinimumFloor)
|| !VoxelMath::IsFinite(MaximumFloor)
|| MaximumFloor < MinimumFloor)
{
Result.HalfWidth = 0.0f;
@@ -455,8 +456,8 @@ namespace VoxelPassageGeometry
FORCEINLINE bool LatticeAxisHasSampleInInterval(
float Min, float Max, float Origin, int32 Step)
{
if (Step <= 0 || !FMath::IsFinite(Min) || !FMath::IsFinite(Max)
|| !FMath::IsFinite(Origin) || Min > Max)
if (Step <= 0 || !VoxelMath::IsFinite(Min) || !VoxelMath::IsFinite(Max)
|| !VoxelMath::IsFinite(Origin) || Min > Max)
{
return false;
}
+45
View File
@@ -8,6 +8,51 @@
#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
//=============================================================================