standalone: cheap far-survival repairs -- whole view 1.80 -> 1.40 s, payload 277 -> 111 MiB

- Far repairs are source-aware (only where the sampled mesh lost a shell) and redundant radius probes
  trimmed; ~175k two-triangle repair panels remain (+18 MiB over the no-shell 92.6 MiB).
- Pipelined start builds the shape world once; the 27-tile neighbourhood is ready ~0.73 s from
  process start; pipelined whole view is no slower than direct.
- Far audit passes, bad-shell control still fails (16 missing / 16 holes); look audits pass; routes
  5642/5642; 60 W1/W8 + direct/pipeline hash fields equal; six fixed captures pixel-identical.
Verified by me head to head (8 workers, cold, BelowNormal 0xFF00, quiet machine, two runs each):
1.40 s vs 1.80 s for the previous default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-05 01:56:41 +02:00
1 parent a40b0454b3
commit d4fa89204d
4 files changed
+837 -303

No files matched your search

+42 -38
View File
@@ -403,47 +403,23 @@ public:
const std::vector<FFarConnectorSegment>& GetFarConnectorSegments() const
{ return FarConnectorSegments; }
size_t BuildFarConnectorAirSamples(const FIntVector& TileOrigin,int32 Step,int32 Cells,
std::unordered_set<uint64>& OutSamples) const
void FindFarConnectorCandidates(const FIntVector& QueryMin,const FIntVector& QueryMax,
std::vector<uint32>& OutIndices) const
{
OutSamples.clear();
if(FarConnectorSegments.empty()||Step<=0||Cells<=0)return 0;
const double Pad=Step;
const double TileMin[3]={TileOrigin.X-Pad,TileOrigin.Y-Pad,TileOrigin.Z-Pad};
const double TileMax[3]={TileOrigin.X+(Cells+1)*Step,TileOrigin.Y+(Cells+1)*Step,
TileOrigin.Z+(Cells+1)*Step};
for(const FFarConnectorSegment& Connector:FarConnectorSegments)
constexpr int32 BinSize=2048;
OutIndices.clear();
const int32 MinX=FloorDiv(QueryMin.X,BinSize),MaxX=FloorDiv(QueryMax.X,BinSize);
const int32 MinY=FloorDiv(QueryMin.Y,BinSize),MaxY=FloorDiv(QueryMax.Y,BinSize);
const int32 MinZ=FloorDiv(QueryMin.Z,BinSize),MaxZ=FloorDiv(QueryMax.Z,BinSize);
for(int32 Z=MinZ;Z<=MaxZ;++Z)for(int32 Y=MinY;Y<=MaxY;++Y)
for(int32 X=MinX;X<=MaxX;++X)
{
const double Start[3]={Connector.Start.X,Connector.Start.Y,Connector.Start.Z};
const double End[3]={Connector.End.X,Connector.End.Y,Connector.End.Z};
bool bOverlaps=true;
for(int32 Axis=0;Axis<3;++Axis)
bOverlaps &= std::min(Start[Axis],End[Axis])-Connector.Radius<=TileMax[Axis]
&&std::max(Start[Axis],End[Axis])+Connector.Radius>=TileMin[Axis];
if(!bOverlaps)continue;
const double Delta[3]={End[0]-Start[0],End[1]-Start[1],End[2]-Start[2]};
const double Length=std::sqrt(Delta[0]*Delta[0]+Delta[1]*Delta[1]+Delta[2]*Delta[2]);
if(Length<=1.0e-6)continue;
const int32 Samples=std::max(1,static_cast<int32>(std::ceil(Length/(Step*0.25))));
for(int32 I=0;I<=Samples;++I)
{
const double T=static_cast<double>(I)/Samples;
const double P[3]={Start[0]+Delta[0]*T,Start[1]+Delta[1]*T,Start[2]+Delta[2]*T};
if(P[0]<TileMin[0]||P[0]>TileMax[0]||P[1]<TileMin[1]||P[1]>TileMax[1]
||P[2]<TileMin[2]||P[2]>TileMax[2])continue;
int32 Base[3];
for(int32 Axis=0;Axis<3;++Axis)
Base[Axis]=static_cast<int32>(std::floor((P[Axis]-(&TileOrigin.X)[Axis])/Step));
for(int32 DZ=0;DZ<=1;++DZ)for(int32 DY=0;DY<=1;++DY)for(int32 DX=0;DX<=1;++DX)
{
const int32 IX=Base[0]+DX,IY=Base[1]+DY,IZ=Base[2]+DZ;
if(IX<0||IY<0||IZ<0||IX>Cells||IY>Cells||IZ>Cells)continue;
OutSamples.insert(PackLatticeKey(TileOrigin.X+IX*Step,
TileOrigin.Y+IY*Step,TileOrigin.Z+IZ*Step));
}
}
const auto It=FarConnectorSpatialBins.find({X,Y,Z});
if(It!=FarConnectorSpatialBins.end())
OutIndices.insert(OutIndices.end(),It->second.begin(),It->second.end());
}
return OutSamples.size();
std::sort(OutIndices.begin(),OutIndices.end());
OutIndices.erase(std::unique(OutIndices.begin(),OutIndices.end()),OutIndices.end());
}
class FScopedForcedFarAirSamples
@@ -2107,12 +2083,39 @@ private:
FarConnectorSegments.push_back({A,B,64.0f});
}
}
BuildFarConnectorSpatialBins();
if(!Parents.empty())
std::printf("[FarParents] pitch=%d rooms=%zu links=%llu clip=(%d,%d)..(%d,%d)\n",
ParentPitch,Parents.size(),static_cast<unsigned long long>(Primitives.size()),
ClipMin[0],ClipMin[1],ClipMax[0],ClipMax[1]);
}
void BuildFarConnectorSpatialBins()
{
constexpr int32 BinSize=2048;
FarConnectorSpatialBins.clear();
FarConnectorSpatialBins.reserve(FarConnectorSegments.size());
for(uint32 Index=0;Index<FarConnectorSegments.size();++Index)
{
const FFarConnectorSegment& Connector=FarConnectorSegments[Index];
const int32 MinX=static_cast<int32>(std::floor(
(std::min(Connector.Start.X,Connector.End.X)-Connector.Radius)/BinSize));
const int32 MaxX=static_cast<int32>(std::floor(
(std::max(Connector.Start.X,Connector.End.X)+Connector.Radius)/BinSize));
const int32 MinY=static_cast<int32>(std::floor(
(std::min(Connector.Start.Y,Connector.End.Y)-Connector.Radius)/BinSize));
const int32 MaxY=static_cast<int32>(std::floor(
(std::max(Connector.Start.Y,Connector.End.Y)+Connector.Radius)/BinSize));
const int32 MinZ=static_cast<int32>(std::floor(
(std::min(Connector.Start.Z,Connector.End.Z)-Connector.Radius)/BinSize));
const int32 MaxZ=static_cast<int32>(std::floor(
(std::max(Connector.Start.Z,Connector.End.Z)+Connector.Radius)/BinSize));
for(int32 Z=MinZ;Z<=MaxZ;++Z)for(int32 Y=MinY;Y<=MaxY;++Y)
for(int32 X=MinX;X<=MaxX;++X)
FarConnectorSpatialBins[{X,Y,Z}].push_back(Index);
}
}
const std::vector<uint32>& GetLineCandidates(int32 Axis,int32 A,int32 B) const
{
static const std::vector<uint32> Empty;
@@ -3236,6 +3239,7 @@ private:
std::vector<FLayerField> LayerFields;
std::vector<FPrimitive> Primitives;
std::vector<FFarConnectorSegment> FarConnectorSegments;
std::unordered_map<FBinKey,std::vector<uint32>,FBinHash> FarConnectorSpatialBins;
std::vector<FEditBrush> EditBrushes;
std::array<FAxisBins,3> AxisBins;
std::unordered_map<FBinKey,FBinItems,FBinHash> SpatialBins;