standalone: owner review fixes -- paged streaming in Core, no LOD fins, LOD0 stair patches fixed
From the owner's fly-through ("very impressive, in some cases slightly better than the original"):
- Streaming: Core compiles world-aligned fine-detail pages for tiles entering the view and releases
them when they leave; the viewer keeps resident tiles. One chunk crossing: 144 new tiles, 1,822
kept (was a full rebuild). A tile built as a late page hashes identically (density, mesh, payload,
topology) to the same tile from an initial build.
- LOD>=1 fins: off-surface planar connector panels are now checked against the source surface and
projected onto it; coarse audit 0 off-surface panels; far survival passes, bad-shell still fails.
- LOD0 stair patches: 2,630 sign-changing edges had one endpoint at the fixed +-4.125 fallback
(carve surfaces were excluded from distance storage); distances now completed analytically, 462
packed signs corrected; the audit now fails on any sign edge missing either endpoint (0 of 952,997).
- W1/W8 hashes equal; routes 5642/5642; look, passage and far audits pass.
Verified by me, interleaved (8 workers, cold): 1.014 s vs 1.008 s for aeeedaa, no regression.
Open: a chunk crossing still costs ~1.2 s of page compilation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
aeeedaa73d
commit
3b37d5702e
6 files changed
+939
-25
No files matched your search
@@ -319,6 +319,7 @@ public:
|
||||
|
||||
Stage=Clock::now();
|
||||
ApplyDetailBand(Stats.DetailBandLines);
|
||||
Stats.SurfaceProxyNodes+=CompleteSignEdgeDistances();
|
||||
Stats.SurfaceSeconds=std::chrono::duration<double>(Clock::now()-Stage).count();
|
||||
ValidatePassageRoutes();
|
||||
Built=true;
|
||||
@@ -782,6 +783,89 @@ public:
|
||||
return bPassageOnly?bPassageDetail:(Tested>0&&FlatShare<20.0&&bPass&&bPassageDetail);
|
||||
}
|
||||
|
||||
bool AuditGridStairIntegrity() const
|
||||
{
|
||||
uint64 CheckedEdges=0,MissingAny=0,MissingBoth=0;
|
||||
std::array<std::array<int32,4>,8> Examples{};
|
||||
size_t ExampleCount=0;
|
||||
const auto Record=[&](uint64 EdgeMask,uint64 CandidateA,uint64 CandidateB,
|
||||
int32 X,int32 Y,int32 Z,int32 Axis)
|
||||
{
|
||||
CheckedEdges+=std::popcount(EdgeMask);
|
||||
const uint64 Missing=EdgeMask&~(CandidateA&CandidateB);
|
||||
uint64 AnyMissing=Missing;
|
||||
MissingAny+=std::popcount(Missing);
|
||||
MissingBoth+=std::popcount(EdgeMask&~(CandidateA|CandidateB));
|
||||
while(AnyMissing&&ExampleCount<Examples.size())
|
||||
{
|
||||
const uint32 Bit=std::countr_zero(AnyMissing);AnyMissing&=AnyMissing-1;
|
||||
Examples[ExampleCount++]={X,Y,Z+static_cast<int32>(Bit),Axis};
|
||||
}
|
||||
};
|
||||
|
||||
const size_t Columns=static_cast<size_t>(Size[0])*Size[1];
|
||||
for(size_t Line=0;Line<Columns;++Line)
|
||||
{
|
||||
const int32 X=Min[0]+static_cast<int32>(Line%Size[0]);
|
||||
const int32 Y=Min[1]+static_cast<int32>(Line/Size[0]);
|
||||
const size_t Base=Line*WordsPerZ;
|
||||
for(size_t W=0;W<WordsPerZ;++W)
|
||||
{
|
||||
const size_t Word=Base+W;
|
||||
const uint64 Rock=RockWords[Word],Candidates=CandidateWords[Word];
|
||||
const uint64 PreviousRock=W?RockWords[Word-1]>>63:0;
|
||||
const uint64 PreviousCandidates=W?CandidateWords[Word-1]>>63:0;
|
||||
uint64 Valid=(Size[2]-W*64)>=64?~uint64{0}
|
||||
:((uint64{1}<<(Size[2]-W*64))-1);
|
||||
if(W==0)Valid&=~uint64{1};
|
||||
const uint64 ShiftedRock=(Rock<<1)|PreviousRock;
|
||||
const uint64 ShiftedCandidates=(Candidates<<1)|PreviousCandidates;
|
||||
Record((Rock^ShiftedRock)&Valid,Candidates,ShiftedCandidates,
|
||||
X,Y,Min[2]+static_cast<int32>(W*64),2);
|
||||
|
||||
if(X+1<Max[0]+1)
|
||||
{
|
||||
const size_t Other=Word+WordsPerZ;
|
||||
Record(Rock^RockWords[Other],Candidates,CandidateWords[Other],
|
||||
X,Y,Min[2]+static_cast<int32>(W*64),0);
|
||||
}
|
||||
if(Y+1<Max[1]+1)
|
||||
{
|
||||
const size_t Other=Word+static_cast<size_t>(Size[0])*WordsPerZ;
|
||||
Record(Rock^RockWords[Other],Candidates,CandidateWords[Other],
|
||||
X,Y,Min[2]+static_cast<int32>(W*64),1);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::printf("[GridStairDistanceAudit] region=(%d,%d,%d)..(%d,%d,%d) sign_edges=%llu candidate_fallback_edges=%llu both_fallback_edges=%llu status=%s\n",
|
||||
Min[0],Min[1],Min[2],Max[0],Max[1],Max[2],
|
||||
static_cast<unsigned long long>(CheckedEdges),
|
||||
static_cast<unsigned long long>(MissingAny),
|
||||
static_cast<unsigned long long>(MissingBoth),MissingAny==0?"PASS":"FAIL");
|
||||
const auto CandidateAt=[&](int32 X,int32 Y,int32 Z)
|
||||
{
|
||||
if(!Contains(X,Y,Z))return false;
|
||||
const size_t Column=static_cast<size_t>(Y-Min[1])*Size[0]+static_cast<size_t>(X-Min[0]);
|
||||
const size_t Zi=static_cast<size_t>(Z-Min[2]);
|
||||
return (CandidateWords[Column*WordsPerZ+(Zi>>6)]&(uint64{1}<<(Zi&63u)))!=0;
|
||||
};
|
||||
for(size_t I=0;I<ExampleCount;++I)
|
||||
{
|
||||
int32 AX=Examples[I][0],AY=Examples[I][1],AZ=Examples[I][2];
|
||||
int32 BX=AX,BY=AY,BZ=AZ;
|
||||
if(Examples[I][3]==0)++BX;else if(Examples[I][3]==1)++BY;else --BZ;
|
||||
const float AD=DensityAtLattice(AX,AY,AZ),BD=DensityAtLattice(BX,BY,BZ);
|
||||
const float AExact=AnalyticDensityAt(static_cast<float>(AX),static_cast<float>(AY),static_cast<float>(AZ));
|
||||
const float BExact=AnalyticDensityAt(static_cast<float>(BX),static_cast<float>(BY),static_cast<float>(BZ));
|
||||
std::printf("[GridStairDistanceCandidate] a=(%d,%d,%d) b=(%d,%d,%d) axis=%d candidate=(%d,%d) solid=(%d,%d) density=(%.4f,%.4f) exact=(%.4f,%.4f) critical_air=(%d,%d)\n",
|
||||
AX,AY,AZ,BX,BY,BZ,Examples[I][3],CandidateAt(AX,AY,AZ),CandidateAt(BX,BY,BZ),
|
||||
IsRock(AX,AY,AZ),IsRock(BX,BY,BZ),
|
||||
AD,BD,AExact,BExact,
|
||||
IsInsideCriticalAir(AX,AY,AZ),IsInsideCriticalAir(BX,BY,BZ));
|
||||
}
|
||||
return MissingAny==0;
|
||||
}
|
||||
|
||||
bool AuditViewSurface(double CameraX,double CameraY,double CameraZ,
|
||||
float Yaw,float Pitch) const
|
||||
{
|
||||
@@ -2812,6 +2896,107 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
uint64 CompleteSignEdgeDistances()
|
||||
{
|
||||
uint64 AddedTotal=0,SignCorrections=0;
|
||||
const size_t Columns=static_cast<size_t>(Size[0])*Size[1];
|
||||
for(int32 Pass=0;Pass<4;++Pass)
|
||||
{
|
||||
uint64 AddedThisPass=0;
|
||||
bool bSignChanged=false;
|
||||
const auto EnsureDistance=[&](int32 X,int32 Y,int32 Z)
|
||||
{
|
||||
const size_t Column=static_cast<size_t>(Y-Min[1])*Size[0]
|
||||
+static_cast<size_t>(X-Min[0]);
|
||||
const size_t Zi=static_cast<size_t>(Z-Min[2]);
|
||||
const size_t Word=Column*WordsPerZ+(Zi>>6);
|
||||
const uint64 Mask=uint64{1}<<(Zi&63u);
|
||||
if(CandidateWords[Word]&Mask)return;
|
||||
|
||||
const float Density=AnalyticDensityAt(static_cast<float>(X),
|
||||
static_cast<float>(Y),static_cast<float>(Z));
|
||||
const size_t Node=(Zi*static_cast<size_t>(Size[1])
|
||||
+static_cast<size_t>(Y-Min[1]))*Size[0]
|
||||
+static_cast<size_t>(X-Min[0]);
|
||||
StoreSurfaceDistance(Node,Density);
|
||||
CandidateWords[Word]|=Mask;
|
||||
++AddedThisPass;
|
||||
|
||||
const bool bExactRock=Density<0.0f;
|
||||
const bool bPackedRock=(RockWords[Word]&Mask)!=0;
|
||||
if(bExactRock!=bPackedRock)
|
||||
{
|
||||
if(bExactRock)RockWords[Word]|=Mask;
|
||||
else RockWords[Word]&=~Mask;
|
||||
++SignCorrections;
|
||||
bSignChanged=true;
|
||||
}
|
||||
};
|
||||
|
||||
for(size_t Line=0;Line<Columns;++Line)
|
||||
{
|
||||
const int32 X=Min[0]+static_cast<int32>(Line%Size[0]);
|
||||
const int32 Y=Min[1]+static_cast<int32>(Line/Size[0]);
|
||||
const size_t Base=Line*WordsPerZ;
|
||||
for(size_t W=0;W<WordsPerZ;++W)
|
||||
{
|
||||
const size_t Word=Base+W;
|
||||
const uint64 Rock=RockWords[Word],Candidates=CandidateWords[Word];
|
||||
const uint64 PreviousRock=W?RockWords[Word-1]>>63:0;
|
||||
const uint64 PreviousCandidates=W?CandidateWords[Word-1]>>63:0;
|
||||
uint64 Valid=(Size[2]-W*64)>=64?~uint64{0}
|
||||
:((uint64{1}<<(Size[2]-W*64))-1);
|
||||
if(W==0)Valid&=~uint64{1};
|
||||
|
||||
const uint64 ShiftedRock=(Rock<<1)|PreviousRock;
|
||||
const uint64 ShiftedCandidates=(Candidates<<1)|PreviousCandidates;
|
||||
uint64 Missing=((Rock^ShiftedRock)&Valid)
|
||||
&~(Candidates&ShiftedCandidates);
|
||||
while(Missing)
|
||||
{
|
||||
const uint32 Bit=std::countr_zero(Missing);Missing&=Missing-1;
|
||||
const int32 Z=Min[2]+static_cast<int32>(W*64+Bit);
|
||||
EnsureDistance(X,Y,Z);
|
||||
EnsureDistance(X,Y,Z-1);
|
||||
}
|
||||
|
||||
if(X<Max[0])
|
||||
{
|
||||
const size_t Other=Word+WordsPerZ;
|
||||
Missing=(Rock^RockWords[Other])&Valid
|
||||
&~(Candidates&CandidateWords[Other]);
|
||||
while(Missing)
|
||||
{
|
||||
const uint32 Bit=std::countr_zero(Missing);Missing&=Missing-1;
|
||||
const int32 Z=Min[2]+static_cast<int32>(W*64+Bit);
|
||||
EnsureDistance(X,Y,Z);
|
||||
EnsureDistance(X+1,Y,Z);
|
||||
}
|
||||
}
|
||||
if(Y<Max[1])
|
||||
{
|
||||
const size_t Other=Word+static_cast<size_t>(Size[0])*WordsPerZ;
|
||||
Missing=(Rock^RockWords[Other])&Valid
|
||||
&~(Candidates&CandidateWords[Other]);
|
||||
while(Missing)
|
||||
{
|
||||
const uint32 Bit=std::countr_zero(Missing);Missing&=Missing-1;
|
||||
const int32 Z=Min[2]+static_cast<int32>(W*64+Bit);
|
||||
EnsureDistance(X,Y,Z);
|
||||
EnsureDistance(X,Y+1,Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AddedTotal+=AddedThisPass;
|
||||
if(!bSignChanged)break;
|
||||
}
|
||||
std::printf("[GridStairDistanceRepair] exact_endpoint_proxies=%llu occupancy_corrections=%llu\n",
|
||||
static_cast<unsigned long long>(AddedTotal),
|
||||
static_cast<unsigned long long>(SignCorrections));
|
||||
return AddedTotal;
|
||||
}
|
||||
|
||||
void StoreSurfaceDistance(size_t Node,float Density)
|
||||
{
|
||||
int32 Q=static_cast<int32>(std::lround(Density*16.0f));
|
||||
|
||||
Reference in new issue
Block a user