refactor(dead-code): remove functions, members and types with no caller
Each symbol below had zero references in Source/ (tests included), Tools/, Config/ and the build files after comment/string stripping. Functions: EvaluateTunnelCoreSDF, EvaluateSDF (uncached wrapper), IsTunnelSupportFloorWorldPoint, BuildTunnelSupportFloorColumn, IsTunnelSupportFloorColumnZ, GetTunnelSupportFloorColumnBand, VF_TunnelFloorAtSegment, VF_ProjectSweptTunnelFloor, FVoxelWormField EvaluateExact, ApplyPassageLandingAirMC, ApplyPassageTunnelAirMC, GetGenerationParamsFingerprint, FVoxelStrateCorpus::LoadFromSettings, GetSkippedDefinitions, VF_RollStrateParams, VF_ArePlayerFitConnectedWithSampler, VF_GetVoxelSeasonSelectionReasonName, UVoxelSeasonAsset::GetManifestContentHash, FVoxelStackSampler::IsRunning, CompareSkippedPostValue, MakeSurfaceColumnSource, WriteObjTile, ExploreEffectName, ExploreTileClassName, and the VoxelTypes.h chunk-local helpers (WorldToLocalCoord, ChunkToWorldPos, LocalToIndex, IndexToLocal, IsValidLocalCoord, GetFaceDirection, GetFaceNormal, CHUNK_SIZE_SQUARED, CHUNK_VOLUME). Members/types: write-only floor flags (FVoxelOpSample:: bProtectedStructuralFloor, StructuralFloorMinimumDensity, bTunnelCoreSupportFloor; bSupportFloor on the tunnel evaluations; FTunnelFloorSegmentProfile::NumSteps), UVoxelStrateManager::BlendChunks, unused FSummary counters in the stack sampler, two unused FVoxelSeasonCompositionSettings aliases, and a few unused locals/constants. No UPROPERTY, UFUNCTION, reflected type or enum was touched. Behaviour is unchanged: removed code was unreachable or only written, never read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URDGLsu7c4nunqNFPJEFPU
This commit is contained in:
26 files changed
+9
-1113
No files matched your search
@@ -81,7 +81,6 @@ namespace
|
|||||||
struct FVFTunnelShapeEvaluation
|
struct FVFTunnelShapeEvaluation
|
||||||
{
|
{
|
||||||
float SDF = FLT_MAX;
|
float SDF = FLT_MAX;
|
||||||
bool bSupportFloor = false;
|
|
||||||
bool bHasSweptFloor = false;
|
bool bHasSweptFloor = false;
|
||||||
float SweptFloorZ = -FLT_MAX;
|
float SweptFloorZ = -FLT_MAX;
|
||||||
float SweptFloorRadius = 0.0f;
|
float SweptFloorRadius = 0.0f;
|
||||||
@@ -548,7 +547,6 @@ namespace
|
|||||||
Profile.NaturalStartFloorZ = FloorA;
|
Profile.NaturalStartFloorZ = FloorA;
|
||||||
Profile.NaturalEndFloorZ = FloorB;
|
Profile.NaturalEndFloorZ = FloorB;
|
||||||
Profile.bLedgeTransition = false;
|
Profile.bLedgeTransition = false;
|
||||||
Profile.NumSteps = 0;
|
|
||||||
|
|
||||||
if (bHasLedgeLevels)
|
if (bHasLedgeLevels)
|
||||||
{
|
{
|
||||||
@@ -934,27 +932,6 @@ namespace
|
|||||||
return FloorZ;
|
return FloorZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE float VF_TunnelFloorAtSegment(
|
|
||||||
const FVector& A, float RadiusA,
|
|
||||||
const FVector& B, float RadiusB,
|
|
||||||
float T, int32 SegmentIndex, int32 NumSegments,
|
|
||||||
const FVector& Position,
|
|
||||||
const FCachedTunnel& Tunnel,
|
|
||||||
const void* CacheIdentity, int32 TunnelIndex,
|
|
||||||
bool bEvaluateRelief,
|
|
||||||
const FVFFloorReliefColumnKey& Column,
|
|
||||||
const FTunnelFloorSegmentProfile* FloorProfile,
|
|
||||||
const FVFRoomFloorOwnership* RoomFloorOwnership)
|
|
||||||
{
|
|
||||||
const FVFTunnelFloorTerms Terms = VF_TunnelFloorTerms(
|
|
||||||
A, RadiusA, B, RadiusB,
|
|
||||||
T, SegmentIndex, NumSegments, Tunnel, FloorProfile,
|
|
||||||
RoomFloorOwnership);
|
|
||||||
return VF_TunnelFloorFromTerms(
|
|
||||||
Position, Tunnel, Terms,
|
|
||||||
CacheIdentity, TunnelIndex, bEvaluateRelief, Column);
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCEINLINE bool VF_ProjectTunnelSegmentXY(
|
FORCEINLINE bool VF_ProjectTunnelSegmentXY(
|
||||||
const FVector& Position, const FVector& A, const FVector& B,
|
const FVector& Position, const FVector& A, const FVector& B,
|
||||||
float& OutT, float& OutDistanceSquared)
|
float& OutT, float& OutDistanceSquared)
|
||||||
@@ -1229,76 +1206,6 @@ namespace
|
|||||||
RoomFloorOwnership);
|
RoomFloorOwnership);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VF_ProjectSweptTunnelFloor(
|
|
||||||
const FVector& Position,
|
|
||||||
const FCachedTunnel& Tunnel,
|
|
||||||
bool bWorldChain,
|
|
||||||
float& OutFloorZ,
|
|
||||||
float& OutSupportRadius,
|
|
||||||
const void* CacheIdentity, int32 TunnelIndex,
|
|
||||||
const FVFRoomFloorOwnership* RoomFloorOwnership = nullptr)
|
|
||||||
{
|
|
||||||
const FVFFloorReliefColumnKey ReliefColumn =
|
|
||||||
VF_MakeFloorReliefColumnKey(
|
|
||||||
static_cast<float>(Position.X), static_cast<float>(Position.Y));
|
|
||||||
const TArray<FVector>& ControlPoints = bWorldChain
|
|
||||||
? Tunnel.WorldControlPoints : Tunnel.ControlPoints;
|
|
||||||
const TArray<float>& ControlRadii = bWorldChain
|
|
||||||
? Tunnel.WorldControlRadii : Tunnel.ControlRadii;
|
|
||||||
if (ControlPoints.Num() < 2
|
|
||||||
|| ControlRadii.Num() != ControlPoints.Num())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32 ControlPointCount = ControlPoints.Num();
|
|
||||||
const int32 NumSegments = ControlPointCount - 1;
|
|
||||||
const FVector* ControlPointData = ControlPoints.GetData();
|
|
||||||
const float* ControlRadiusData = ControlRadii.GetData();
|
|
||||||
const TArray<FTunnelFloorSegmentProfile>* FloorProfiles = bWorldChain
|
|
||||||
? &Tunnel.WorldFloorProfiles : &Tunnel.FloorProfiles;
|
|
||||||
const FTunnelFloorSegmentProfile* FloorProfileData =
|
|
||||||
FloorProfiles->Num() == NumSegments ? FloorProfiles->GetData() : nullptr;
|
|
||||||
float BestDistanceSquared = FLT_MAX;
|
|
||||||
bool bFound = false;
|
|
||||||
for (int32 SegmentIndex = 0;
|
|
||||||
SegmentIndex < NumSegments;
|
|
||||||
++SegmentIndex)
|
|
||||||
{
|
|
||||||
float T = 0.0f;
|
|
||||||
float DistanceSquared = FLT_MAX;
|
|
||||||
if (!VF_ProjectTunnelSegmentXY(
|
|
||||||
Position,
|
|
||||||
ControlPointData[SegmentIndex], ControlPointData[SegmentIndex + 1],
|
|
||||||
T, DistanceSquared)
|
|
||||||
|| DistanceSquared >= BestDistanceSquared)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float RadiusA = ControlRadiusData[SegmentIndex];
|
|
||||||
const float RadiusB = ControlRadiusData[SegmentIndex + 1];
|
|
||||||
OutFloorZ = VF_TunnelFloorAtSegment(
|
|
||||||
ControlPointData[SegmentIndex], RadiusA,
|
|
||||||
ControlPointData[SegmentIndex + 1], RadiusB,
|
|
||||||
T, SegmentIndex, NumSegments, Position, Tunnel,
|
|
||||||
CacheIdentity, TunnelIndex, /*bEvaluateRelief=*/true,
|
|
||||||
ReliefColumn,
|
|
||||||
FloorProfileData != nullptr ? FloorProfileData + SegmentIndex : nullptr,
|
|
||||||
RoomFloorOwnership);
|
|
||||||
OutSupportRadius = FMath::Max(
|
|
||||||
FMath::Min(FMath::Abs(RadiusA), FMath::Abs(RadiusB)) - 0.5f,
|
|
||||||
VoxelPassageGeometry::PlayerRadiusVoxels);
|
|
||||||
BestDistanceSquared = DistanceSquared;
|
|
||||||
bFound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bFound
|
|
||||||
&& VoxelMath::IsFinite(OutFloorZ)
|
|
||||||
&& VoxelMath::IsFinite(OutSupportRadius)
|
|
||||||
&& BestDistanceSquared <= FMath::Square(OutSupportRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FChunkSDFSpatialIndex::Reset()
|
void FChunkSDFSpatialIndex::Reset()
|
||||||
@@ -8960,50 +8867,6 @@ float VoxelCaveMorphology::EvaluateSDFCached(
|
|||||||
return MinSDF;
|
return MinSDF;
|
||||||
}
|
}
|
||||||
|
|
||||||
float VoxelCaveMorphology::EvaluateTunnelCoreSDF(
|
|
||||||
float WorldX, float WorldY, float WorldZ,
|
|
||||||
const FChunkSDFCache& Cache,
|
|
||||||
bool bUseSpatialIndex)
|
|
||||||
{
|
|
||||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
|
||||||
{
|
|
||||||
return FLT_MAX;
|
|
||||||
}
|
|
||||||
const FVector Pos(WorldX, WorldY, WorldZ);
|
|
||||||
float MinSDF = FLT_MAX;
|
|
||||||
const FCachedTunnel* TunnelData = Cache.Tunnels.GetData();
|
|
||||||
|
|
||||||
auto EvaluateTunnel = [&](int32 TunnelIdx)
|
|
||||||
{
|
|
||||||
const FCachedTunnel& Tunnel = TunnelData[TunnelIdx];
|
|
||||||
if (Tunnel.SDFInfluenceRadius > 0.0f
|
|
||||||
&& VF_DistanceSquaredToAabb(
|
|
||||||
WorldX, WorldY, WorldZ,
|
|
||||||
Tunnel.SDFCenterlineMin, Tunnel.SDFCenterlineMax)
|
|
||||||
> FMath::Square(Tunnel.SDFInfluenceRadius))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (VF_FloatDistSquared(WorldX, WorldY, WorldZ, Tunnel.BoundCenter)
|
|
||||||
> Tunnel.BoundRadiusSq)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MinSDF = FMath::Min(
|
|
||||||
MinSDF,
|
|
||||||
VF_EvaluateSweptTunnel(
|
|
||||||
Pos, Tunnel, /*bWorldChain=*/false, Cache.SDFBlendRadius,
|
|
||||||
/*bApplyFloorCut=*/false, &Cache, TunnelIdx).SDF);
|
|
||||||
};
|
|
||||||
|
|
||||||
VF_ForEachSpatialCandidate(
|
|
||||||
Cache.TunnelSpatialIndex, Cache.Tunnels.Num(), WorldX, WorldY, EvaluateTunnel,
|
|
||||||
bUseSpatialIndex);
|
|
||||||
|
|
||||||
return MinSDF;
|
|
||||||
}
|
|
||||||
|
|
||||||
FTunnelCoreWorldEvaluation VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
FTunnelCoreWorldEvaluation VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||||
float WorldX, float WorldY, float WorldZ,
|
float WorldX, float WorldY, float WorldZ,
|
||||||
const FChunkSDFCache& Cache,
|
const FChunkSDFCache& Cache,
|
||||||
@@ -9454,7 +9317,7 @@ bool VoxelCaveMorphology::AnyTunnelCoreWorldNearLattice(
|
|||||||
// The broad sphere already encloses the swept radius and finite floor band. Add the
|
// The broad sphere already encloses the swept radius and finite floor band. Add the
|
||||||
// vertical relief and room-mouth ownership envelopes before asking whether the lattice
|
// vertical relief and room-mouth ownership envelopes before asking whether the lattice
|
||||||
// box can touch it. A miss is therefore an identity proof for the core evaluator and
|
// box can touch it. A miss is therefore an identity proof for the core evaluator and
|
||||||
// its support/room-floor tail; its only field writes are bSupportFloor, bRoomFloor, or
|
// its support/room-floor tail; its only field writes are bRoomFloor or
|
||||||
// CoreSDF < -inset, all of which are inside this envelope.
|
// CoreSDF < -inset, all of which are inside this envelope.
|
||||||
const float Reach = (
|
const float Reach = (
|
||||||
FMath::Sqrt(FMath::Max(BoundRadiusSq, 0.0f))
|
FMath::Sqrt(FMath::Max(BoundRadiusSq, 0.0f))
|
||||||
@@ -9477,254 +9340,6 @@ float VoxelCaveMorphology::EvaluateTunnelCoreWorldSDF(
|
|||||||
WorldX, WorldY, WorldZ, Cache, nullptr, bUseSpatialIndex).SDF;
|
WorldX, WorldY, WorldZ, Cache, nullptr, bUseSpatialIndex).SDF;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelCaveMorphology::IsTunnelSupportFloorWorldPoint(
|
|
||||||
float WorldX, float WorldY, float WorldZ,
|
|
||||||
const FChunkSDFCache& Cache,
|
|
||||||
bool bUseSpatialIndex)
|
|
||||||
{
|
|
||||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const FVector Pos(WorldX, WorldY, WorldZ);
|
|
||||||
const FCachedTunnel* TunnelData = Cache.Tunnels.GetData();
|
|
||||||
|
|
||||||
auto TestTunnel = [&](int32 TunnelIdx) -> bool
|
|
||||||
{
|
|
||||||
const FCachedTunnel& Tunnel = TunnelData[TunnelIdx];
|
|
||||||
const bool bHasWorldChain = Tunnel.WorldControlPoints.Num() >= 2
|
|
||||||
&& Tunnel.WorldControlRadii.Num() == Tunnel.WorldControlPoints.Num();
|
|
||||||
const FVector& CenterlineMin = bHasWorldChain
|
|
||||||
? Tunnel.WorldCenterlineMin : Tunnel.SDFCenterlineMin;
|
|
||||||
const FVector& CenterlineMax = bHasWorldChain
|
|
||||||
? Tunnel.WorldCenterlineMax : Tunnel.SDFCenterlineMax;
|
|
||||||
const float InfluenceRadius = bHasWorldChain
|
|
||||||
? Tunnel.WorldInfluenceRadius : Tunnel.SDFInfluenceRadius;
|
|
||||||
if (InfluenceRadius > 0.0f
|
|
||||||
&& VF_DistanceSquaredToAabb(
|
|
||||||
WorldX, WorldY, WorldZ, CenterlineMin, CenterlineMax)
|
|
||||||
> FMath::Square(InfluenceRadius))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FVector& BoundCenter = bHasWorldChain
|
|
||||||
? Tunnel.WorldBoundCenter : Tunnel.BoundCenter;
|
|
||||||
const float BoundRadiusSq = bHasWorldChain
|
|
||||||
? Tunnel.WorldBoundRadiusSq : Tunnel.BoundRadiusSq;
|
|
||||||
if (BoundRadiusSq > 0.0f
|
|
||||||
&& VF_FloatDistSquared(WorldX, WorldY, WorldZ, BoundCenter) > BoundRadiusSq)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FVFRoomFloorOwnership RoomMouthOwnership =
|
|
||||||
VF_FindWorldTunnelMouthOwnership(Pos, Tunnel, Cache.SDFBlendRadius);
|
|
||||||
if (RoomMouthOwnership.bValid)
|
|
||||||
{
|
|
||||||
float ProjectedFloorZ = 0.0f;
|
|
||||||
float SupportRadius = 0.0f;
|
|
||||||
if (VF_ProjectSweptTunnelFloor(
|
|
||||||
Pos, Tunnel, bHasWorldChain, ProjectedFloorZ, SupportRadius,
|
|
||||||
&Cache, TunnelIdx, &RoomMouthOwnership)
|
|
||||||
&& ProjectedFloorZ > RoomMouthOwnership.FloorZ + KINDA_SMALL_NUMBER)
|
|
||||||
{
|
|
||||||
// Only a raised tunnel apron is clipped. If the tunnel is lower, the room's
|
|
||||||
// SmoothMax floor already wins naturally and retaining this support band is
|
|
||||||
// capability-safe for legacy callers.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return VF_EvaluateSweptTunnel(
|
|
||||||
Pos, Tunnel, bHasWorldChain, Cache.SDFBlendRadius,
|
|
||||||
/*bApplyFloorCut=*/true, &Cache, TunnelIdx,
|
|
||||||
&RoomMouthOwnership).bSupportFloor;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool bSupport = false;
|
|
||||||
int32 CandidateCount = 0;
|
|
||||||
auto TestRange = [&](int32 Begin, int32 End)
|
|
||||||
{
|
|
||||||
const int32* ItemIndexData = Cache.TunnelSpatialIndex.ItemIndices.GetData();
|
|
||||||
for (int32 Cursor = Begin; Cursor < End; ++Cursor)
|
|
||||||
{
|
|
||||||
const int32 TunnelIdx = ItemIndexData[Cursor];
|
|
||||||
if (!Cache.Tunnels.IsValidIndex(TunnelIdx))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++CandidateCount;
|
|
||||||
if (TestTunnel(TunnelIdx))
|
|
||||||
{
|
|
||||||
bSupport = true;
|
|
||||||
if (VoxelDensityProfile::AreCountersEnabled())
|
|
||||||
{
|
|
||||||
VoxelDensityProfile::AddCounter(
|
|
||||||
VoxelDensityProfile::ECounter::TunnelCoreEvaluated);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int32 Begin = 0;
|
|
||||||
int32 End = 0;
|
|
||||||
if (bUseSpatialIndex && Cache.TunnelSpatialIndex.GetRange(WorldX, WorldY, Begin, End))
|
|
||||||
{
|
|
||||||
TestRange(Begin, End);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int32 TunnelIdx = 0; TunnelIdx < Cache.Tunnels.Num() && !bSupport; ++TunnelIdx)
|
|
||||||
{
|
|
||||||
++CandidateCount;
|
|
||||||
if (TestTunnel(TunnelIdx))
|
|
||||||
{
|
|
||||||
bSupport = true;
|
|
||||||
if (VoxelDensityProfile::AreCountersEnabled())
|
|
||||||
{
|
|
||||||
VoxelDensityProfile::AddCounter(
|
|
||||||
VoxelDensityProfile::ECounter::TunnelCoreEvaluated);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (VoxelDensityProfile::AreCountersEnabled())
|
|
||||||
{
|
|
||||||
VoxelDensityProfile::AddCounter(
|
|
||||||
VoxelDensityProfile::ECounter::TunnelCoreCandidates,
|
|
||||||
static_cast<uint64>(CandidateCount));
|
|
||||||
}
|
|
||||||
return bSupport;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VoxelCaveMorphology::BuildTunnelSupportFloorColumn(
|
|
||||||
float WorldX, float WorldY,
|
|
||||||
const FChunkSDFCache& Cache,
|
|
||||||
FTunnelSupportFloorColumn& OutColumn,
|
|
||||||
bool bUseSpatialIndex)
|
|
||||||
{
|
|
||||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
|
||||||
{
|
|
||||||
OutColumn.Reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
|
||||||
VoxelDensityProfile::EBucket::TunnelCoreSupport);
|
|
||||||
OutColumn.Reset();
|
|
||||||
|
|
||||||
if (VoxelDensityProfile::AreCountersEnabled())
|
|
||||||
{
|
|
||||||
VoxelDensityProfile::AddCounter(
|
|
||||||
VoxelDensityProfile::ECounter::TunnelSupportColumnBuilds);
|
|
||||||
}
|
|
||||||
|
|
||||||
const FVector ColumnPosition(WorldX, WorldY, 0.0f);
|
|
||||||
const FCachedTunnel* TunnelData = Cache.Tunnels.GetData();
|
|
||||||
|
|
||||||
auto EvaluateTunnel = [&](int32 TunnelIdx)
|
|
||||||
{
|
|
||||||
const FCachedTunnel& Tunnel = TunnelData[TunnelIdx];
|
|
||||||
const FVFRoomFloorOwnership RoomMouthOwnership =
|
|
||||||
VF_FindWorldTunnelMouthOwnership(ColumnPosition, Tunnel, Cache.SDFBlendRadius);
|
|
||||||
float FloorZ = 0.0f;
|
|
||||||
float SupportRadius = 0.0f;
|
|
||||||
if (!VF_ProjectSweptTunnelFloor(
|
|
||||||
ColumnPosition, Tunnel, /*bWorldChain=*/true,
|
|
||||||
FloorZ, SupportRadius, &Cache, TunnelIdx, &RoomMouthOwnership))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float MinZ = FloorZ - VoxelPassageGeometry::LandingFloorThicknessVoxels;
|
|
||||||
float MaxZ = FloorZ + VoxelPassageGeometry::WalkableTunnelFloorAirClearanceVoxels;
|
|
||||||
|
|
||||||
// Preserve the public point predicate's world bounding sphere exactly, while resolving
|
|
||||||
// its Z interval once. The XY projection already proves the support-radius condition.
|
|
||||||
if (Tunnel.WorldBoundRadiusSq > 0.0f)
|
|
||||||
{
|
|
||||||
const float DX = WorldX - static_cast<float>(Tunnel.WorldBoundCenter.X);
|
|
||||||
const float DY = WorldY - static_cast<float>(Tunnel.WorldBoundCenter.Y);
|
|
||||||
const float Remaining = Tunnel.WorldBoundRadiusSq - (DX * DX + DY * DY);
|
|
||||||
if (Remaining < 0.0f)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const float HalfZ = FMath::Sqrt(Remaining);
|
|
||||||
MinZ = FMath::Max(MinZ, static_cast<float>(Tunnel.WorldBoundCenter.Z) - HalfZ);
|
|
||||||
MaxZ = FMath::Min(MaxZ, static_cast<float>(Tunnel.WorldBoundCenter.Z) + HalfZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MinZ <= MaxZ)
|
|
||||||
{
|
|
||||||
FTunnelSupportFloorInterval& Interval =
|
|
||||||
OutColumn.Intervals.Emplace_GetRef();
|
|
||||||
Interval.TunnelIndex = TunnelIdx;
|
|
||||||
Interval.FloorZ = FloorZ;
|
|
||||||
Interval.MinZ = MinZ;
|
|
||||||
Interval.MaxZ = MaxZ;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const int32 CandidateCount = VF_ForEachSpatialCandidate(
|
|
||||||
Cache.TunnelSpatialIndex, Cache.Tunnels.Num(), WorldX, WorldY, EvaluateTunnel,
|
|
||||||
bUseSpatialIndex);
|
|
||||||
if (VoxelDensityProfile::AreCountersEnabled())
|
|
||||||
{
|
|
||||||
VoxelDensityProfile::AddCounter(
|
|
||||||
VoxelDensityProfile::ECounter::TunnelSupportColumnCandidates,
|
|
||||||
static_cast<uint64>(CandidateCount));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Candidate IDs are deterministic and allow the world evaluator to find a
|
|
||||||
// tunnel's own band without re-running the XY projection. The public union
|
|
||||||
// query below simply tests every band; graph columns normally contain only a
|
|
||||||
// handful of candidates.
|
|
||||||
OutColumn.Intervals.Sort(
|
|
||||||
[](const FTunnelSupportFloorInterval& A,
|
|
||||||
const FTunnelSupportFloorInterval& B)
|
|
||||||
{
|
|
||||||
return A.TunnelIndex < B.TunnelIndex;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VoxelCaveMorphology::IsTunnelSupportFloorColumnZ(
|
|
||||||
float WorldZ,
|
|
||||||
const FTunnelSupportFloorColumn& Column)
|
|
||||||
{
|
|
||||||
for (const FTunnelSupportFloorInterval& Interval : Column.Intervals)
|
|
||||||
{
|
|
||||||
if (WorldZ <= Interval.MaxZ)
|
|
||||||
{
|
|
||||||
if (WorldZ >= Interval.MinZ)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VoxelCaveMorphology::GetTunnelSupportFloorColumnBand(
|
|
||||||
int32 TunnelIndex,
|
|
||||||
const FTunnelSupportFloorColumn& Column,
|
|
||||||
float& OutFloorZ,
|
|
||||||
float& OutMinZ,
|
|
||||||
float& OutMaxZ)
|
|
||||||
{
|
|
||||||
for (const FTunnelSupportFloorInterval& Interval : Column.Intervals)
|
|
||||||
{
|
|
||||||
if (Interval.TunnelIndex == TunnelIndex)
|
|
||||||
{
|
|
||||||
OutFloorZ = Interval.FloorZ;
|
|
||||||
OutMinZ = Interval.MinZ;
|
|
||||||
OutMaxZ = Interval.MaxZ;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// CONVENIENCE WRAPPER (backward compatible)
|
// CONVENIENCE WRAPPER (backward compatible)
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -9734,35 +9349,3 @@ bool VoxelCaveMorphology::GetTunnelSupportFloorColumnBand(
|
|||||||
// internally widens the COLLECT region to (2*MaxTunnelLength + MaxInfluence) so the
|
// internally widens the COLLECT region to (2*MaxTunnelLength + MaxInfluence) so the
|
||||||
// graph it builds is the same one the chunk path would build at this point.
|
// graph it builds is the same one the chunk path would build at this point.
|
||||||
|
|
||||||
float VoxelCaveMorphology::EvaluateSDF(
|
|
||||||
float WorldX, float WorldY, float WorldZ,
|
|
||||||
const FStrateGenerationParams& Params,
|
|
||||||
uint32 Seed, int32 StrateIndex)
|
|
||||||
{
|
|
||||||
const float RoomRadiusEnvelope = FMath::Max(
|
|
||||||
FMath::Abs(Params.MinRoomRadius), FMath::Abs(Params.MaxRoomRadius));
|
|
||||||
const float TunnelRadiusEnvelope = FMath::Max(
|
|
||||||
0.5f,
|
|
||||||
FMath::Max(FMath::Abs(Params.TunnelMinRadius), FMath::Abs(Params.TunnelMaxRadius))
|
|
||||||
* 1.18f);
|
|
||||||
const float FloorReliefEnvelope = FMath::Abs(Params.FloorReliefStrength)
|
|
||||||
* VOXEL_NOISE_SCALE * 1.5f;
|
|
||||||
const float BlendEnvelope = FMath::Max(Params.SDFBlendRadius, 0.0f);
|
|
||||||
const float Margin = FMath::Max(
|
|
||||||
RoomRadiusEnvelope + FloorReliefEnvelope,
|
|
||||||
FMath::Abs(Params.TunnelWarpStrength) + TunnelRadiusEnvelope
|
|
||||||
) + BlendEnvelope * 3.0f;
|
|
||||||
|
|
||||||
FChunkSDFCache TempCache;
|
|
||||||
BuildChunkCache(
|
|
||||||
TempCache,
|
|
||||||
WorldX - Margin, WorldY - Margin,
|
|
||||||
WorldX + Margin, WorldY + Margin,
|
|
||||||
Params, Seed, StrateIndex
|
|
||||||
);
|
|
||||||
|
|
||||||
return EvaluateSDFCached(
|
|
||||||
WorldX, WorldY, WorldZ,
|
|
||||||
TempCache, Params.SDFBlendRadius
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -361,33 +361,6 @@ namespace
|
|||||||
// STAGE B5 DECISION: repeated early-out in each op, NOT a scoping container — the stack is a flat
|
// STAGE B5 DECISION: repeated early-out in each op, NOT a scoping container — the stack is a flat
|
||||||
// list that ClassifyBox folds op by op, and an op that only exists inside a container is not
|
// list that ClassifyBox folds op by op, and an op that only exists inside a container is not
|
||||||
// composable. Cost stated honestly: twelve predictable compares instead of one branch.
|
// composable. Cost stated honestly: twelve predictable compares instead of one branch.
|
||||||
/** Distance d'un point à un SEGMENT (pas à une droite). Écrite ici plutôt que prise dans
|
|
||||||
* `FMath` : cinq lignes, aucune ambiguïté d'API, et elle sert une borne de correction — le
|
|
||||||
* genre d'endroit où « je crois que cette fonction fait ça » n'est pas suffisant. */
|
|
||||||
FORCEINLINE float VF_DistPointSegment(const FVector& P, const FVector& A, const FVector& B)
|
|
||||||
{
|
|
||||||
const FVector AB = B - A;
|
|
||||||
const double LenSq = FVector::DotProduct(AB, AB);
|
|
||||||
const double T = (LenSq > KINDA_SMALL_NUMBER)
|
|
||||||
? FMath::Clamp(FVector::DotProduct(P - A, AB) / LenSq, 0.0, 1.0)
|
|
||||||
: 0.0;
|
|
||||||
return (float)FVector::Dist(P, A + AB * T);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** La même chose en 2D, pour les connecteurs de puits : ce sont des capsules HORIZONTALES, donc
|
|
||||||
* Z se teste exactement et seul XY demande une distance point-segment. */
|
|
||||||
FORCEINLINE float VF_DistPointSegment2D(const FVector2D& P, const FVector2D& A, const FVector2D& B)
|
|
||||||
{
|
|
||||||
const FVector2D AB = B - A;
|
|
||||||
const double LenSq = (double)AB.X * AB.X + (double)AB.Y * AB.Y;
|
|
||||||
const double T = (LenSq > KINDA_SMALL_NUMBER)
|
|
||||||
? FMath::Clamp(((double)(P.X - A.X) * AB.X + (double)(P.Y - A.Y) * AB.Y) / LenSq, 0.0, 1.0)
|
|
||||||
: 0.0;
|
|
||||||
const double DX = (double)P.X - ((double)A.X + AB.X * T);
|
|
||||||
const double DY = (double)P.Y - ((double)A.Y + AB.Y * T);
|
|
||||||
return (float)FMath::Sqrt(DX * DX + DY * DY);
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCEINLINE bool VF_NearCaveSurface(float Sdf, float SDFBlendRadius)
|
FORCEINLINE bool VF_NearCaveSurface(float Sdf, float SDFBlendRadius)
|
||||||
{
|
{
|
||||||
// Transcrit tel quel, ordre des comparaisons compris :
|
// Transcrit tel quel, ordre des comparaisons compris :
|
||||||
@@ -795,16 +768,6 @@ namespace
|
|||||||
return FVector((X + 0.5f) * CellSize, (Y + 0.5f) * CellSize, (Z + 0.5f) * CellSize);
|
return FVector((X + 0.5f) * CellSize, (Y + 0.5f) * CellSize, (Z + 0.5f) * CellSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sur-approximation volontaire : boîte englobante du segment contre la boîte élargie.
|
|
||||||
// Un test capsule/AABB exact serait plus serré ; il coûterait plus cher pour un gain nul
|
|
||||||
// ici, car la réponse ne sert qu'à un rejet grossier par tuile.
|
|
||||||
static bool SegmentHitsBox(const FVector& A, const FVector& B, const FVector& Min, const FVector& Max)
|
|
||||||
{
|
|
||||||
return FMath::Min(A.X, B.X) <= Max.X && FMath::Max(A.X, B.X) >= Min.X
|
|
||||||
&& FMath::Min(A.Y, B.Y) <= Max.Y && FMath::Max(A.Y, B.Y) >= Min.Y
|
|
||||||
&& FMath::Min(A.Z, B.Z) <= Max.Z && FMath::Max(A.Z, B.Z) >= Min.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Le cache par CELLULE, partagé avec le même contrat que GetMazeDensity. Il est `thread_local` et non
|
* Le cache par CELLULE, partagé avec le même contrat que GetMazeDensity. Il est `thread_local` et non
|
||||||
* membre parce que la pile est PARTAGÉE entre workers en lecture — un membre mutable serait
|
* membre parce que la pile est PARTAGÉE entre workers en lecture — un membre mutable serait
|
||||||
@@ -1120,12 +1083,6 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sans biomes — délègue, pour qu'il n'existe qu'UN corps de construction et UN compteur
|
|
||||||
* d'identité. Deux constructeurs qui s'initialisent chacun de leur côté, c'est deux
|
|
||||||
* endroits où oublier un membre. */
|
|
||||||
FSurfaceColumnSource(const FSurfaceGenerationParams& InP, int32 Seed)
|
|
||||||
: FSurfaceColumnSource(InP, Seed, TArray<FSurfaceGenerationParams>(), nullptr) {}
|
|
||||||
|
|
||||||
void BuildSingleBiome(const FSurfaceGenerationParams& InP, int32 Seed)
|
void BuildSingleBiome(const FSurfaceGenerationParams& InP, int32 Seed)
|
||||||
{
|
{
|
||||||
// Construite à la main (pas via BuildSurfaceHeightStack) pour GARDER le pointeur vers la
|
// Construite à la main (pas via BuildSurfaceHeightStack) pour GARDER le pointeur vers la
|
||||||
@@ -1342,8 +1299,6 @@ namespace
|
|||||||
return S.Height;
|
return S.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FSurfaceGenerationParams& GetParams() const { return P; }
|
|
||||||
|
|
||||||
EVoxelOpRole GetRole() const override { return EVoxelOpRole::FieldSource; }
|
EVoxelOpRole GetRole() const override { return EVoxelOpRole::FieldSource; }
|
||||||
EVoxelOpChannelMask ChannelReads() const override { return VoxelOpChannels::None; }
|
EVoxelOpChannelMask ChannelReads() const override { return VoxelOpChannels::None; }
|
||||||
EVoxelOpChannelMask ChannelWrites() const override { return VoxelOpChannels::Density; }
|
EVoxelOpChannelMask ChannelWrites() const override { return VoxelOpChannels::Density; }
|
||||||
@@ -4313,7 +4268,6 @@ namespace
|
|||||||
// room's own volume.
|
// room's own volume.
|
||||||
InOut.bHasTunnelCoreWorldEvaluation = true;
|
InOut.bHasTunnelCoreWorldEvaluation = true;
|
||||||
InOut.TunnelCoreWorldSDF = S.LastTunnelCoreWorldEvaluation.SDF;
|
InOut.TunnelCoreWorldSDF = S.LastTunnelCoreWorldEvaluation.SDF;
|
||||||
InOut.bTunnelCoreSupportFloor = false;
|
|
||||||
InOut.bTunnelCoreRoomFloor =
|
InOut.bTunnelCoreRoomFloor =
|
||||||
S.LastTunnelCoreWorldEvaluation.bRoomFloor;
|
S.LastTunnelCoreWorldEvaluation.bRoomFloor;
|
||||||
InOut.bHasTunnelCoreSweptFloor =
|
InOut.bHasTunnelCoreSweptFloor =
|
||||||
@@ -4322,8 +4276,6 @@ namespace
|
|||||||
S.LastTunnelCoreWorldEvaluation.SweptFloorZ;
|
S.LastTunnelCoreWorldEvaluation.SweptFloorZ;
|
||||||
InOut.TunnelCoreSweptFloorRadius =
|
InOut.TunnelCoreSweptFloorRadius =
|
||||||
S.LastTunnelCoreWorldEvaluation.SweptFloorRadius;
|
S.LastTunnelCoreWorldEvaluation.SweptFloorRadius;
|
||||||
InOut.bProtectedStructuralFloor = false;
|
|
||||||
InOut.StructuralFloorMinimumDensity = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These cache hand-offs remain valid when tunnel core is off; detail operators still
|
// These cache hand-offs remain valid when tunnel core is off; detail operators still
|
||||||
@@ -4445,7 +4397,6 @@ namespace
|
|||||||
bool bMayHaveTunnelCoreTail = false;
|
bool bMayHaveTunnelCoreTail = false;
|
||||||
uint32 ExactTailQueries = 0;
|
uint32 ExactTailQueries = 0;
|
||||||
uint32 ExactTailEvaluated = 0;
|
uint32 ExactTailEvaluated = 0;
|
||||||
uint32 ExactTailCacheHits = 0;
|
|
||||||
uint64 ExactTailCycles = 0;
|
uint64 ExactTailCycles = 0;
|
||||||
uint64 PropagateCycles = 0;
|
uint64 PropagateCycles = 0;
|
||||||
uint64 ExactPrimitiveCycles = 0;
|
uint64 ExactPrimitiveCycles = 0;
|
||||||
@@ -4534,12 +4485,6 @@ namespace
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasRoomColumnsForLastBox() const
|
|
||||||
{
|
|
||||||
const FBoxState& B = BoxState();
|
|
||||||
return !B.bValid || GetBoxCache().Columns.Num() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float RoomColumnFillSupremumForLastBox() const
|
float RoomColumnFillSupremumForLastBox() const
|
||||||
{
|
{
|
||||||
const FBoxState& B = BoxState();
|
const FBoxState& B = BoxState();
|
||||||
@@ -5623,18 +5568,6 @@ namespace
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto EffectiveZRangeToWorld = [&](float MinEffectiveZ,
|
|
||||||
float MaxEffectiveZ) -> FVector2D
|
|
||||||
{
|
|
||||||
if (P.VerticalScale > 0.0f && P.VerticalScale != 1.0f)
|
|
||||||
{
|
|
||||||
const float WorldA = MinEffectiveZ * P.VerticalScale;
|
|
||||||
const float WorldB = MaxEffectiveZ * P.VerticalScale;
|
|
||||||
return FVector2D(FMath::Min(WorldA, WorldB), FMath::Max(WorldA, WorldB));
|
|
||||||
}
|
|
||||||
return FVector2D(MinEffectiveZ, MaxEffectiveZ);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto DistanceBlockToInfiniteLineLower = [&](const FExactLatticeBlock& Block,
|
auto DistanceBlockToInfiniteLineLower = [&](const FExactLatticeBlock& Block,
|
||||||
const FVector& A,
|
const FVector& A,
|
||||||
const FVector& BPoint) -> float
|
const FVector& BPoint) -> float
|
||||||
@@ -9463,11 +9396,6 @@ namespace VoxelDensityOps
|
|||||||
return MakeUnique<FGridColumnMod>(P, Seed);
|
return MakeUnique<FGridColumnMod>(P, Seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
TUniquePtr<IVoxelDensityOp> MakeSurfaceColumnSource(const FSurfaceGenerationParams& P, int32 Seed)
|
|
||||||
{
|
|
||||||
return MakeUnique<FSurfaceColumnSource>(P, Seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildSurfaceStack(FVoxelOpStack& OutStack, const FSurfaceGenerationParams& P,
|
void BuildSurfaceStack(FVoxelOpStack& OutStack, const FSurfaceGenerationParams& P,
|
||||||
int32 Seed, float SpineRadius, const UVoxelStrateManager* StrateManager,
|
int32 Seed, float SpineRadius, const UVoxelStrateManager* StrateManager,
|
||||||
const TArray<FSurfaceGenerationParams>& PerBiomeParams,
|
const TArray<FSurfaceGenerationParams>& PerBiomeParams,
|
||||||
|
|||||||
@@ -218,11 +218,6 @@ namespace VoxelDensityProfile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnabled(bool bEnabled)
|
|
||||||
{
|
|
||||||
SetMode(bEnabled ? EMode::Sampled : EMode::Disabled, DefaultSampleInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMode(EMode Mode, uint32 SampleInterval)
|
void SetMode(EMode Mode, uint32 SampleInterval)
|
||||||
{
|
{
|
||||||
if (SampleInterval == 0)
|
if (SampleInterval == 0)
|
||||||
|
|||||||
@@ -3287,7 +3287,6 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
float BlockDensity = 0.f;
|
float BlockDensity = 0.f;
|
||||||
bool bBlockHasTunnelCore = false;
|
bool bBlockHasTunnelCore = false;
|
||||||
float BlockTunnelCoreSDF = FLT_MAX;
|
float BlockTunnelCoreSDF = FLT_MAX;
|
||||||
bool bBlockTunnelCoreSupportFloor = false;
|
|
||||||
bool bBlockTunnelCoreRoomFloor = false;
|
bool bBlockTunnelCoreRoomFloor = false;
|
||||||
bool bBlockHasTunnelCoreSweptFloor = false;
|
bool bBlockHasTunnelCoreSweptFloor = false;
|
||||||
float BlockTunnelCoreSweptFloorZ = -FLT_MAX;
|
float BlockTunnelCoreSweptFloorZ = -FLT_MAX;
|
||||||
@@ -3362,7 +3361,6 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
BlockDensity = BlockCoreSample.Density;
|
BlockDensity = BlockCoreSample.Density;
|
||||||
bBlockHasTunnelCore = BlockCoreSample.bHasTunnelCoreWorldEvaluation;
|
bBlockHasTunnelCore = BlockCoreSample.bHasTunnelCoreWorldEvaluation;
|
||||||
BlockTunnelCoreSDF = BlockCoreSample.TunnelCoreWorldSDF;
|
BlockTunnelCoreSDF = BlockCoreSample.TunnelCoreWorldSDF;
|
||||||
bBlockTunnelCoreSupportFloor = BlockCoreSample.bTunnelCoreSupportFloor;
|
|
||||||
bBlockTunnelCoreRoomFloor = BlockCoreSample.bTunnelCoreRoomFloor;
|
bBlockTunnelCoreRoomFloor = BlockCoreSample.bTunnelCoreRoomFloor;
|
||||||
bBlockHasTunnelCoreSweptFloor =
|
bBlockHasTunnelCoreSweptFloor =
|
||||||
BlockCoreSample.bHasTunnelCoreSweptFloor;
|
BlockCoreSample.bHasTunnelCoreSweptFloor;
|
||||||
@@ -3466,7 +3464,6 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
|||||||
else if (bUsedOpBlockSample && bBlockHasTunnelCore)
|
else if (bUsedOpBlockSample && bBlockHasTunnelCore)
|
||||||
{
|
{
|
||||||
PreDisturbanceTunnelCore.SDF = BlockTunnelCoreSDF;
|
PreDisturbanceTunnelCore.SDF = BlockTunnelCoreSDF;
|
||||||
PreDisturbanceTunnelCore.bSupportFloor = bBlockTunnelCoreSupportFloor;
|
|
||||||
PreDisturbanceTunnelCore.bRoomFloor = bBlockTunnelCoreRoomFloor;
|
PreDisturbanceTunnelCore.bRoomFloor = bBlockTunnelCoreRoomFloor;
|
||||||
PreDisturbanceTunnelCore.bHasSweptFloor =
|
PreDisturbanceTunnelCore.bHasSweptFloor =
|
||||||
bBlockHasTunnelCoreSweptFloor;
|
bBlockHasTunnelCoreSweptFloor;
|
||||||
|
|||||||
@@ -1410,59 +1410,6 @@ namespace VoxelSeasonManifestPrivate
|
|||||||
return bValid;
|
return bValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SaveJson(const FString& FilePath, const TSharedPtr<FJsonObject>& Root,
|
|
||||||
FString& OutReport)
|
|
||||||
{
|
|
||||||
const FString Directory = FPaths::GetPath(FilePath);
|
|
||||||
if (!Directory.IsEmpty() && !IFileManager::Get().MakeDirectory(*Directory, true))
|
|
||||||
{
|
|
||||||
OutReport = FString::Printf(TEXT("could not create manifest directory %s"), *Directory);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
FString JsonText;
|
|
||||||
TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> Writer =
|
|
||||||
TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonText);
|
|
||||||
if (!FJsonSerializer::Serialize(Root.ToSharedRef(), Writer) || !Writer->Close()
|
|
||||||
|| !FFileHelper::SaveStringToFile(JsonText, *FilePath))
|
|
||||||
{
|
|
||||||
OutReport = FString::Printf(TEXT("could not write season manifest %s"), *FilePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoadJson(const FString& FilePath, TSharedPtr<FJsonObject>& OutRoot,
|
|
||||||
FString& OutReport, FString* OutJsonText = nullptr)
|
|
||||||
{
|
|
||||||
FString JsonText;
|
|
||||||
if (!FFileHelper::LoadFileToString(JsonText, *FilePath))
|
|
||||||
{
|
|
||||||
OutReport = FString::Printf(TEXT("could not read season manifest %s"), *FilePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonText);
|
|
||||||
if (!FJsonSerializer::Deserialize(Reader, OutRoot) || !OutRoot.IsValid())
|
|
||||||
{
|
|
||||||
OutReport = FString::Printf(TEXT("invalid JSON in season manifest %s"), *FilePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (OutJsonText != nullptr)
|
|
||||||
{
|
|
||||||
*OutJsonText = MoveTemp(JsonText);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const TCHAR* VF_GetVoxelSeasonSelectionReasonName(EVoxelSeasonSelectionReason Reason)
|
|
||||||
{
|
|
||||||
switch (Reason)
|
|
||||||
{
|
|
||||||
case EVoxelSeasonSelectionReason::Grounded: return TEXT("grounded");
|
|
||||||
case EVoxelSeasonSelectionReason::Outlier: return TEXT("outlier");
|
|
||||||
case EVoxelSeasonSelectionReason::Fixed: return TEXT("fixed");
|
|
||||||
}
|
|
||||||
return TEXT("unknown");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|||||||
@@ -863,12 +863,6 @@ void FVoxelStackSampler::Shutdown()
|
|||||||
StopAndWrite();
|
StopAndWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FVoxelStackSampler::IsRunning() const
|
|
||||||
{
|
|
||||||
FScopeLock LifecycleLock(&LifecycleMutex);
|
|
||||||
return Impl != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FVoxelStackSampler::RegisterCurrentThread(int32 LODLevel)
|
bool FVoxelStackSampler::RegisterCurrentThread(int32 LODLevel)
|
||||||
{
|
{
|
||||||
// Keep this as the first and only operation in the disabled fast path. In particular, do not
|
// Keep this as the first and only operation in the disabled fast path. In particular, do not
|
||||||
|
|||||||
@@ -3800,55 +3800,6 @@ bool FVoxelStrateCorpus::LoadFromAssetRegistry(
|
|||||||
return bLoaded && NumUnresolved == 0 && bPromotedLoaded;
|
return bLoaded && NumUnresolved == 0 && bPromotedLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FVoxelStrateCorpus::LoadFromSettings(const UVoxelSettings* Settings, FString& OutReport)
|
|
||||||
{
|
|
||||||
// Compatibility/audit entry point. It intentionally does not load any soft reference: the
|
|
||||||
// Asset Registry is the corpus source, while the settings pool is reported as the reason the
|
|
||||||
// first Tier 4a run saw only one vector.
|
|
||||||
TArray<FString> SettingsPaths;
|
|
||||||
if (Settings != nullptr)
|
|
||||||
{
|
|
||||||
TSet<FString> UniquePaths;
|
|
||||||
for (const TPair<int32, TSoftObjectPtr<UVoxelStrateDefinition>>& Pair : Settings->FixedStrates)
|
|
||||||
{
|
|
||||||
const FString Path = Pair.Value.ToSoftObjectPath().ToString();
|
|
||||||
if (!Path.IsEmpty())
|
|
||||||
{
|
|
||||||
UniquePaths.Add(Path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const TSoftObjectPtr<UVoxelStrateDefinition>& Reference : Settings->StratePool)
|
|
||||||
{
|
|
||||||
const FString Path = Reference.ToSoftObjectPath().ToString();
|
|
||||||
if (!Path.IsEmpty())
|
|
||||||
{
|
|
||||||
UniquePaths.Add(Path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const FString& Path : UniquePaths)
|
|
||||||
{
|
|
||||||
SettingsPaths.Add(Path);
|
|
||||||
}
|
|
||||||
SettingsPaths.Sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
FString RegistryReport;
|
|
||||||
const bool bLoaded = LoadFromAssetRegistry(RegistryReport);
|
|
||||||
OutReport = FString::Printf(
|
|
||||||
TEXT("Settings audit: %d unique fixed/pool soft paths"), SettingsPaths.Num());
|
|
||||||
for (const FString& Path : SettingsPaths)
|
|
||||||
{
|
|
||||||
OutReport += FString::Printf(TEXT(" [%s]"), *Path);
|
|
||||||
}
|
|
||||||
if (Settings == nullptr)
|
|
||||||
{
|
|
||||||
OutReport += TEXT(" [settings object was null]");
|
|
||||||
}
|
|
||||||
OutReport += TEXT("; settings references are diagnostic only. ");
|
|
||||||
OutReport += RegistryReport;
|
|
||||||
return bLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 FVoxelStrateCorpus::NumForArchetype(ECaveGeneratorType Archetype) const
|
int32 FVoxelStrateCorpus::NumForArchetype(ECaveGeneratorType Archetype) const
|
||||||
{
|
{
|
||||||
int32 Count = 0;
|
int32 Count = 0;
|
||||||
@@ -5301,12 +5252,6 @@ bool VF_ValidateStrateCorpusFreeConstraints(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FStrateGenerationParams VF_RollStrateParams(const FVoxelStrateCorpus& Corpus,
|
|
||||||
int32 Seed, int32 Index)
|
|
||||||
{
|
|
||||||
return VF_RollStrateParamsDetailed(Corpus, Seed, Index).Params;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const TCHAR* VF_RecipeOpCode(EVoxelStrateOpClass OpClass)
|
const TCHAR* VF_RecipeOpCode(EVoxelStrateOpClass OpClass)
|
||||||
@@ -5532,15 +5477,6 @@ FVoxelStrateRegionManifest VF_RollStrateRegionManifest(
|
|||||||
ECaveGeneratorType::VerticalShafts,
|
ECaveGeneratorType::VerticalShafts,
|
||||||
ECaveGeneratorType::FloatingIslands,
|
ECaveGeneratorType::FloatingIslands,
|
||||||
};
|
};
|
||||||
static const EVoxelStrateParamBlock BlockIds[] =
|
|
||||||
{
|
|
||||||
EVoxelStrateParamBlock::TunnelNetwork,
|
|
||||||
EVoxelStrateParamBlock::Slab,
|
|
||||||
EVoxelStrateParamBlock::Maze,
|
|
||||||
EVoxelStrateParamBlock::Surface,
|
|
||||||
EVoxelStrateParamBlock::VerticalShaft,
|
|
||||||
EVoxelStrateParamBlock::FloatingIsland,
|
|
||||||
};
|
|
||||||
static const uint32 BlockSalts[] = { 0x1001u, 0x1003u, 0x1005u,
|
static const uint32 BlockSalts[] = { 0x1001u, 0x1003u, 0x1005u,
|
||||||
0x1007u, 0x1009u, 0x100Bu };
|
0x1007u, 0x1009u, 0x100Bu };
|
||||||
|
|
||||||
|
|||||||
@@ -3023,20 +3023,6 @@ void UVoxelStrateManager::ApplyPassageLandingAir(
|
|||||||
VF_ApplyPassageLandingCarving(Density, MinLandingSDF, BaseDensity, SealThickness);
|
VF_ApplyPassageLandingCarving(Density, MinLandingSDF, BaseDensity, SealThickness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UVoxelStrateManager::ApplyPassageLandingAirMC(
|
|
||||||
float& Density, float WorldX, float WorldY, float WorldZ,
|
|
||||||
float BaseDensity, float SealThickness) const
|
|
||||||
{
|
|
||||||
// ApplyDisturbances is deliberately an MC-space post-process and can add a bridge or ridge
|
|
||||||
// on top of the structural passage. Reassert only landing air here; the support slab is
|
|
||||||
// restored by ApplyPassageLandingFloorMC immediately afterwards. This stays on the same
|
|
||||||
// thread-local passage shortlist as the hot voxel path and performs no source/topology work.
|
|
||||||
float InternalDensity = -Density;
|
|
||||||
ApplyPassageLandingAir(
|
|
||||||
InternalDensity, WorldX, WorldY, WorldZ, BaseDensity, SealThickness);
|
|
||||||
Density = -InternalDensity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UVoxelStrateManager::ApplyPassageTunnelAir(
|
void UVoxelStrateManager::ApplyPassageTunnelAir(
|
||||||
float& Density, float WorldX, float WorldY, float WorldZ,
|
float& Density, float WorldX, float WorldY, float WorldZ,
|
||||||
float BaseDensity, float SealThickness) const
|
float BaseDensity, float SealThickness) const
|
||||||
@@ -3070,18 +3056,6 @@ void UVoxelStrateManager::ApplyPassageTunnelAir(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UVoxelStrateManager::ApplyPassageTunnelAirMC(
|
|
||||||
float& Density, float WorldX, float WorldY, float WorldZ,
|
|
||||||
float BaseDensity, float SealThickness) const
|
|
||||||
{
|
|
||||||
// The disturbance layer uses MC polarity (negative = solid), so reuse the exact internal
|
|
||||||
// tunnel-air operation rather than maintaining a second polarity-specific formula.
|
|
||||||
float InternalDensity = -Density;
|
|
||||||
ApplyPassageTunnelAir(
|
|
||||||
InternalDensity, WorldX, WorldY, WorldZ, BaseDensity, SealThickness);
|
|
||||||
Density = -InternalDensity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UVoxelStrateManager::ApplyPassageLandingFloorMC(
|
void UVoxelStrateManager::ApplyPassageLandingFloorMC(
|
||||||
float& Density, float WorldX, float WorldY, float WorldZ, float BaseDensity) const
|
float& Density, float WorldX, float WorldY, float WorldZ, float BaseDensity) const
|
||||||
{
|
{
|
||||||
@@ -6712,7 +6686,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
|||||||
// Three transition styles:
|
// Three transition styles:
|
||||||
//
|
//
|
||||||
// GRADIENT (default):
|
// GRADIENT (default):
|
||||||
// Classic linear lerp of all params across BlendChunks. Smooth,
|
// Classic linear lerp of all params across TransitionBlendChunks. Smooth,
|
||||||
// invisible boundary. Cave shape morphs gradually from one strate
|
// invisible boundary. Cave shape morphs gradually from one strate
|
||||||
// to the next over several chunks.
|
// to the next over several chunks.
|
||||||
//
|
//
|
||||||
@@ -6720,7 +6694,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
|||||||
// No blending at all — params switch instantly at the boundary.
|
// No blending at all — params switch instantly at the boundary.
|
||||||
// The abrupt change in density, room size, roughness, etc. creates
|
// The abrupt change in density, room size, roughness, etc. creates
|
||||||
// a natural cliff, ledge, or visible material discontinuity.
|
// a natural cliff, ledge, or visible material discontinuity.
|
||||||
// BlendChunks is ignored (effectively 0).
|
// TransitionBlendChunks is ignored (effectively 0).
|
||||||
//
|
//
|
||||||
// INTERLEAVED:
|
// INTERLEAVED:
|
||||||
// 3D Perlin noise warps the effective boundary Z position per XY column.
|
// 3D Perlin noise warps the effective boundary Z position per XY column.
|
||||||
@@ -6740,7 +6714,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
|||||||
// CHECK BOTTOM BOUNDARY (transitioning to strate below)
|
// CHECK BOTTOM BOUNDARY (transitioning to strate below)
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// DistFromBottom = how many chunks above the bottom edge of this strate.
|
// DistFromBottom = how many chunks above the bottom edge of this strate.
|
||||||
// When 0, we're right at the boundary. When == BlendChunks, we're at
|
// When 0, we're right at the boundary. When == TransitionBlendChunks, we're at
|
||||||
// the outer edge of the transition zone.
|
// the outer edge of the transition zone.
|
||||||
int32 DistFromBottom = ChunkCoord.Z - Slot.BottomChunkZ;
|
int32 DistFromBottom = ChunkCoord.Z - Slot.BottomChunkZ;
|
||||||
|
|
||||||
@@ -6749,7 +6723,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
|||||||
// The upper strate (this one) controls the transition type at its lower edge
|
// The upper strate (this one) controls the transition type at its lower edge
|
||||||
const EVoxelStrateTransition TransType = Slot.Definition->TransitionType;
|
const EVoxelStrateTransition TransType = Slot.Definition->TransitionType;
|
||||||
|
|
||||||
// Per-definition blend distance (overrides the manager's default BlendChunks)
|
// Per-definition blend distance.
|
||||||
const int32 EffectiveBlend = Slot.Definition->TransitionBlendChunks;
|
const int32 EffectiveBlend = Slot.Definition->TransitionBlendChunks;
|
||||||
|
|
||||||
// Prepare the neighbor's params (only used for Gradient and Interleaved)
|
// Prepare the neighbor's params (only used for Gradient and Interleaved)
|
||||||
@@ -6952,93 +6926,3 @@ FStrateGenerationParams UVoxelStrateManager::BuildParamsFromDefinition(const UVo
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 UVoxelStrateManager::GetGenerationParamsFingerprint() const
|
|
||||||
{
|
|
||||||
// The diagnostic command-line override changes density inputs without changing an asset. Do
|
|
||||||
// not let a verdict from the unoverridden layout survive into an overridden session (or vice
|
|
||||||
// versa); a zero fingerprint conservatively disables persistence for that session.
|
|
||||||
const FRuntimeRoughnessOverrides& RoughnessOverrides = VF_GetRuntimeRoughnessOverrides();
|
|
||||||
if (RoughnessOverrides.bSurfaceRoughness
|
|
||||||
|| RoughnessOverrides.bFrequency
|
|
||||||
|| RoughnessOverrides.bNoiseType)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The session cache is deliberately conservative. These inputs are valid density inputs but
|
|
||||||
// are not represented by the fixed-size hash below, so returning zero disables verdict reuse
|
|
||||||
// instead of pretending that a partial key is complete.
|
|
||||||
if (IsUsingSeason())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#if WITH_EDITOR
|
|
||||||
if (ComposerOverrides.Num() > 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32 A = 0x9E3779B9u;
|
|
||||||
uint32 B = 0x85EBCA6Bu;
|
|
||||||
auto HashBytes = [&A, &B](const void* Data, int32 Size)
|
|
||||||
{
|
|
||||||
A = FCrc::MemCrc32(Data, Size, A);
|
|
||||||
B = FCrc::MemCrc32(Data, Size, B ^ 0xA511E9B3u);
|
|
||||||
};
|
|
||||||
auto HashValue = [&HashBytes](const auto& Value)
|
|
||||||
{
|
|
||||||
HashBytes(&Value, sizeof(Value));
|
|
||||||
};
|
|
||||||
|
|
||||||
HashValue(CachedSeed);
|
|
||||||
HashValue(bOpenSurfaceEntry);
|
|
||||||
HashValue(OriginSpineRadius);
|
|
||||||
HashValue(InterStrateGapChunks);
|
|
||||||
const int32 LayoutCount = StrateLayout.Num();
|
|
||||||
HashValue(LayoutCount);
|
|
||||||
|
|
||||||
for (const FStrateSlot& Slot : StrateLayout)
|
|
||||||
{
|
|
||||||
if (Slot.Definition == nullptr)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildChunkCache resolves these arrays into the room cache. Hashing UObject pointers or
|
|
||||||
// asset names would not prove the asset contents, so dynamic operation/biome layouts
|
|
||||||
// conservatively opt out. The normal synthetic/runtime profile has neither array.
|
|
||||||
if (Slot.Definition->TerrainOperations.Num() > 0
|
|
||||||
|| Slot.Definition->Biomes.Num() > 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashValue(Slot.StrateIndex);
|
|
||||||
HashValue(Slot.TopChunkZ);
|
|
||||||
HashValue(Slot.BottomChunkZ);
|
|
||||||
HashValue(Slot.HeightInChunks);
|
|
||||||
HashValue(Slot.Definition->GeneratorType);
|
|
||||||
HashValue(Slot.Definition->bUseOperatorStack);
|
|
||||||
HashValue(Slot.Definition->bEnableWorms);
|
|
||||||
HashValue(VF_WormsForceOff());
|
|
||||||
// Development-only stage ablations change the field and therefore belong in every
|
|
||||||
// persistent/verdict key even though they are not authored generation parameters.
|
|
||||||
HashValue(VoxelDensityAblation::GetResolvedMask());
|
|
||||||
HashValue(Slot.Definition->StrateHeightInChunks);
|
|
||||||
HashValue(Slot.Definition->TransitionType);
|
|
||||||
HashValue(Slot.Definition->TransitionBlendChunks);
|
|
||||||
HashValue(Slot.Definition->GenerationParams);
|
|
||||||
HashValue(Slot.Definition->SlabParams);
|
|
||||||
HashValue(Slot.Definition->MazeParams);
|
|
||||||
HashValue(Slot.Definition->SurfaceParams);
|
|
||||||
HashValue(Slot.Definition->VerticalShaftParams);
|
|
||||||
HashValue(Slot.Definition->FloatingIslandParams);
|
|
||||||
HashValue(Slot.Definition->PassageConfig);
|
|
||||||
HashValue(Slot.Definition->bHasWater);
|
|
||||||
HashValue(Slot.Definition->BiomeMapParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64 Result = (static_cast<uint64>(B) << 32) | static_cast<uint64>(A);
|
|
||||||
return Result != 0 ? Result : 1;
|
|
||||||
}
|
|
||||||
@@ -2973,24 +2973,6 @@ namespace VoxelStrateMeasurePrivate
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 GetSixNeighbour(const FSampleGrid& Grid, int32 Cell, int32 Direction)
|
|
||||||
{
|
|
||||||
int32 X = 0;
|
|
||||||
int32 Y = 0;
|
|
||||||
int32 Z = 0;
|
|
||||||
DecodeIndex(Grid, Cell, X, Y, Z);
|
|
||||||
switch (Direction)
|
|
||||||
{
|
|
||||||
case 0: return X + 1 < Grid.NumX ? Grid.Index(X + 1, Y, Z) : INDEX_NONE;
|
|
||||||
case 1: return X > 0 ? Grid.Index(X - 1, Y, Z) : INDEX_NONE;
|
|
||||||
case 2: return Y + 1 < Grid.NumY ? Grid.Index(X, Y + 1, Z) : INDEX_NONE;
|
|
||||||
case 3: return Y > 0 ? Grid.Index(X, Y - 1, Z) : INDEX_NONE;
|
|
||||||
case 4: return Z + 1 < Grid.NumZ ? Grid.Index(X, Y, Z + 1) : INDEX_NONE;
|
|
||||||
case 5: return Z > 0 ? Grid.Index(X, Y, Z - 1) : INDEX_NONE;
|
|
||||||
default: return INDEX_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 CountPlayerFitNeighbours(
|
int32 CountPlayerFitNeighbours(
|
||||||
const FSampleGrid& Grid,
|
const FSampleGrid& Grid,
|
||||||
const TArray<uint8>& PlayerFitMask,
|
const TArray<uint8>& PlayerFitMask,
|
||||||
@@ -3458,26 +3440,6 @@ FVoxelConnectivityDiagnostics VF_DiagnoseConnectivityWithSampler(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
EVoxelConnectivityResult VF_ArePlayerFitConnectedWithSampler(
|
|
||||||
const IVoxelStrateDensitySampler& Sampler,
|
|
||||||
int32 StrateBottomWorldZ,
|
|
||||||
int32 StrateTopWorldZ,
|
|
||||||
float BoundarySealThickness,
|
|
||||||
const FVector& AVoxel,
|
|
||||||
const FVector& BVoxel,
|
|
||||||
const FVoxelStrateMeasureSettings& Settings,
|
|
||||||
bool& bOutStartSnapped,
|
|
||||||
bool& bOutGoalSnapped,
|
|
||||||
FVoxelConnectivityDiagnostics* OutDiagnostics)
|
|
||||||
{
|
|
||||||
int32 NumRouteRetries = 0;
|
|
||||||
return VoxelStrateMeasurePrivate::QueryConnectivity(
|
|
||||||
nullptr, nullptr, &Sampler, INDEX_NONE,
|
|
||||||
StrateBottomWorldZ, StrateTopWorldZ, BoundarySealThickness, true,
|
|
||||||
AVoxel, BVoxel, Settings, bOutStartSnapped, bOutGoalSnapped,
|
|
||||||
NumRouteRetries, OutDiagnostics, true, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
FVoxelConnectivityDiagnostics VF_DiagnosePlayerFitConnectivityWithSampler(
|
FVoxelConnectivityDiagnostics VF_DiagnosePlayerFitConnectivityWithSampler(
|
||||||
const IVoxelStrateDensitySampler& Sampler,
|
const IVoxelStrateDensitySampler& Sampler,
|
||||||
int32 StrateBottomWorldZ,
|
int32 StrateBottomWorldZ,
|
||||||
|
|||||||
@@ -76,16 +76,6 @@ namespace
|
|||||||
|
|
||||||
namespace VoxelWormField
|
namespace VoxelWormField
|
||||||
{
|
{
|
||||||
float EvaluateExact(
|
|
||||||
float WorldX,
|
|
||||||
float WorldY,
|
|
||||||
float WorldZ,
|
|
||||||
float Threshold,
|
|
||||||
const FParameters& Parameters)
|
|
||||||
{
|
|
||||||
return EvaluateExactField(WorldX, WorldY, WorldZ, Threshold, Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Evaluate(
|
float Evaluate(
|
||||||
float WorldX,
|
float WorldX,
|
||||||
float WorldY,
|
float WorldY,
|
||||||
|
|||||||
@@ -637,9 +637,8 @@ struct FCachedRoomFloorJoin
|
|||||||
|
|
||||||
// One immutable floor segment authored while the tunnel chain is built. The floor is continuous
|
// One immutable floor segment authored while the tunnel chain is built. The floor is continuous
|
||||||
// unless bLedgeTransition is set; that marker means the segment terminates at a deliberate
|
// unless bLedgeTransition is set; that marker means the segment terminates at a deliberate
|
||||||
// dramatic ledge and the vertical riser is placed at the next control-point boundary. NumSteps is
|
// dramatic ledge and the vertical riser is placed at the next control-point boundary. A steep
|
||||||
// retained as a compatibility/diagnostic field and is always zero for newly authored tunnels: a
|
// floor is never quantised into a staircase. ReliefScale is baked with a derivative bound,
|
||||||
// steep floor is never quantised into a staircase. ReliefScale is baked with a derivative bound,
|
|
||||||
// so evaluation only reads this profile and never decides a floor shape per voxel.
|
// so evaluation only reads this profile and never decides a floor shape per voxel.
|
||||||
struct FTunnelFloorSegmentProfile
|
struct FTunnelFloorSegmentProfile
|
||||||
{
|
{
|
||||||
@@ -652,9 +651,6 @@ struct FTunnelFloorSegmentProfile
|
|||||||
float NaturalEndFloorZ = 0.0f;
|
float NaturalEndFloorZ = 0.0f;
|
||||||
float ReliefScale = 0.0f;
|
float ReliefScale = 0.0f;
|
||||||
bool bLedgeTransition = false;
|
bool bLedgeTransition = false;
|
||||||
// Deprecated staircase count. New profiles leave this at zero; keep the member so old
|
|
||||||
// diagnostic consumers can still compile while the authored representation has one meaning.
|
|
||||||
int32 NumSteps = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A pre-computed wandering tunnel chain — all connection decisions and hash-derived properties
|
// A pre-computed wandering tunnel chain — all connection decisions and hash-derived properties
|
||||||
@@ -938,8 +934,6 @@ struct FChunkSDFCache
|
|||||||
struct FTunnelCoreWorldEvaluation
|
struct FTunnelCoreWorldEvaluation
|
||||||
{
|
{
|
||||||
float SDF = FLT_MAX;
|
float SDF = FLT_MAX;
|
||||||
// Deprecated compatibility output. The separate graph-tunnel support slab was removed.
|
|
||||||
bool bSupportFloor = false;
|
|
||||||
// Room geometry owns the lower side while the world-space tunnel is inside a room. The
|
// Room geometry owns the lower side while the world-space tunnel is inside a room. The
|
||||||
// tunnel SDF may still reopen air there, but its swept bottom must not turn that room air back
|
// tunnel SDF may still reopen air there, but its swept bottom must not turn that room air back
|
||||||
// into a shelf or wall.
|
// into a shelf or wall.
|
||||||
@@ -1065,15 +1059,6 @@ namespace VoxelCaveMorphology
|
|||||||
bool* OutRoomOwnsBottom = nullptr
|
bool* OutRoomOwnsBottom = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
// Evaluate the raw union of cached graph-tunnel capsules. This is intentionally separate from
|
|
||||||
// the SmoothMin morphology: the generator uses it after terrain/passage posts to reassert the
|
|
||||||
// tunnel's walkable air core without reintroducing a connector or changing room ownership.
|
|
||||||
VOXELFORGE_API float EvaluateTunnelCoreSDF(
|
|
||||||
float WorldX, float WorldY, float WorldZ,
|
|
||||||
const FChunkSDFCache& Cache,
|
|
||||||
bool bUseSpatialIndex = true
|
|
||||||
);
|
|
||||||
|
|
||||||
// Evaluate the final structural air contract against the world-space wandering chain. Room
|
// Evaluate the final structural air contract against the world-space wandering chain. Room
|
||||||
// SDFs remain evaluated in warped coordinates; only this post uses world coordinates so its
|
// SDFs remain evaluated in warped coordinates; only this post uses world coordinates so its
|
||||||
// walkable floor follows the authored chain exactly.
|
// walkable floor follows the authored chain exactly.
|
||||||
@@ -1106,46 +1091,6 @@ namespace VoxelCaveMorphology
|
|||||||
float ReachScale = 1.0f
|
float ReachScale = 1.0f
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deprecated compatibility query for the removed graph-tunnel support slab. Production
|
|
||||||
// generation does not call this predicate; the tunnel's own swept shape owns its floor.
|
|
||||||
VOXELFORGE_API bool IsTunnelSupportFloorWorldPoint(
|
|
||||||
float WorldX, float WorldY, float WorldZ,
|
|
||||||
const FChunkSDFCache& Cache,
|
|
||||||
bool bUseSpatialIndex = true
|
|
||||||
);
|
|
||||||
|
|
||||||
// Deprecated compatibility helper for callers that still inspect the old support-band
|
|
||||||
// diagnostic. It is detached from production density generation.
|
|
||||||
VOXELFORGE_API void BuildTunnelSupportFloorColumn(
|
|
||||||
float WorldX, float WorldY,
|
|
||||||
const FChunkSDFCache& Cache,
|
|
||||||
FTunnelSupportFloorColumn& OutColumn,
|
|
||||||
bool bUseSpatialIndex = true
|
|
||||||
);
|
|
||||||
|
|
||||||
VOXELFORGE_API bool IsTunnelSupportFloorColumnZ(
|
|
||||||
float WorldZ,
|
|
||||||
const FTunnelSupportFloorColumn& Column
|
|
||||||
);
|
|
||||||
|
|
||||||
// Returns the legacy projected band for one tunnel at this XY column. The world evaluator no
|
|
||||||
// longer uses it to write a support slab.
|
|
||||||
VOXELFORGE_API bool GetTunnelSupportFloorColumnBand(
|
|
||||||
int32 TunnelIndex,
|
|
||||||
const FTunnelSupportFloorColumn& Column,
|
|
||||||
float& OutFloorZ,
|
|
||||||
float& OutMinZ,
|
|
||||||
float& OutMaxZ
|
|
||||||
);
|
|
||||||
|
|
||||||
// CONVENIENCE WRAPPER: builds a temporary cache and evaluates in one call.
|
|
||||||
// Use this for one-off queries (debug visualization, single-point sampling).
|
|
||||||
// For chunk generation, use BuildChunkCache + EvaluateSDFCached instead.
|
|
||||||
float EvaluateSDF(
|
|
||||||
float WorldX, float WorldY, float WorldZ,
|
|
||||||
const FStrateGenerationParams& Params,
|
|
||||||
uint32 Seed, int32 StrateIndex
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -337,11 +337,6 @@ struct FVoxelOpSample
|
|||||||
// FLT_MAX = "no surface nearby" — the initial state, and the early-out placed sources use.
|
// FLT_MAX = "no surface nearby" — the initial state, and the early-out placed sources use.
|
||||||
float Sdf = FLT_MAX;
|
float Sdf = FLT_MAX;
|
||||||
|
|
||||||
// Deprecated structural-floor compatibility fields. Graph tunnels now carry their floor in
|
|
||||||
// the swept shape itself; the production stack does not use these fields to write a slab.
|
|
||||||
bool bProtectedStructuralFloor = false;
|
|
||||||
float StructuralFloorMinimumDensity = 0.0f;
|
|
||||||
|
|
||||||
// Block evaluation keeps the room source's per-sample selection explicit. The scalar path
|
// Block evaluation keeps the room source's per-sample selection explicit. The scalar path
|
||||||
// still uses the source's worker-local state, but a later block-capable modifier must never
|
// still uses the source's worker-local state, but a later block-capable modifier must never
|
||||||
// observe the state belonging to the last sample of the preceding operator.
|
// observe the state belonging to the last sample of the preceding operator.
|
||||||
@@ -353,7 +348,6 @@ struct FVoxelOpSample
|
|||||||
// consulting a last-sample TLS value after an op-major evaluation.
|
// consulting a last-sample TLS value after an op-major evaluation.
|
||||||
bool bHasTunnelCoreWorldEvaluation = false;
|
bool bHasTunnelCoreWorldEvaluation = false;
|
||||||
float TunnelCoreWorldSDF = FLT_MAX;
|
float TunnelCoreWorldSDF = FLT_MAX;
|
||||||
bool bTunnelCoreSupportFloor = false;
|
|
||||||
bool bTunnelCoreRoomFloor = false;
|
bool bTunnelCoreRoomFloor = false;
|
||||||
bool bHasTunnelCoreSweptFloor = false;
|
bool bHasTunnelCoreSweptFloor = false;
|
||||||
float TunnelCoreSweptFloorZ = -FLT_MAX;
|
float TunnelCoreSweptFloorZ = -FLT_MAX;
|
||||||
|
|||||||
@@ -568,12 +568,6 @@ namespace VoxelDensityOps
|
|||||||
* `FillOnly` quand une colonne atteint la boîte, `Identity` (le cas courant) sinon. */
|
* `FillOnly` quand une colonne atteint la boîte, `Identity` (le cas courant) sinon. */
|
||||||
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeGridColumnMod(const FSlabGenerationParams& P, int32 Seed);
|
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeGridColumnMod(const FSlabGenerationParams& P, int32 Seed);
|
||||||
|
|
||||||
/** Rôle 1 — le pont entre les deux espaces : consomme les piles de HAUTEUR (sol + voûte,
|
|
||||||
* `VoxelHeightOp.h`) et en fait une densité. `IsXYPure()` est **false** — les hauteurs sont
|
|
||||||
* pures en XY, la densité est une distance à celles-ci et ne peut pas l'être. */
|
|
||||||
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeSurfaceColumnSource(const FSurfaceGenerationParams& P,
|
|
||||||
int32 Seed);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SurfaceWorld, COMPLET : colonne (sol + voûte) → densité, overhang 3D, post structurel, et le
|
* SurfaceWorld, COMPLET : colonne (sol + voûte) → densité, overhang 3D, post structurel, et le
|
||||||
* mélange de biomes quand `PerBiomeParams` est non vide.
|
* mélange de biomes quand `PerBiomeParams` est non vide.
|
||||||
|
|||||||
@@ -300,7 +300,6 @@ FORCEINLINE void VF_ApplyXYEdgeSealMC(float& Density, float WorldX, float WorldY
|
|||||||
// mathematical inner edge the helper is a true no-op, so claiming AllSolid there would be false.
|
// mathematical inner edge the helper is a true no-op, so claiming AllSolid there would be false.
|
||||||
namespace VoxelDensityReach
|
namespace VoxelDensityReach
|
||||||
{
|
{
|
||||||
constexpr float SpineBlend = 3.0f;
|
|
||||||
constexpr float PassageBlend = 4.0f;
|
constexpr float PassageBlend = 4.0f;
|
||||||
constexpr float EdgeProofMargin = 1.0f;
|
constexpr float EdgeProofMargin = 1.0f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,7 +312,6 @@ namespace VoxelDensityProfile
|
|||||||
FCacheMemoryBreakdown RoomGraphCacheBreakdown;
|
FCacheMemoryBreakdown RoomGraphCacheBreakdown;
|
||||||
};
|
};
|
||||||
|
|
||||||
VOXELFORGE_API void SetEnabled(bool bEnabled);
|
|
||||||
VOXELFORGE_API void SetMode(EMode Mode, uint32 SampleInterval = DefaultSampleInterval);
|
VOXELFORGE_API void SetMode(EMode Mode, uint32 SampleInterval = DefaultSampleInterval);
|
||||||
// Counters are collected only while a diagnostic mode is enabled. In the ordinary clean
|
// Counters are collected only while a diagnostic mode is enabled. In the ordinary clean
|
||||||
// path this is a single relaxed load, so the measurement hooks stay dormant.
|
// path this is a single relaxed load, so the measurement hooks stay dormant.
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ namespace VoxelPassageGeometry
|
|||||||
// ownership band: the floor writer owns the plane, while the air writer owns the capsule
|
// ownership band: the floor writer owns the plane, while the air writer owns the capsule
|
||||||
// volume above it even when two overlapping passage projections differ by a fraction.
|
// volume above it even when two overlapping passage projections differ by a fraction.
|
||||||
constexpr float WalkableTunnelFloorAirClearanceVoxels = 0.5f;
|
constexpr float WalkableTunnelFloorAirClearanceVoxels = 0.5f;
|
||||||
// The graph-tunnel post owns the interior above its floor after terrain and passage-floor
|
|
||||||
// writers have run. The support-floor predicate is also an exclusion mask for the air post,
|
|
||||||
// so overlapping graph tubes cannot erase one another's walkable support band.
|
|
||||||
constexpr float CaveTunnelAirCoreInsetVoxels = 0.5f;
|
|
||||||
|
|
||||||
// A 15 degree ramp is comfortably below the 44 degree engine walkability ceiling. The
|
// A 15 degree ramp is comfortably below the 44 degree engine walkability ceiling. The
|
||||||
// latter is a scramble limit, not a sensible default for a tunnel the player walks through.
|
// latter is a scramble limit, not a sensible default for a tunnel the player walks through.
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ public:
|
|||||||
int32 GetSeasonSeed() const { return SeasonSeed; }
|
int32 GetSeasonSeed() const { return SeasonSeed; }
|
||||||
float GetOriginSpineRadius() const { return OriginSpineRadius; }
|
float GetOriginSpineRadius() const { return OriginSpineRadius; }
|
||||||
float GetWorldRadiusVoxels() const { return WorldRadiusVoxels; }
|
float GetWorldRadiusVoxels() const { return WorldRadiusVoxels; }
|
||||||
const FString& GetManifestContentHash() const { return ManifestContentHash; }
|
|
||||||
|
|
||||||
/** Create the asset in Content Browser, choose a JSON file, then press this button. */
|
/** Create the asset in Content Browser, choose a JSON file, then press this button. */
|
||||||
UFUNCTION(CallInEditor, Category = "Season")
|
UFUNCTION(CallInEditor, Category = "Season")
|
||||||
|
|||||||
@@ -134,10 +134,6 @@ struct VOXELFORGE_API FVoxelSeasonCompositionSettings
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Friendly aliases for callers that use the task's shorter naming.
|
|
||||||
using FVoxelSeasonComposerSettings = FVoxelSeasonCompositionSettings;
|
|
||||||
using FVoxelSeasonComposeSettings = FVoxelSeasonCompositionSettings;
|
|
||||||
|
|
||||||
/** Compact audit row; the full vectors live only for selected strates. */
|
/** Compact audit row; the full vectors live only for selected strates. */
|
||||||
struct VOXELFORGE_API FVoxelSeasonCandidateAudit
|
struct VOXELFORGE_API FVoxelSeasonCandidateAudit
|
||||||
{
|
{
|
||||||
@@ -260,10 +256,6 @@ struct VOXELFORGE_API FVoxelSeasonManifest
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Human-readable enum names used by JSON and the review page. */
|
|
||||||
VOXELFORGE_API const TCHAR* VF_GetVoxelSeasonSelectionReasonName(
|
|
||||||
EVoxelSeasonSelectionReason Reason);
|
|
||||||
|
|
||||||
/** Compose, validate, select, serialize, and (by default) write one season. Editor/build-box only. */
|
/** Compose, validate, select, serialize, and (by default) write one season. Editor/build-box only. */
|
||||||
#if WITH_EDITOR
|
#if WITH_EDITOR
|
||||||
VOXELFORGE_API FVoxelSeasonManifest VF_ComposeSeason(
|
VOXELFORGE_API FVoxelSeasonManifest VF_ComposeSeason(
|
||||||
|
|||||||
@@ -48,15 +48,6 @@ public:
|
|||||||
uint64 RetainedSamples = 0;
|
uint64 RetainedSamples = 0;
|
||||||
uint64 DroppedSamples = 0;
|
uint64 DroppedSamples = 0;
|
||||||
uint64 TotalFrames = 0;
|
uint64 TotalFrames = 0;
|
||||||
// Kept for source compatibility with the earlier in-process summary. Raw sessions leave
|
|
||||||
// these zero; the offline summary owns all resolved-frame counts and tables.
|
|
||||||
uint64 ResolvedFrames = 0;
|
|
||||||
uint64 UnknownFrames = 0;
|
|
||||||
uint64 WaitLikeFrames = 0;
|
|
||||||
uint64 SamplesWithResolvedLeaf = 0;
|
|
||||||
uint64 SamplesWithWaitLikeFrame = 0;
|
|
||||||
uint64 UniqueProgramCounters = 0;
|
|
||||||
uint64 InlineSymbols = 0;
|
|
||||||
uint64 MaxActiveRegisteredThreads = 0;
|
uint64 MaxActiveRegisteredThreads = 0;
|
||||||
uint64 ModuleCount = 0;
|
uint64 ModuleCount = 0;
|
||||||
double RunSeconds = 0.0;
|
double RunSeconds = 0.0;
|
||||||
@@ -78,8 +69,6 @@ public:
|
|||||||
/** Used by the module shutdown path as a final lifecycle backstop. */
|
/** Used by the module shutdown path as a final lifecycle backstop. */
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
bool IsRunning() const;
|
|
||||||
|
|
||||||
/** Called only by FScopedVoxelStackRegistration; cheap when disabled. */
|
/** Called only by FScopedVoxelStackRegistration; cheap when disabled. */
|
||||||
static bool RegisterCurrentThread(int32 LODLevel = INDEX_NONE);
|
static bool RegisterCurrentThread(int32 LODLevel = INDEX_NONE);
|
||||||
static void DeregisterCurrentThread();
|
static void DeregisterCurrentThread();
|
||||||
|
|||||||
@@ -594,11 +594,6 @@ public:
|
|||||||
const FString& PromotedStorePath = FString(),
|
const FString& PromotedStorePath = FString(),
|
||||||
const IVoxelStratePromotionVerifier* PromotionVerifier = nullptr);
|
const IVoxelStratePromotionVerifier* PromotionVerifier = nullptr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Compatibility alias retained for callers compiled against the first Tier 4a pass. The
|
|
||||||
* settings argument is audited only for diagnostics; it is not a corpus input.
|
|
||||||
*/
|
|
||||||
bool LoadFromSettings(const UVoxelSettings* Settings, FString& OutReport);
|
|
||||||
bool LoadFromDefinitions(const TArray<UVoxelStrateDefinition*>& Definitions, FString& OutReport);
|
bool LoadFromDefinitions(const TArray<UVoxelStrateDefinition*>& Definitions, FString& OutReport);
|
||||||
|
|
||||||
/** Add an already-resolved vector, primarily for offline tools and focused tests. */
|
/** Add an already-resolved vector, primarily for offline tools and focused tests. */
|
||||||
@@ -625,7 +620,6 @@ public:
|
|||||||
int32 Num() const { return Entries.Num(); }
|
int32 Num() const { return Entries.Num(); }
|
||||||
const TArray<FVoxelStrateCorpusEntry>& GetEntries() const { return Entries; }
|
const TArray<FVoxelStrateCorpusEntry>& GetEntries() const { return Entries; }
|
||||||
const TArray<FVoxelStrateFieldSpread>& GetFieldSpreads() const { return FieldSpreads; }
|
const TArray<FVoxelStrateFieldSpread>& GetFieldSpreads() const { return FieldSpreads; }
|
||||||
const TArray<FString>& GetSkippedDefinitions() const { return SkippedDefinitions; }
|
|
||||||
|
|
||||||
int32 NumForArchetype(ECaveGeneratorType Archetype) const;
|
int32 NumForArchetype(ECaveGeneratorType Archetype) const;
|
||||||
int32 NumForProvenance(EVoxelStrateCorpusProvenance Provenance) const;
|
int32 NumForProvenance(EVoxelStrateCorpusProvenance Provenance) const;
|
||||||
@@ -804,10 +798,6 @@ VOXELFORGE_API uint32 VF_HashStrateStructureRecipe(const FVoxelOpStackRecipe& Re
|
|||||||
VOXELFORGE_API bool VF_AreStrateStructureRecipesIdentical(
|
VOXELFORGE_API bool VF_AreStrateStructureRecipesIdentical(
|
||||||
const FVoxelOpStackRecipe& A, const FVoxelOpStackRecipe& B);
|
const FVoxelOpStackRecipe& A, const FVoxelOpStackRecipe& B);
|
||||||
|
|
||||||
/** The compact API requested by the composer design. */
|
|
||||||
VOXELFORGE_API FStrateGenerationParams VF_RollStrateParams(
|
|
||||||
const FVoxelStrateCorpus& Corpus, int32 Seed, int32 Index);
|
|
||||||
|
|
||||||
/** Bitwise comparison over exactly the fields in FStrateGenerationParams::Lerp. */
|
/** Bitwise comparison over exactly the fields in FStrateGenerationParams::Lerp. */
|
||||||
VOXELFORGE_API bool VF_AreStrateParamsBitIdentical(
|
VOXELFORGE_API bool VF_AreStrateParamsBitIdentical(
|
||||||
const FStrateGenerationParams& A, const FStrateGenerationParams& B);
|
const FStrateGenerationParams& A, const FStrateGenerationParams& B);
|
||||||
|
|||||||
@@ -249,15 +249,6 @@ public:
|
|||||||
* live edit) can never serve a stale strate index or passage shortlist. */
|
* live edit) can never serve a stale strate index or passage shortlist. */
|
||||||
uint32 GetLayoutVersion() const { return PassagesVersion; }
|
uint32 GetLayoutVersion() const { return PassagesVersion; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Fingerprint of the immutable density inputs used by the generator.
|
|
||||||
*
|
|
||||||
* Returns zero when the manager has dynamic inputs that this compact cache key intentionally
|
|
||||||
* does not serialize (seasons, composer recipes, biome maps, or terrain-op assets). Zero is a
|
|
||||||
* fail-closed answer: callers must skip verdict reuse rather than risk an old all-air proof.
|
|
||||||
*/
|
|
||||||
uint64 GetGenerationParamsFingerprint() const;
|
|
||||||
|
|
||||||
/** Diagnostic-only switch for isolating the inter-strate support writer. */
|
/** Diagnostic-only switch for isolating the inter-strate support writer. */
|
||||||
void SetPassageSupportFloorWritesEnabledForDiagnostics(bool bEnabled)
|
void SetPassageSupportFloorWritesEnabledForDiagnostics(bool bEnabled)
|
||||||
{
|
{
|
||||||
@@ -289,7 +280,7 @@ public:
|
|||||||
* Get generation params for a chunk, with boundary blending.
|
* Get generation params for a chunk, with boundary blending.
|
||||||
*
|
*
|
||||||
* BLENDING CONCEPT:
|
* BLENDING CONCEPT:
|
||||||
* When a chunk is near a strate boundary (within BlendChunks of the edge),
|
* When a chunk is near a strate boundary (within the definition's TransitionBlendChunks of the edge),
|
||||||
* the params are lerped between the two adjacent strates. This prevents
|
* the params are lerped between the two adjacent strates. This prevents
|
||||||
* hard visual seams where one strate ends and another begins.
|
* hard visual seams where one strate ends and another begins.
|
||||||
*
|
*
|
||||||
@@ -419,14 +410,6 @@ public:
|
|||||||
void ApplyPassageTunnelAir(float& Density, float WorldX, float WorldY, float WorldZ,
|
void ApplyPassageTunnelAir(float& Density, float WorldX, float WorldY, float WorldZ,
|
||||||
float BaseDensity, float SealThickness) const;
|
float BaseDensity, float SealThickness) const;
|
||||||
|
|
||||||
/** Re-assert landing air after MC-space disturbances, still before the final XY seal. */
|
|
||||||
void ApplyPassageLandingAirMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
|
||||||
float BaseDensity, float SealThickness) const;
|
|
||||||
|
|
||||||
/** Re-assert walkable tunnel air after MC-space disturbances, still before the final XY seal. */
|
|
||||||
void ApplyPassageTunnelAirMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
|
||||||
float BaseDensity, float SealThickness) const;
|
|
||||||
|
|
||||||
/** Apply the landing/tunnel MC post in one cached passage scan after disturbances. */
|
/** Apply the landing/tunnel MC post in one cached passage scan after disturbances. */
|
||||||
void ApplyPassageStructuralPostsMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
void ApplyPassageStructuralPostsMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
||||||
float BaseDensity, float SealThickness) const;
|
float BaseDensity, float SealThickness) const;
|
||||||
@@ -530,9 +513,6 @@ protected:
|
|||||||
// allocator address reuse must not make a stale worker-local stack look current.
|
// allocator address reuse must not make a stale worker-local stack look current.
|
||||||
uint64 CacheLifetimeId = 0;
|
uint64 CacheLifetimeId = 0;
|
||||||
|
|
||||||
// How many chunks at strate boundaries are blended (transition zone)
|
|
||||||
int32 BlendChunks = 2;
|
|
||||||
|
|
||||||
// World seed (stored for passage generation)
|
// World seed (stored for passage generation)
|
||||||
int32 CachedSeed = 0;
|
int32 CachedSeed = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -510,23 +510,6 @@ VOXELFORGE_API FVoxelConnectivityDiagnostics VF_DiagnoseConnectivityWithSampler(
|
|||||||
const FVector& BVoxel,
|
const FVector& BVoxel,
|
||||||
const FVoxelStrateMeasureSettings& Settings);
|
const FVoxelStrateMeasureSettings& Settings);
|
||||||
|
|
||||||
/**
|
|
||||||
* Player-fit connectivity over a custom stack. This is deliberately a separate API from the
|
|
||||||
* legacy air route: it refuses unless Settings.SampleStep == 1, resolves endpoints against the
|
|
||||||
* direct capsule-occupancy/floor mask, and flood-fills/routes only through player-fit cells.
|
|
||||||
*/
|
|
||||||
VOXELFORGE_API EVoxelConnectivityResult VF_ArePlayerFitConnectedWithSampler(
|
|
||||||
const IVoxelStrateDensitySampler& Sampler,
|
|
||||||
int32 StrateBottomWorldZ,
|
|
||||||
int32 StrateTopWorldZ,
|
|
||||||
float BoundarySealThickness,
|
|
||||||
const FVector& AVoxel,
|
|
||||||
const FVector& BVoxel,
|
|
||||||
const FVoxelStrateMeasureSettings& Settings,
|
|
||||||
bool& bOutStartSnapped,
|
|
||||||
bool& bOutGoalSnapped,
|
|
||||||
FVoxelConnectivityDiagnostics* OutDiagnostics = nullptr);
|
|
||||||
|
|
||||||
/** Full diagnostics variant for the player-fit custom-stack route. */
|
/** Full diagnostics variant for the player-fit custom-stack route. */
|
||||||
VOXELFORGE_API FVoxelConnectivityDiagnostics VF_DiagnosePlayerFitConnectivityWithSampler(
|
VOXELFORGE_API FVoxelConnectivityDiagnostics VF_DiagnosePlayerFitConnectivityWithSampler(
|
||||||
const IVoxelStrateDensitySampler& Sampler,
|
const IVoxelStrateDensitySampler& Sampler,
|
||||||
|
|||||||
@@ -411,14 +411,4 @@ namespace VoxelGenLOD
|
|||||||
Density = Before;
|
Density = Before;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compare a scalar proof input such as EvaluateModifierSDF without changing the field. */
|
|
||||||
FORCEINLINE void CompareSkippedPostValue(
|
|
||||||
float Candidate, float Canonical,
|
|
||||||
ETilePostComparisonKind Kind = ETilePostComparisonKind::Other)
|
|
||||||
{
|
|
||||||
if (bTilePostReachDebug && !bTilePostReachBypass)
|
|
||||||
{
|
|
||||||
RecordSkippedPostComparison(Kind, !SameFloatBits(Candidate, Canonical));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -209,9 +209,7 @@ namespace VoxelMath
|
|||||||
// règle côté RENDU (ombres off sur LOD lointain, voir ApplyMeshToChunk), pas via la
|
// règle côté RENDU (ombres off sur LOD lointain, voir ApplyMeshToChunk), pas via la
|
||||||
// taille de chunk. La taille de chunk reste le levier streaming-vs-draws si besoin.
|
// taille de chunk. La taille de chunk reste le levier streaming-vs-draws si besoin.
|
||||||
|
|
||||||
constexpr int32 CHUNK_SIZE = 32;
|
constexpr int32 CHUNK_SIZE = 32;
|
||||||
constexpr int32 CHUNK_SIZE_SQUARED = CHUNK_SIZE * CHUNK_SIZE; // 1024
|
|
||||||
constexpr int32 CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; // 32768
|
|
||||||
|
|
||||||
constexpr float VOXEL_SIZE = 25.0f;
|
constexpr float VOXEL_SIZE = 25.0f;
|
||||||
|
|
||||||
@@ -276,26 +274,6 @@ enum class EVoxelFace : uint8
|
|||||||
NegativeZ, // Down (-Z)
|
NegativeZ, // Down (-Z)
|
||||||
};
|
};
|
||||||
|
|
||||||
inline FIntVector GetFaceDirection(EVoxelFace Face)
|
|
||||||
{
|
|
||||||
switch (Face)
|
|
||||||
{
|
|
||||||
case EVoxelFace::PositiveX: return FIntVector( 1, 0, 0);
|
|
||||||
case EVoxelFace::NegativeX: return FIntVector(-1, 0, 0);
|
|
||||||
case EVoxelFace::PositiveY: return FIntVector( 0, 1, 0);
|
|
||||||
case EVoxelFace::NegativeY: return FIntVector( 0, -1, 0);
|
|
||||||
case EVoxelFace::PositiveZ: return FIntVector( 0, 0, 1);
|
|
||||||
case EVoxelFace::NegativeZ: return FIntVector( 0, 0, -1);
|
|
||||||
default: return FIntVector( 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FVector GetFaceNormal(EVoxelFace Face)
|
|
||||||
{
|
|
||||||
const FIntVector Dir = GetFaceDirection(Face);
|
|
||||||
return FVector(Dir.X, Dir.Y, Dir.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// COORDINATE CONVERSION
|
// COORDINATE CONVERSION
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -319,53 +297,6 @@ inline FIntVector WorldToChunkCoord(const FVector& WorldPos)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FIntVector WorldToLocalCoord(const FVector& WorldPos)
|
|
||||||
{
|
|
||||||
// ((x % n) + n) % n → modulo positif même pour x négatif.
|
|
||||||
// (-5 % 32) = -5 en C++, mais on veut 27.
|
|
||||||
return FIntVector(
|
|
||||||
((FMath::FloorToInt(WorldPos.X / VOXEL_SIZE) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE,
|
|
||||||
((FMath::FloorToInt(WorldPos.Y / VOXEL_SIZE) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE,
|
|
||||||
((FMath::FloorToInt(WorldPos.Z / VOXEL_SIZE) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FVector ChunkToWorldPos(const FIntVector& ChunkCoord)
|
|
||||||
{
|
|
||||||
return FVector(
|
|
||||||
ChunkCoord.X * CHUNK_SIZE * VOXEL_SIZE,
|
|
||||||
ChunkCoord.Y * CHUNK_SIZE * VOXEL_SIZE,
|
|
||||||
ChunkCoord.Z * CHUNK_SIZE * VOXEL_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index 3D → 1D pour un tableau plat (voir doc CLAUDE.md: "x + y*SizeX + z*SizeX*SizeY").
|
|
||||||
inline int32 LocalToIndex(int32 X, int32 Y, int32 Z)
|
|
||||||
{
|
|
||||||
return X + (Y * CHUNK_SIZE) + (Z * CHUNK_SIZE_SQUARED);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FIntVector IndexToLocal(int32 Index)
|
|
||||||
{
|
|
||||||
return FIntVector(
|
|
||||||
Index % CHUNK_SIZE,
|
|
||||||
(Index / CHUNK_SIZE) % CHUNK_SIZE,
|
|
||||||
Index / CHUNK_SIZE_SQUARED
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsValidLocalCoord(int32 X, int32 Y, int32 Z)
|
|
||||||
{
|
|
||||||
return X >= 0 && X < CHUNK_SIZE
|
|
||||||
&& Y >= 0 && Y < CHUNK_SIZE
|
|
||||||
&& Z >= 0 && Z < CHUNK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsValidLocalCoord(const FIntVector& Coord)
|
|
||||||
{
|
|
||||||
return IsValidLocalCoord(Coord.X, Coord.Y, Coord.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// MATH HELPERS (partagés entre générateur, morphologie, manager)
|
// MATH HELPERS (partagés entre générateur, morphologie, manager)
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|||||||
@@ -17,14 +17,6 @@ namespace VoxelWormField
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Evaluate the exact two-noise field, retaining the N1 threshold short-circuit. */
|
/** Evaluate the exact two-noise field, retaining the N1 threshold short-circuit. */
|
||||||
VOXELFORGE_API float EvaluateExact(
|
|
||||||
float WorldX,
|
|
||||||
float WorldY,
|
|
||||||
float WorldZ,
|
|
||||||
float Threshold,
|
|
||||||
const FParameters& Parameters);
|
|
||||||
|
|
||||||
/** Evaluate the exact two-noise field. */
|
|
||||||
VOXELFORGE_API float Evaluate(
|
VOXELFORGE_API float Evaluate(
|
||||||
float WorldX,
|
float WorldX,
|
||||||
float WorldY,
|
float WorldY,
|
||||||
|
|||||||
@@ -4243,76 +4243,6 @@ bool WriteObjHeader(FArchive& Archive)
|
|||||||
return bOk && !Archive.IsError();
|
return bOk && !Archive.IsError();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteObjTile(
|
|
||||||
FArchive& Archive,
|
|
||||||
const FVoxelMeshData& MeshData,
|
|
||||||
int32 VertexOffset,
|
|
||||||
FString& OutError)
|
|
||||||
{
|
|
||||||
if (!ValidateCanonicalTile(MeshData, OutError))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool bOk = true;
|
|
||||||
for (const FVector& Vertex : MeshData.Vertices)
|
|
||||||
{
|
|
||||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
|
||||||
TEXT("v %.9f %.9f %.9f\n"),
|
|
||||||
Vertex.X / 100.0,
|
|
||||||
Vertex.Y / 100.0,
|
|
||||||
Vertex.Z / 100.0));
|
|
||||||
}
|
|
||||||
for (const FVector2D& UV : MeshData.UVs)
|
|
||||||
{
|
|
||||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
|
||||||
TEXT("vt %.9f %.9f\n"), UV.X, UV.Y));
|
|
||||||
}
|
|
||||||
for (const FVector& Normal : MeshData.Normals)
|
|
||||||
{
|
|
||||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
|
||||||
TEXT("vn %.9f %.9f %.9f\n"), Normal.X, Normal.Y, Normal.Z));
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32 NumTriangles = MeshData.Triangles.Num() / 3;
|
|
||||||
const int32 FirstCeilingTriangle = FMath::Clamp(
|
|
||||||
NumTriangles - MeshData.NumCeilingTriangles, 0, NumTriangles);
|
|
||||||
if (NumTriangles > 0)
|
|
||||||
{
|
|
||||||
bOk = bOk && WriteUtf8(Archive, TEXT("usemtl VoxelGround\n"));
|
|
||||||
}
|
|
||||||
for (int32 Triangle = 0; Triangle < NumTriangles; ++Triangle)
|
|
||||||
{
|
|
||||||
if (Triangle == FirstCeilingTriangle)
|
|
||||||
{
|
|
||||||
bOk = bOk && WriteUtf8(Archive, TEXT("usemtl VoxelCeiling\n"));
|
|
||||||
}
|
|
||||||
const int32 Base = Triangle * 3;
|
|
||||||
const int32 SourceA = MeshData.Triangles[Base];
|
|
||||||
const int32 SourceB = MeshData.Triangles[Base + 1];
|
|
||||||
const int32 SourceC = MeshData.Triangles[Base + 2];
|
|
||||||
if (SourceA < 0 || SourceB < 0 || SourceC < 0
|
|
||||||
|| SourceA >= MeshData.Vertices.Num()
|
|
||||||
|| SourceB >= MeshData.Vertices.Num()
|
|
||||||
|| SourceC >= MeshData.Vertices.Num())
|
|
||||||
{
|
|
||||||
OutError = TEXT("Canonical mesher returned an out-of-range triangle index.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const int32 A = SourceA + 1 + VertexOffset;
|
|
||||||
const int32 B = SourceB + 1 + VertexOffset;
|
|
||||||
const int32 C = SourceC + 1 + VertexOffset;
|
|
||||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
|
||||||
TEXT("f %d/%d/%d %d/%d/%d %d/%d/%d\n"),
|
|
||||||
A, A, A, B, B, B, C, C, C));
|
|
||||||
}
|
|
||||||
if (!bOk || Archive.IsError())
|
|
||||||
{
|
|
||||||
OutError = TEXT("Could not write a canonical OBJ tile.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WriteObjMesh(
|
bool WriteObjMesh(
|
||||||
FArchive& Archive,
|
FArchive& Archive,
|
||||||
const FVoxelMeshData& MeshData,
|
const FVoxelMeshData& MeshData,
|
||||||
@@ -7091,29 +7021,6 @@ FString BuildExploreJson(
|
|||||||
return Writer->Close() ? Json : FString();
|
return Writer->Close() ? Json : FString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const TCHAR* ExploreEffectName(EVoxelOpEffect Effect)
|
|
||||||
{
|
|
||||||
switch (Effect)
|
|
||||||
{
|
|
||||||
case EVoxelOpEffect::Identity: return TEXT("Identity");
|
|
||||||
case EVoxelOpEffect::CarveOnly: return TEXT("CarveOnly");
|
|
||||||
case EVoxelOpEffect::FillOnly: return TEXT("FillOnly");
|
|
||||||
case EVoxelOpEffect::Both: return TEXT("Both");
|
|
||||||
default: return TEXT("Unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const TCHAR* ExploreTileClassName(EVoxelTileClass Class)
|
|
||||||
{
|
|
||||||
switch (Class)
|
|
||||||
{
|
|
||||||
case EVoxelTileClass::AllSolid: return TEXT("AllSolid");
|
|
||||||
case EVoxelTileClass::AllAir: return TEXT("AllAir");
|
|
||||||
case EVoxelTileClass::Mixed: return TEXT("Mixed");
|
|
||||||
default: return TEXT("Unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Density-bound APIs use FLT_MAX as the documented "unknown/unbounded" sentinel. It is finite
|
// Density-bound APIs use FLT_MAX as the documented "unknown/unbounded" sentinel. It is finite
|
||||||
// according to IEEE-754, so FMath::IsFinite alone would misreport the very failure this audit is
|
// according to IEEE-754, so FMath::IsFinite alone would misreport the very failure this audit is
|
||||||
// intended to expose as a real numeric envelope.
|
// intended to expose as a real numeric envelope.
|
||||||
|
|||||||
Reference in new issue
Block a user