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:
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"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|||||||
Reference in new issue
Block a user