wip(assembler): round L32 -- smooth Gradient interface at full amplitude (no rings, not flat)

Band faces now use signed distance to the displaced solid intervals, continuous across bands, so
MC interpolates the interface instead of terracing at density levels. The Gradient amplitude is
restored to width/8 (about 4 m peak-to-peak at 16 m). Ring/terrace audit at LOD0-8 on the FI floor and SW
ceiling passes; negative controls: L30 (rings) and L31 (flat) both fail. Hole/interface audits,
16 passage rows and 24/24 determinism pass. Evaluator 20. Cost vs L31 SW +1.9%, FI +1.5%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-21 20:27:29 +02:00
1 parent 28069f0d98
commit d0158c6019
31 files changed
+2207 -111

No files matched your search

@@ -250,9 +250,8 @@ namespace VoxelForgeCore
inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256;
inline constexpr std::uint32_t WorldAssemblySchemaVersion = 2;
// Version 14 adds shared passage columns; version 16 smooths owner Gradient faces;
// version 18 limits FloatingIslands Gradient face displacement to one voxel;
// version 19 reduces it to one quarter voxel to remove the residual floor contour.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 19;
// version 20 restores full Gradient amplitude and uses a continuous signed-distance band union.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 20;
enum class FieldChannel : std::uint32_t
{
+240 -25
View File
@@ -1217,6 +1217,82 @@ inline void AppendFarStratumShells(const FStandaloneOwnerWorld& World,const FSta
Mesh.NumSurfaceVertices=OldSurfaceVertices+AddedVertices;
}
// Fill only underside cells that marching cubes missed. Active transitions use the
// same displaced face and passage-mouth fade as the signed-distance field.
struct FTransitionFaceReplacement
{
double BaseZVoxels=0.0;
double MaximumDisplacementVoxels=0.0;
std::vector<uint8> Cells;
};
inline int32 RemoveCoarseTransitionFaceTriangles(FVoxelMeshData& Mesh,
const FIntVector& Origin,int32 Step,int32 GridSide,double VoxelSizeCm,
const std::vector<FTransitionFaceReplacement>& Replacements,bool bUpward)
{
if(Step<=0||GridSide<2||VoxelSizeCm<=0.0||Replacements.empty())return 0;
const int32 TriangleCount=Mesh.Triangles.Num()/3;
const int32 OldCeilingStart=std::max(0,TriangleCount-Mesh.NumCeilingTriangles);
TArray<uint8> OldMasks=Mesh.TriangleSkirtFaceMasks;
OldMasks.SetNum(TriangleCount);
TArray<int32> KeptTriangles;
TArray<uint8> KeptMasks;
KeptTriangles.Reserve(Mesh.Triangles.Num());
KeptMasks.Reserve(TriangleCount);
int32 Removed=0,RemovedCeiling=0;
const int32 CellSide=GridSide-1;
for(int32 Triangle=0;Triangle<TriangleCount;++Triangle)
{
const int32 IA=Mesh.Triangles[Triangle*3];
const int32 IB=Mesh.Triangles[Triangle*3+1];
const int32 IC=Mesh.Triangles[Triangle*3+2];
bool bRemove=false;
if(OldMasks[Triangle]==0&&IA>=0&&IB>=0&&IC>=0
&&IA<Mesh.Vertices.Num()&&IB<Mesh.Vertices.Num()&&IC<Mesh.Vertices.Num())
{
const FVector& A=Mesh.Vertices[IA];
const FVector& B=Mesh.Vertices[IB];
const FVector& C=Mesh.Vertices[IC];
const FVector GeometricNormal=FVector::CrossProduct(B-A,C-A);
const double NormalLength=GeometricNormal.Size();
const double Facing=NormalLength>1.0e-12?GeometricNormal.Z/NormalLength:0.0;
if((bUpward&&Facing>0.35)||(!bUpward&&Facing< -0.35))
{
const double X=(A.X+B.X+C.X)/(3.0*VoxelSizeCm);
const double Y=(A.Y+B.Y+C.Y)/(3.0*VoxelSizeCm);
const double Z=(A.Z+B.Z+C.Z)/(3.0*VoxelSizeCm);
const int32 CellX=static_cast<int32>(std::floor((X-Origin.X)/Step));
const int32 CellY=static_cast<int32>(std::floor((Y-Origin.Y)/Step));
if(CellX>=0&&CellX<CellSide&&CellY>=0&&CellY<CellSide)
{
const std::size_t Cell=static_cast<std::size_t>(CellY)*CellSide+CellX;
for(const auto& Replacement:Replacements)
{
if(Cell>=Replacement.Cells.size()||!Replacement.Cells[Cell])continue;
const double Margin=Replacement.MaximumDisplacementVoxels+4.0;
if(Z>=Replacement.BaseZVoxels-Margin
&&Z<=Replacement.BaseZVoxels+Margin)
{bRemove=true;break;}
}
}
}
}
if(bRemove)
{
++Removed;
if(Triangle>=OldCeilingStart)++RemovedCeiling;
continue;
}
KeptTriangles.Add(IA);KeptTriangles.Add(IB);KeptTriangles.Add(IC);
KeptMasks.Add(OldMasks[Triangle]);
}
if(Removed==0)return 0;
Mesh.Triangles=std::move(KeptTriangles);
Mesh.TriangleSkirtFaceMasks=std::move(KeptMasks);
Mesh.NumCeilingTriangles=std::max(0,Mesh.NumCeilingTriangles-RemovedCeiling);
return Removed;
}
inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
const FStandaloneShapeWorld& Shape,const FVoxelTileKey& Key,int32 Step,FVoxelMeshData& Mesh)
{
@@ -1230,9 +1306,14 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
{
double FaceZ=0.0;
double Thickness=0.0;
double MaximumDisplacementVoxels=0.0;
std::vector<double> FaceHeights;
std::vector<uint8> SolidAbove;
const VoxelForgeCore::ResolvedLayoutStratumV2* Stratum=nullptr;
bool bTransition=false;
};
std::vector<FCandidate> Candidates;
std::vector<FTransitionFaceReplacement> Replacements;
const double CoreMicrons=std::max<std::uint32_t>(1,World.CoreVoxelSizeMicrons);
for(const FStrateSlot& Slot:World.Manager->GetLayout())
{
@@ -1243,19 +1324,34 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
Candidate.FaceZ=static_cast<double>(Stratum->ceiling.bottomMicrometres)/CoreMicrons;
Candidate.Thickness=static_cast<double>(Stratum->ceiling.topMicrometres
-Stratum->ceiling.bottomMicrometres)/CoreMicrons;
if(Candidate.FaceZ<Origin.Z-1.0e-6||Candidate.FaceZ>Origin.Z+Extent+1.0e-6)continue;
Candidate.Stratum=Stratum;
const auto* transitionUpper=Shape.FindResolvedLayoutStratumByOrder(Stratum->order-1);
const bool bTransition=transitionUpper
&&Shape.IsResolvedLayoutTransitionActive(*transitionUpper);
const double displacement=bTransition?static_cast<double>(
Shape.ResolvedTransitionMaximumFaceDisplacementMicrometres(*transitionUpper,*Stratum))
/CoreMicrons:0.0;
if(Candidate.FaceZ<Origin.Z-displacement-1.0e-6
||Candidate.FaceZ>Origin.Z+Extent+displacement+1.0e-6)continue;
Candidate.bTransition=bTransition;
Candidate.MaximumDisplacementVoxels=displacement;
const double Epsilon=std::min(0.5,Candidate.Thickness*0.25);
if(Epsilon<=0.0)continue;
Candidate.SolidAbove.resize(static_cast<std::size_t>(GridSide)*GridSide,0);
const std::size_t GridCount=static_cast<std::size_t>(GridSide)*GridSide;
Candidate.FaceHeights.resize(GridCount,Candidate.FaceZ);
Candidate.SolidAbove.resize(GridCount,0);
bool AnySolidAbove=false;
for(int32 Y=0;Y<GridSide;++Y)for(int32 X=0;X<GridSide;++X)
{
const double WorldX=Origin.X+X*GridStep;
const double WorldY=Origin.Y+Y*GridStep;
const std::size_t GridIndex=static_cast<std::size_t>(Y*GridSide+X);
Candidate.bTransition=Shape.ResolvedCeilingBottomAt(*Candidate.Stratum,
WorldX,WorldY,Candidate.FaceHeights[GridIndex])||Candidate.bTransition;
const float Above=Shape.DensityAt(static_cast<float>(WorldX),static_cast<float>(WorldY),
static_cast<float>(Candidate.FaceZ+Epsilon));
static_cast<float>(Candidate.FaceHeights[GridIndex]+Epsilon));
const bool bSolidAbove=std::isfinite(Above)&&Above<0.0f;
Candidate.SolidAbove[static_cast<std::size_t>(Y*GridSide+X)]=bSolidAbove?1:0;
Candidate.SolidAbove[GridIndex]=bSolidAbove?1:0;
AnySolidAbove=AnySolidAbove||bSolidAbove;
}
if(AnySolidAbove)Candidates.push_back(std::move(Candidate));
@@ -1277,8 +1373,19 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
std::vector<int32> NewTriangles;
for(const FCandidate& Candidate:Candidates)
{
std::vector<int32> VertexMap(static_cast<std::size_t>(GridSide)*GridSide,INDEX_NONE);
const double CeilingZ=Candidate.FaceZ;
const std::size_t GridCount=static_cast<std::size_t>(GridSide)*GridSide;
std::vector<int32> VertexMap(GridCount,INDEX_NONE);
FTransitionFaceReplacement Replacement;
Replacement.BaseZVoxels=Candidate.FaceZ;
Replacement.MaximumDisplacementVoxels=Candidate.MaximumDisplacementVoxels;
Replacement.Cells.resize(static_cast<std::size_t>(GridSide-1)*(GridSide-1),0);
const auto heightAt=[&](double X,double Y)
{
if(!Candidate.bTransition)return Candidate.FaceZ;
double height=Candidate.FaceZ;
Shape.ResolvedCeilingBottomAt(*Candidate.Stratum,X,Y,height);
return height;
};
const auto AddVertex=[&](int32 X,int32 Y)
{
const std::size_t GridIndex=static_cast<std::size_t>(Y*GridSide+X);
@@ -1286,8 +1393,20 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
if(Mapped!=INDEX_NONE)return Mapped;
Mapped=static_cast<int32>(NewVertices.size());
const double WorldX=Origin.X+X*GridStep,WorldY=Origin.Y+Y*GridStep;
NewVertices.emplace_back(WorldX*VoxelSizeCm,WorldY*VoxelSizeCm,CeilingZ*VoxelSizeCm);
NewNormals.emplace_back(0.0,0.0,-1.0);
const double FaceZ=Candidate.FaceHeights[GridIndex];
FVector Normal(0.0,0.0,-1.0);
if(Candidate.bTransition)
{
const double Delta=std::max(1.0,std::min<double>(GridStep,4.0));
const double DX=(heightAt(WorldX+Delta,WorldY)-heightAt(WorldX-Delta,WorldY))
/(2.0*Delta);
const double DY=(heightAt(WorldX,WorldY+Delta)-heightAt(WorldX,WorldY-Delta))
/(2.0*Delta);
Normal=FVector(DX,DY,-1.0);
Normal.Normalize();
}
NewVertices.emplace_back(WorldX*VoxelSizeCm,WorldY*VoxelSizeCm,FaceZ*VoxelSizeCm);
NewNormals.push_back(Normal);
if(bHasUVs)NewUVs.emplace_back(static_cast<float>(WorldX),static_cast<float>(WorldY));
if(bHasColors)NewColors.push_back(Color);
return Mapped;
@@ -1300,15 +1419,40 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
||!Candidate.SolidAbove[I01]||!Candidate.SolidAbove[I11])continue;
const double CellX0=Origin.X+X*GridStep,CellY0=Origin.Y+Y*GridStep;
const double CellX1=CellX0+GridStep,CellY1=CellY0+GridStep;
// Suppress a coincident plane only when it covers the full cell. A hit at just the
// center of a curved shell triangle is not enough to leave the rest of this cap cell open.
if(MeshIndex.HasDownwardCellCoverage(CellX0,CellY0,CellX1,CellY1,CeilingZ,0.001))continue;
bool fullyCovered=false;
if(!Candidate.bTransition)
fullyCovered=MeshIndex.HasDownwardCellCoverage(
CellX0,CellY0,CellX1,CellY1,Candidate.FaceZ,0.001);
else
{
fullyCovered=true;
constexpr double CoverageSamples[5][2]={
{0.0,0.0},{1.0,0.0},{0.0,1.0},{1.0,1.0},{0.5,0.5}};
for(const auto& Sample:CoverageSamples)
{
const double U=Sample[0],V=Sample[1];
const double SampleX=CellX0+(CellX1-CellX0)*U;
const double SampleY=CellY0+(CellY1-CellY0)*V;
const double SampleZ=heightAt(SampleX,SampleY);
if(!MeshIndex.HasDownwardHit(SampleX,SampleY,SampleZ,0.25))
fullyCovered=false;
}
}
if(fullyCovered)continue;
if(Key.Level>=4&&Candidate.bTransition)
Replacement.Cells[static_cast<std::size_t>(Y)*(GridSide-1)+X]=1;
const int32 A=AddVertex(X,Y),B=AddVertex(X+1,Y);
const int32 C=AddVertex(X+1,Y+1),D=AddVertex(X,Y+1);
NewTriangles.insert(NewTriangles.end(),{A,C,B,A,D,C});
}
if(Key.Level>=4&&Candidate.bTransition
&&std::any_of(Replacement.Cells.begin(),Replacement.Cells.end(),
[](uint8 Value){return Value!=0;}))
Replacements.push_back(std::move(Replacement));
}
if(NewTriangles.empty())return;
const int32 removedCoarse=RemoveCoarseTransitionFaceTriangles(Mesh,Origin,GridStep,
GridSide,VoxelSizeCm,Replacements,false);
const int32 AddedVertices=static_cast<int32>(NewVertices.size());
auto InsertVertices=[&](auto& Existing,const auto& Added)
@@ -1347,9 +1491,8 @@ inline void AppendStratumBoundaryCeilings(const FStandaloneOwnerWorld& World,
Mesh.NumCeilingTriangles+=static_cast<int32>(NewTriangles.size()/3);
}
// Add the interior-facing top of each bedrock band. The density composition already
// makes this band solid and editable; this planar closure keeps its visible floor
// continuous when a coarse marching-cubes step would otherwise skip a sub-voxel band.
// Fill only top cells that marching cubes missed. Active transitions use the same
// displaced face and passage-mouth fade as the signed-distance field.
inline void AppendStratumBoundaryFloors(const FStandaloneOwnerWorld& World,
const FStandaloneShapeWorld& Shape,const FVoxelTileKey& Key,int32 Step,FVoxelMeshData& Mesh)
{
@@ -1358,8 +1501,16 @@ inline void AppendStratumBoundaryFloors(const FStandaloneOwnerWorld& World,
const int32 Extent=Key.ExtentVoxels();
if(Extent<=0||Extent%Step!=0)return;
const int32 GridSide=Extent/Step+1;
struct FCandidate { double FloorZ=0.0; double Thickness=0.0; };
struct FCandidate
{
double FloorZ=0.0;
double Thickness=0.0;
double MaximumDisplacementVoxels=0.0;
const VoxelForgeCore::ResolvedLayoutStratumV2* Stratum=nullptr;
bool bTransition=false;
};
std::vector<FCandidate> Candidates;
std::vector<FTransitionFaceReplacement> Replacements;
const double CoreMicrons=std::max<std::uint32_t>(1,World.CoreVoxelSizeMicrons);
for(const FStrateSlot& Slot:World.Manager->GetLayout())
{
@@ -1367,9 +1518,17 @@ inline void AppendStratumBoundaryFloors(const FStandaloneOwnerWorld& World,
if(!Stratum||!Stratum->bedrock.presentInCurrentField
||Stratum->bedrock.topMicrometres<=Stratum->bedrock.bottomMicrometres)continue;
const double FloorZ=static_cast<double>(Stratum->bedrock.topMicrometres)/CoreMicrons;
if(FloorZ<Origin.Z-1.0e-6||FloorZ>Origin.Z+Extent+1.0e-6)continue;
const auto* transitionLower=Shape.FindResolvedLayoutStratumByOrder(Stratum->order+1);
const bool bTransition=transitionLower
&&Shape.IsResolvedLayoutTransitionActive(*Stratum);
const double displacement=bTransition
?static_cast<double>(Shape.ResolvedTransitionMaximumFaceDisplacementMicrometres(
*Stratum,*transitionLower))/CoreMicrons
:0.0;
if(FloorZ<Origin.Z-displacement-1.0e-6
||FloorZ>Origin.Z+Extent+displacement+1.0e-6)continue;
Candidates.push_back({FloorZ,static_cast<double>(Stratum->bedrock.topMicrometres
-Stratum->bedrock.bottomMicrometres)/CoreMicrons});
-Stratum->bedrock.bottomMicrometres)/CoreMicrons,displacement,Stratum,bTransition});
}
if(Candidates.empty())return;
@@ -1390,16 +1549,34 @@ inline void AppendStratumBoundaryFloors(const FStandaloneOwnerWorld& World,
{
const double Epsilon=std::min(0.5,Candidate.Thickness*0.25);
if(Epsilon<=0.0)continue;
std::vector<uint8> SolidBelow(static_cast<std::size_t>(GridSide)*GridSide,0);
const std::size_t GridCount=static_cast<std::size_t>(GridSide)*GridSide;
std::vector<double> faceHeights(GridCount,Candidate.FloorZ);
std::vector<uint8> solidBelow(GridCount,0);
FTransitionFaceReplacement Replacement;
Replacement.BaseZVoxels=Candidate.FloorZ;
Replacement.MaximumDisplacementVoxels=Candidate.MaximumDisplacementVoxels;
Replacement.Cells.resize(static_cast<std::size_t>(GridSide-1)*(GridSide-1),0);
for(int32 Y=0;Y<GridSide;++Y)for(int32 X=0;X<GridSide;++X)
{
const double WorldX=Origin.X+X*Step,WorldY=Origin.Y+Y*Step;
const std::size_t GridIndex=static_cast<std::size_t>(Y*GridSide+X);
if(Candidate.bTransition)
Shape.ResolvedBedrockTopAt(*Candidate.Stratum,WorldX,WorldY,
faceHeights[GridIndex]);
const float Density=Shape.DensityAt(static_cast<float>(WorldX),static_cast<float>(WorldY),
static_cast<float>(Candidate.FloorZ-Epsilon));
SolidBelow[static_cast<std::size_t>(Y*GridSide+X)]=
static_cast<float>(faceHeights[GridIndex]-Epsilon));
solidBelow[GridIndex]=
std::isfinite(Density)&&Density<0.0f?1:0;
}
std::vector<int32> VertexMap(static_cast<std::size_t>(GridSide)*GridSide,INDEX_NONE);
const auto heightAt=[&](double X,double Y)
{
if(!Candidate.bTransition)return Candidate.FloorZ;
double height=Candidate.FloorZ;
if(Candidate.bTransition)
Shape.ResolvedBedrockTopAt(*Candidate.Stratum,X,Y,height);
return height;
};
std::vector<int32> VertexMap(GridCount,INDEX_NONE);
const auto AddVertex=[&](int32 X,int32 Y)
{
const std::size_t GridIndex=static_cast<std::size_t>(Y*GridSide+X);
@@ -1407,9 +1584,20 @@ inline void AppendStratumBoundaryFloors(const FStandaloneOwnerWorld& World,
if(Mapped!=INDEX_NONE)return Mapped;
Mapped=static_cast<int32>(NewVertices.size());
const double WorldX=Origin.X+X*Step,WorldY=Origin.Y+Y*Step;
FVector Normal(0.0,0.0,1.0);
if(Candidate.bTransition)
{
const double Delta=std::max(1.0,std::min<double>(Step,4.0));
const double DX=(heightAt(WorldX+Delta,WorldY)-heightAt(WorldX-Delta,WorldY))
/(2.0*Delta);
const double DY=(heightAt(WorldX,WorldY+Delta)-heightAt(WorldX,WorldY-Delta))
/(2.0*Delta);
Normal=FVector(-DX,-DY,1.0);
Normal.Normalize();
}
NewVertices.emplace_back(WorldX*VoxelSizeCm,WorldY*VoxelSizeCm,
Candidate.FloorZ*VoxelSizeCm);
NewNormals.emplace_back(0.0,0.0,1.0);
faceHeights[GridIndex]*VoxelSizeCm);
NewNormals.push_back(Normal);
if(bHasUVs)NewUVs.emplace_back(static_cast<float>(WorldX),static_cast<float>(WorldY));
if(bHasColors)NewColors.push_back(Color);
return Mapped;
@@ -1418,16 +1606,43 @@ inline void AppendStratumBoundaryFloors(const FStandaloneOwnerWorld& World,
{
const std::size_t I00=static_cast<std::size_t>(Y*GridSide+X);
const std::size_t I10=I00+1,I01=I00+GridSide,I11=I01+1;
if(!SolidBelow[I00]||!SolidBelow[I10]||!SolidBelow[I01]||!SolidBelow[I11])continue;
if(!solidBelow[I00]||!solidBelow[I10]||!solidBelow[I01]||!solidBelow[I11])continue;
const double X0=Origin.X+X*Step,Y0=Origin.Y+Y*Step;
const double X1=X0+Step,Y1=Y0+Step;
if(MeshIndex.HasUpwardCellCoverage(X0,Y0,X1,Y1,Candidate.FloorZ,0.001))continue;
bool fullyCovered=false;
if(!Candidate.bTransition)
fullyCovered=MeshIndex.HasUpwardCellCoverage(
X0,Y0,X1,Y1,Candidate.FloorZ,0.001);
else
{
fullyCovered=true;
constexpr double CoverageSamples[5][2]={
{0.0,0.0},{1.0,0.0},{0.0,1.0},{1.0,1.0},{0.5,0.5}};
for(const auto& Sample:CoverageSamples)
{
const double U=Sample[0],V=Sample[1];
const double SampleX=X0+(X1-X0)*U;
const double SampleY=Y0+(Y1-Y0)*V;
const double SampleZ=heightAt(SampleX,SampleY);
if(!MeshIndex.HasUpwardHit(SampleX,SampleY,SampleZ,0.25))
fullyCovered=false;
}
}
if(fullyCovered)continue;
if(Key.Level>=4&&Candidate.bTransition)
Replacement.Cells[static_cast<std::size_t>(Y)*(GridSide-1)+X]=1;
const int32 A=AddVertex(X,Y),B=AddVertex(X+1,Y);
const int32 C=AddVertex(X+1,Y+1),D=AddVertex(X,Y+1);
NewTriangles.insert(NewTriangles.end(),{A,B,C,A,C,D});
}
if(Key.Level>=4&&Candidate.bTransition
&&std::any_of(Replacement.Cells.begin(),Replacement.Cells.end(),
[](uint8 Value){return Value!=0;}))
Replacements.push_back(std::move(Replacement));
}
if(NewTriangles.empty())return;
const int32 removedCoarse=RemoveCoarseTransitionFaceTriangles(Mesh,Origin,Step,
GridSide,VoxelSizeCm,Replacements,true);
const int32 AddedVertices=static_cast<int32>(NewVertices.size());
auto InsertVertices=[&](auto& Existing,const auto& Added)
+16 -5
View File
@@ -71,8 +71,22 @@ namespace
const std::int64_t ix = TransitionFloorDiv(x, cell), iy = TransitionFloorDiv(y, cell);
const std::int64_t tx = TransitionFade(((x - ix * cell) * TransitionQ16) / cell);
const std::int64_t ty = TransitionFade(((y - iy * cell) * TransitionQ16) / cell);
std::uint64_t prefix=14695981039346656037ull;
TransitionHashWord(prefix,static_cast<std::uint32_t>(seed));
TransitionHashWord(prefix,static_cast<std::uint32_t>(interfaceIndex));
const auto at = [&](std::int64_t dx, std::int64_t dy)
{ return TransitionNoiseValue(seed, interfaceIndex, ix + dx, iy + dy, 0, salt); };
{
std::uint64_t hash=prefix;
TransitionHashWord(hash,static_cast<std::uint64_t>(ix+dx));
TransitionHashWord(hash,static_cast<std::uint64_t>(iy+dy));
TransitionHashWord(hash,0);
TransitionHashWord(hash,salt);
hash ^= hash >> 30; hash *= 0xbf58476d1ce4e5b9ull;
hash ^= hash >> 27; hash *= 0x94d049bb133111ebull;
hash ^= hash >> 31;
const std::uint32_t bits=static_cast<std::uint32_t>(hash>>32);
return static_cast<std::int64_t>(bits>>15)-TransitionQ16;
};
return TransitionLerp(TransitionLerp(at(0, 0), at(1, 0), tx),
TransitionLerp(at(0, 1), at(1, 1), tx), ty);
}
@@ -359,10 +373,7 @@ ResolvedLayoutTransitionBandsV1 EvaluateResolvedLayoutTransitionBandsV1(
return result;
}
// FloatingIslands floor faces retain the same deterministic Gradient field but
// cap displacement at one quarter voxel so the transition does not read as a contour.
const std::int64_t gradientDivisor=upper.generatorKind=="FloatingIslands"?256:8;
const std::int64_t displacement = (noise * (width / gradientDivisor)) / TransitionQ16;
const std::int64_t displacement = (noise * (width / 8)) / TransitionQ16;
const std::int64_t interfaceZ = seam + displacement;
result.upperBedrockBottomMicrometres = interfaceZ;
result.upperBedrockTopMicrometres = interfaceZ + upperThickness;
+157 -64
View File
@@ -270,7 +270,7 @@ public:
{
const std::int64_t width=std::max<std::int64_t>(0,Upper.transitionWidthMicrometres);
if(Upper.transitionMode=="Gradient")
return width/(Upper.generatorKind=="FloatingIslands"?256:8);
return width/8;
if(Upper.transitionMode!="Interleaved")return 0;
const std::int64_t upperThickness=std::max<std::int64_t>(0,
Upper.bedrock.topMicrometres-Upper.bedrock.bottomMicrometres);
@@ -385,6 +385,70 @@ public:
return weight;
}
VoxelForgeCore::ResolvedLayoutTransitionBandsV1 ResolvedTransitionBandsAtXY(
const VoxelForgeCore::ResolvedLayoutStratumV2& Upper,
const VoxelForgeCore::ResolvedLayoutStratumV2& Lower,
std::int64_t XMicrometres,std::int64_t YMicrometres,bool SkipPassageFade=false) const
{
auto bands=VoxelForgeCore::EvaluateResolvedLayoutTransitionBandsV1(Upper,Lower,
Owner?Owner->Seed:0,ResolvedLayout?ResolvedLayout->strateLayoutChunkSizeMicrometres:0,
XMicrometres,YMicrometres);
constexpr std::int64_t TransitionQ16=1ll<<16;
const std::int64_t weight=SkipPassageFade?TransitionQ16:
ResolvedTransitionPassageWeightQ16(Upper,Lower,XMicrometres,YMicrometres);
if(weight>=TransitionQ16)return bands;
const std::int64_t seam=Upper.bedrock.bottomMicrometres;
const std::int64_t upperThickness=Upper.bedrock.topMicrometres-seam;
const std::int64_t lowerThickness=Lower.ceiling.topMicrometres
-Lower.ceiling.bottomMicrometres;
const auto scaled=[&](std::int64_t value){return (value*weight)/TransitionQ16;};
bands.upperBedrockBottomMicrometres=seam+scaled(
bands.upperBedrockBottomMicrometres-seam);
bands.upperBedrockTopMicrometres=bands.upperBedrockBottomMicrometres+upperThickness;
bands.lowerCeilingTopMicrometres=seam+scaled(
bands.lowerCeilingTopMicrometres-seam);
bands.lowerCeilingBottomMicrometres=bands.lowerCeilingTopMicrometres-lowerThickness;
bands.crossingDepthMicrometres=std::max<std::int64_t>(0,
bands.lowerCeilingTopMicrometres-bands.upperBedrockBottomMicrometres);
return bands;
}
bool ResolvedBedrockTopAt(const VoxelForgeCore::ResolvedLayoutStratumV2& Upper,
double X,double Y,double& TopZ) const
{
const auto* lower=FindResolvedLayoutStratumByOrder(Upper.order+1);
if(!lower||!Owner||Owner->CoreVoxelSizeMicrons==0
||!IsResolvedLayoutTransitionActive(Upper))return false;
const auto toMicrometres=[&](double value)
{return static_cast<std::int64_t>(std::llround(value*Owner->CoreVoxelSizeMicrons));};
const auto* tileQueries=ActivePassageTileQueries;
const bool skipPassageFade=tileQueries&&tileQueries->matches(*this)
&&!tileQueries->mayContainTransitionPassageFade();
const auto bands=ResolvedTransitionBandsAtXY(Upper,*lower,toMicrometres(X),
toMicrometres(Y),skipPassageFade);
TopZ=static_cast<double>(bands.upperBedrockTopMicrometres)
/Owner->CoreVoxelSizeMicrons;
return std::isfinite(TopZ);
}
bool ResolvedCeilingBottomAt(const VoxelForgeCore::ResolvedLayoutStratumV2& Lower,
double X,double Y,double& BottomZ) const
{
const auto* upper=FindResolvedLayoutStratumByOrder(Lower.order-1);
if(!upper||!Owner||Owner->CoreVoxelSizeMicrons==0
||!IsResolvedLayoutTransitionActive(*upper))return false;
const auto toMicrometres=[&](double value)
{return static_cast<std::int64_t>(std::llround(value*Owner->CoreVoxelSizeMicrons));};
const auto* tileQueries=ActivePassageTileQueries;
const bool skipPassageFade=tileQueries&&tileQueries->matches(*this)
&&!tileQueries->mayContainTransitionPassageFade();
const auto bands=ResolvedTransitionBandsAtXY(*upper,Lower,toMicrometres(X),
toMicrometres(Y),skipPassageFade);
BottomZ=static_cast<double>(bands.lowerCeilingBottomMicrometres)
/Owner->CoreVoxelSizeMicrons;
return std::isfinite(BottomZ);
}
bool IsInsideResolvedStrateBoundaryBand(float Z) const
{
#if defined(VF_L30_ENABLE_COST_COUNTERS)
@@ -471,12 +535,72 @@ public:
return density;
}
}
if(!ResolvedLayout||!Owner||!Owner->Manager||!std::isfinite(Z))return density;
if(!ResolvedLayout||!Owner||!Owner->Manager||Owner->CoreVoxelSizeMicrons==0
||!std::isfinite(Z))return density;
const double zMicrometres=static_cast<double>(Z)*Owner->CoreVoxelSizeMicrons;
if(ResolvedLayout->strates.size()==2)
{
const auto* transitionUpper=FindResolvedLayoutStratumByOrder(0);
const auto* transitionLower=FindResolvedLayoutStratumByOrder(1);
if(transitionUpper&&transitionLower
&&IsResolvedLayoutTransitionActive(*transitionUpper))
{
#if defined(VF_L30_ENABLE_COST_COUNTERS)
++ThreadClassificationStats().TransitionWindowChecks;
#endif
const auto maximumDisplacement=ResolvedTransitionMaximumFaceDisplacementMicrometres(
*transitionUpper,*transitionLower);
const double minimum=std::min(transitionUpper->bedrock.bottomMicrometres,
transitionLower->ceiling.bottomMicrometres)-maximumDisplacement;
const double maximum=std::max(transitionUpper->bedrock.topMicrometres,
transitionLower->ceiling.topMicrometres)+maximumDisplacement;
if(zMicrometres>=minimum&&zMicrometres<maximum)
{
#if defined(VF_L30_ENABLE_COST_COUNTERS)
++ThreadClassificationStats().TransitionWindowHits;
++ThreadClassificationStats().TransitionEvaluatorCalls;
#endif
const auto* tileQueries=ActivePassageTileQueries;
const bool skipPassageFade=tileQueries&&tileQueries->matches(*this)
&&!tileQueries->mayContainTransitionPassageFade();
#if defined(VF_L30_ENABLE_COST_COUNTERS)
if(skipPassageFade)
++ThreadClassificationStats().TransitionPassageTileSkips;
#endif
const auto xMicrometres=static_cast<std::int64_t>(std::llround(
static_cast<double>(X)*Owner->CoreVoxelSizeMicrons));
const auto yMicrometres=static_cast<std::int64_t>(std::llround(
static_cast<double>(Y)*Owner->CoreVoxelSizeMicrons));
const auto bands=ResolvedTransitionBandsAtXY(*transitionUpper,
*transitionLower,xMicrometres,yMicrometres,skipPassageFade);
const std::int64_t solidBottom=std::min(
bands.upperBedrockBottomMicrometres,bands.lowerCeilingBottomMicrometres);
const std::int64_t solidTop=std::max(
bands.upperBedrockTopMicrometres,bands.lowerCeilingTopMicrometres);
const double signedDistanceMicrometres=zMicrometres<solidBottom
?static_cast<double>(solidBottom-zMicrometres)
:zMicrometres>solidTop
?static_cast<double>(zMicrometres-solidTop)
:-static_cast<double>(std::min(zMicrometres-solidBottom,
solidTop-zMicrometres));
const std::int64_t seam=transitionUpper->bedrock.bottomMicrometres;
const bool floatingIslandAirGap=
transitionUpper->generatorKind=="FloatingIslands"
&&transitionUpper->transitionMode=="Gradient"
&&bands.upperBedrockTopMicrometres<seam
&&zMicrometres>=bands.upperBedrockTopMicrometres
&&zMicrometres<seam;
if(!(signedDistanceMicrometres>0.0&&density<0.0f
&&!floatingIslandAirGap))
return static_cast<float>(signedDistanceMicrometres
/Owner->CoreVoxelSizeMicrons);
}
}
}
const double worldZCentimetres=static_cast<double>(Z)*GetCoreVoxelSizeCm();
const int32 strateIndex=Owner->Manager->GetStrateIndex(static_cast<float>(worldZCentimetres));
const auto* stratum=FindResolvedLayoutStratum(strateIndex);
if(!stratum)return density;
const double zMicrometres=static_cast<double>(Z)*Owner->CoreVoxelSizeMicrons;
const auto solidAt=[&](const VoxelForgeCore::ResolvedLayoutBandV2& band)
{return band.presentInCurrentField&&zMicrometres>=band.bottomMicrometres
&&zMicrometres<band.topMicrometres;};
@@ -502,77 +626,46 @@ public:
#endif
if(upper==stratum)bBedrockHandledByTransition=true;
if(lower==stratum)bCeilingHandledByTransition=true;
const auto* tileQueries=ActivePassageTileQueries;
const std::int64_t xMicrometres=static_cast<std::int64_t>(std::llround(
static_cast<double>(X)*Owner->CoreVoxelSizeMicrons));
const std::int64_t yMicrometres=static_cast<std::int64_t>(std::llround(
static_cast<double>(Y)*Owner->CoreVoxelSizeMicrons));
const auto bands=VoxelForgeCore::EvaluateResolvedLayoutTransitionBandsV1(*upper,*lower,
Owner->Seed,ResolvedLayout->strateLayoutChunkSizeMicrometres,
xMicrometres,yMicrometres);
auto resolvedBands=bands;
constexpr std::int64_t TransitionQ16=1ll<<16;
const auto* tileQueries=ActivePassageTileQueries;
const bool skipPassageFade=tileQueries&&tileQueries->matches(*this)
&&!tileQueries->mayContainTransitionPassageFade();
const std::int64_t transitionWeight=skipPassageFade?TransitionQ16
:ResolvedTransitionPassageWeightQ16(*upper,*lower,xMicrometres,yMicrometres);
#if defined(VF_L30_ENABLE_COST_COUNTERS)
if(skipPassageFade)++ThreadClassificationStats().TransitionPassageTileSkips;
#endif
if(transitionWeight<TransitionQ16)
{
const std::int64_t seam=upper->bedrock.bottomMicrometres;
const std::int64_t upperThickness=upper->bedrock.topMicrometres-seam;
const std::int64_t lowerThickness=lower->ceiling.topMicrometres
-lower->ceiling.bottomMicrometres;
const auto scaled=[&](std::int64_t value)
{return (value*transitionWeight)/TransitionQ16;};
resolvedBands.upperBedrockBottomMicrometres=seam+scaled(
bands.upperBedrockBottomMicrometres-seam);
resolvedBands.upperBedrockTopMicrometres=
resolvedBands.upperBedrockBottomMicrometres+upperThickness;
resolvedBands.lowerCeilingTopMicrometres=seam+scaled(
bands.lowerCeilingTopMicrometres-seam);
resolvedBands.lowerCeilingBottomMicrometres=
resolvedBands.lowerCeilingTopMicrometres-lowerThickness;
resolvedBands.crossingDepthMicrometres=std::max<std::int64_t>(0,
resolvedBands.lowerCeilingTopMicrometres
-resolvedBands.upperBedrockBottomMicrometres);
}
const bool upperBedrock=zMicrometres>=resolvedBands.upperBedrockBottomMicrometres
&&zMicrometres<resolvedBands.upperBedrockTopMicrometres;
const bool lowerCeiling=zMicrometres>=resolvedBands.lowerCeilingBottomMicrometres
&&zMicrometres<resolvedBands.lowerCeilingTopMicrometres;
if(!upperBedrock&&!lowerCeiling)
{
// FloatingIslands can retain native solid density above a negatively
// displaced Gradient face, creating a second surface instead of the
// resolved transition top. Keep that air-side gap open in the owner field.
const std::int64_t seam=upper->bedrock.bottomMicrometres;
if(upper->generatorKind=="FloatingIslands"
&&upper->transitionMode=="Gradient"
&&resolvedBands.upperBedrockTopMicrometres<seam
&&zMicrometres>=resolvedBands.upperBedrockTopMicrometres
&&zMicrometres<seam)
{
const double distanceVoxels=static_cast<double>(zMicrometres
-resolvedBands.upperBedrockTopMicrometres)
/std::max<std::uint32_t>(1,Owner->CoreVoxelSizeMicrons);
density=std::max(0.05f,static_cast<float>(distanceVoxels));
return true;
}
const auto resolvedBands=ResolvedTransitionBandsAtXY(*upper,*lower,
xMicrometres,yMicrometres,skipPassageFade);
// Treat the two authored bands as one continuous solid interval. Its
// exterior faces remain the lower ceiling bottom and upper bedrock top;
// measuring signed distance from those faces also clears native generator
// density on both air sides of the displaced interface.
const std::int64_t solidBottom=std::min(
resolvedBands.upperBedrockBottomMicrometres,
resolvedBands.lowerCeilingBottomMicrometres);
const std::int64_t solidTop=std::max(
resolvedBands.upperBedrockTopMicrometres,
resolvedBands.lowerCeilingTopMicrometres);
const double signedDistanceMicrometres=zMicrometres<solidBottom
?static_cast<double>(solidBottom-zMicrometres)
:zMicrometres>solidTop
?static_cast<double>(zMicrometres-solidTop)
:-static_cast<double>(std::min(zMicrometres-solidBottom,
solidTop-zMicrometres));
const std::int64_t seam=upper->bedrock.bottomMicrometres;
const bool floatingIslandAirGap=upper->generatorKind=="FloatingIslands"
&&upper->transitionMode=="Gradient"
&&resolvedBands.upperBedrockTopMicrometres<seam
&&zMicrometres>=resolvedBands.upperBedrockTopMicrometres
&&zMicrometres<seam;
// A native solid may continue beyond either authored face. Keep that
// connected rock; the FI gap is the explicit exception that must stay open.
if(signedDistanceMicrometres>0.0&&density<0.0f&&!floatingIslandAirGap)
return false;
}
const auto& band=upperBedrock?upper->bedrock:lower->ceiling;
if(upperBedrock&&upper->generatorKind=="FloatingIslands"
&&upper->transitionMode=="Gradient")
{
const double distanceVoxels=static_cast<double>(
resolvedBands.upperBedrockTopMicrometres-zMicrometres)
/std::max<std::uint32_t>(1,Owner->CoreVoxelSizeMicrons);
density=-std::max(0.05f,static_cast<float>(distanceVoxels));
}
else density=-std::max(0.05f,static_cast<float>(band.solidDensityQ16)/65536.0f);
density=static_cast<float>(signedDistanceMicrometres
/std::max<std::uint32_t>(1,Owner->CoreVoxelSizeMicrons));
return true;
};
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
"""Audit the displaced floor across the passage-mouth fade edge."""
import argparse
import math
import resource
import sys
import AuditRingTerraceL32 as ring
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("--center", nargs=2, type=float, required=True)
parser.add_argument("--lod", type=int, default=0)
parser.add_argument("--inner-radius-m", type=float, default=5.5)
parser.add_argument("--outer-radius-m", type=float, default=9.5)
parser.add_argument("--step-m", type=float, default=0.125)
parser.add_argument("--height-min-m", type=float, default=-122.5)
parser.add_argument("--height-max-m", type=float, default=-117.5)
parser.add_argument("--preferred-height-m", type=float, default=-119.5)
parser.add_argument("--highest-surface", action="store_true",
help="choose the topmost upward face inside the height window")
parser.add_argument("--plateau-min-m", type=float, default=0.5)
parser.add_argument("--step-threshold-m", type=float, default=0.1)
parser.add_argument("--normal-jump-max-deg", type=float, default=20.0)
args = parser.parse_args()
if (args.inner_radius_m < 0.0 or args.outer_radius_m <= args.inner_radius_m
or args.step_m <= 0.0):
parser.error("invalid radial interval or sample spacing")
cx, cy = args.center
preferred_height = None if args.highest_surface else args.preferred_height_m
bounds = (cx - args.outer_radius_m, cx + args.outer_radius_m,
cy - args.outer_radius_m, cy + args.outer_radius_m)
voxel_um, triangles, selected_tiles = ring.read_scene(
args.scene, args.lod, args.height_min_m, args.height_max_m, bounds)
bucket_size = max(2.0, 16.0 * voxel_um / 1_000_000.0 * (1 << args.lod))
buckets = ring.build_buckets(triangles, True, bounds, bucket_size)
count = round((args.outer_radius_m - args.inner_radius_m) / args.step_m)
lines = []
for angle_degrees in (135.0, 180.0, 225.0, 270.0, 315.0):
angle = math.radians(angle_degrees)
points = [(cx + radius * math.cos(angle), cy + radius * math.sin(angle))
for radius in (args.inner_radius_m + i * args.step_m
for i in range(count + 1))]
lines.append((f"radial-{angle_degrees:.0f}deg", points))
# Tangential sections stay outside the open mouth while crossing the outer
# fade edge on both sides of the 6.5 m center radius.
tangent_count = round(8.0 / args.step_m)
tangent_values = [-4.0 + i * args.step_m for i in range(tangent_count + 1)]
for angle_degrees in (225.0, 315.0):
angle = math.radians(angle_degrees)
normal = (math.cos(angle), math.sin(angle))
tangent = (-normal[1], normal[0])
points = [(cx + 6.5 * normal[0] + t * tangent[0],
cy + 6.5 * normal[1] + t * tangent[1])
for t in tangent_values]
lines.append((f"straight-tangent-{angle_degrees:.0f}deg", points))
failed = False
max_plateau = 0.0
max_step = 0.0
max_normal = 0.0
min_coverage = 1.0
for name, points in lines:
profile = ring.audit_profile(points, buckets, True, args.plateau_min_m,
0.0005, args.step_threshold_m, bucket_size, preferred_height)
samples = [ring.sample_surface(buckets, x, y, True, bucket_size,
preferred_height)
for x, y in points]
for index in range(1, len(samples)):
prior, current = samples[index - 1], samples[index]
if prior is None or current is None:
continue
dot = max(-1.0, min(1.0, sum(a * b for a, b in zip(prior[1], current[1]))))
delta = math.degrees(math.acos(dot))
if delta > args.normal_jump_max_deg:
px, py = points[index - 1]
x, y = points[index]
print(f"[PassageFadeNormalJump] line={name} "
f"radius_m={math.hypot(x-cx,y-cy):.3f} "
f"from_m=({px:.3f},{py:.3f},{prior[0]:.3f}) "
f"to_m=({x:.3f},{y:.3f},{current[0]:.3f}) "
f"normal_delta_deg={delta:.3f}")
coverage = profile["coverage"]
min_coverage = min(min_coverage, coverage)
plateau = max((run[0] for run in profile["plateaus"]), default=0.0)
step = max((run[1] for run in profile["plateaus"]), default=0.0)
angle = profile["max_angle"]
max_plateau = max(max_plateau, plateau)
max_step = max(max_step, step)
max_normal = max(max_normal, angle)
ok = (profile["valid"] and plateau < args.plateau_min_m
and angle <= args.normal_jump_max_deg)
failed |= not ok
print(f"[PassageFadeProfile] line={name} coverage={coverage:.3f} "
f"height_range_m={profile.get('height_range', 0.0):.6f} "
f"flat_step_runs={len(profile['plateaus'])} "
f"max_normal_delta_deg={angle:.6f} status={'PASS' if ok else 'FAIL'}")
passed = not failed and min_coverage >= 0.95
print(f"[PassageFadeRingAudit] scene={args.scene} lod={args.lod} "
f"center_m=({cx:.6f},{cy:.6f}) mouth_radius_m=4.500 "
f"fade_m=5.500..7.500 radial_m={args.inner_radius_m:.3f}.."
f"{args.outer_radius_m:.3f} lines={len(lines)} selected_tiles={selected_tiles} "
f"coverage_min={min_coverage:.3f} longest_flat_run_m={max_plateau:.6f} "
f"following_step_m={max_step:.6f} max_normal_delta_deg={max_normal:.6f} "
f"thresholds=(coverage>=0.950,plateau<0.500,step>=0.100,normal<=20.000) "
f"status={'PASS' if passed else 'FAIL'}")
print(f"[PassageFadeRSS] peak_rss_kib={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
raise SystemExit(0 if passed else 1)
if __name__ == "__main__":
main()
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
"""Audit several bounded face windows and combine their height range."""
import argparse
import gc
import importlib.util
from pathlib import Path
import resource
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("--surface", choices=("floor", "ceiling"), required=True)
parser.add_argument("--center", nargs=2, type=float, action="append", required=True,
help="repeat for each bounded local ring")
parser.add_argument("--radius", type=float, default=8.0)
parser.add_argument("--lod", type=int, required=True)
parser.add_argument("--height-min-m", type=float, required=True)
parser.add_argument("--height-max-m", type=float, required=True)
parser.add_argument("--preferred-height-m", type=float,
help="lock overlapping-face selection near this expected surface height")
parser.add_argument("--step", type=float, default=0.125)
parser.add_argument("--plateau-min-m", type=float, default=0.5)
parser.add_argument("--plateau-epsilon-m", type=float, default=0.0005)
parser.add_argument("--step-threshold-m", type=float, default=0.1)
parser.add_argument("--normal-jump-max-deg", type=float, default=20.0)
parser.add_argument("--amplitude-min-m", type=float, default=3.0)
parser.add_argument("--min-radial-lines-per-center", type=int, default=4)
parser.add_argument("--min-straight-lines-per-center", type=int, default=2)
args = parser.parse_args()
audit_path = Path(__file__).with_name("AuditRingTerraceL32.py")
spec = importlib.util.spec_from_file_location("ring_audit_l32_set", audit_path)
audit = importlib.util.module_from_spec(spec)
spec.loader.exec_module(audit)
upward = args.surface == "floor"
preferred_height = args.preferred_height_m
if preferred_height is None:
preferred_height = args.height_max_m if upward else args.height_min_m
all_ranges = []
overall_max_normal = 0.0
overall_max_plateau = 0.0
overall_max_step = 0.0
overall_min_coverage = 1.0
total_valid_lines = 0
total_lines = 0
failed = False
for center in args.center:
bounds = (center[0] - args.radius, center[0] + args.radius,
center[1] - args.radius, center[1] + args.radius)
voxel_um, triangles, selected_tiles = audit.read_scene(
args.scene, args.lod, args.height_min_m, args.height_max_m, bounds)
max_lod = max((triangle[0] for triangle in triangles), default=0)
cell_size = max(2.0, 16.0 * voxel_um / 1_000_000.0 * (1 << max_lod))
buckets = audit.build_buckets(triangles, upward, bounds, cell_size)
results = []
for name, points in audit.make_lines(*center, args.radius, args.step):
result = audit.audit_profile(points, buckets, upward,
args.plateau_min_m, args.plateau_epsilon_m,
args.step_threshold_m, cell_size, preferred_height)
results.append((name, points, result))
radial = [row for row in results if row[0].startswith("radial-") and row[2]["valid"]]
straight = [row for row in results if row[0].startswith("straight-") and row[2]["valid"]]
valid = [row for row in results if row[2]["valid"]]
local_min = min((row[2]["height_min"] for row in valid), default=float("inf"))
local_max = max((row[2]["height_max"] for row in valid), default=float("-inf"))
local_amplitude = local_max - local_min
local_plateau = max((run[0] for row in valid for run in row[2]["plateaus"]), default=0.0)
local_step = max((run[1] for row in valid for run in row[2]["plateaus"]), default=0.0)
local_normal = max((row[2]["max_angle"] for row in valid), default=float("inf"))
local_coverage = min((row[2]["coverage"] for row in results), default=0.0)
local_ok = (len(valid) == len(results)
and len(radial) >= args.min_radial_lines_per_center
and len(straight) >= args.min_straight_lines_per_center
and local_plateau < args.plateau_min_m
and local_normal <= args.normal_jump_max_deg)
all_ranges.extend((row[2]["height_min"], row[2]["height_max"])
for row in valid)
overall_max_normal = max(overall_max_normal, local_normal)
overall_max_plateau = max(overall_max_plateau, local_plateau)
overall_max_step = max(overall_max_step, local_step)
overall_min_coverage = min(overall_min_coverage, local_coverage)
total_valid_lines += len(valid)
total_lines += len(results)
print(f"[RingSetWindow] center_m=({center[0]:.3f},{center[1]:.3f}) "
f"radius_m={args.radius:.3f} tiles={selected_tiles} lines={len(valid)}/"
f"{len(results)} radial={len(radial)} straight={len(straight)} "
f"coverage_min={local_coverage:.3f} height_m={local_min:.6f}.."
f"{local_max:.6f} amplitude_m={local_amplitude:.6f} "
f"longest_flat_m={local_plateau:.6f} following_step_m={local_step:.6f} "
f"max_normal_delta_deg={local_normal:.6f} "
f"status={'PASS' if local_ok else 'FAIL'}")
for name, _, result in results:
print(f"[RingSetProfile] center_m=({center[0]:.3f},{center[1]:.3f}) "
f"line={name} coverage={result['coverage']:.3f} "
f"range_m={result.get('height_range', 0.0):.6f} "
f"flat_step_runs={len(result['plateaus'])} "
f"max_normal_delta_deg={result['max_angle']:.6f}")
failed |= not local_ok
del triangles, buckets, results, radial, straight, valid
gc.collect()
if all_ranges:
sampled_min = min(value[0] for value in all_ranges)
sampled_max = max(value[1] for value in all_ranges)
amplitude = sampled_max - sampled_min
else:
sampled_min = sampled_max = amplitude = 0.0
passed = not failed and amplitude >= args.amplitude_min_m
print(f"[RingSetAudit] scene={args.scene} surface={args.surface} lod={args.lod} "
f"windows={len(args.center)} radius_m={args.radius:.3f} "
f"height_window_m={args.height_min_m:.3f}..{args.height_max_m:.3f} "
f"sampled_height_m={sampled_min:.6f}..{sampled_max:.6f} "
f"amplitude_range_m={amplitude:.6f} lines={total_valid_lines}/{total_lines} "
f"coverage_min={overall_min_coverage:.3f} "
f"longest_flat_run_m={overall_max_plateau:.6f} "
f"max_step_m={overall_max_step:.6f} "
f"max_normal_delta_deg={overall_max_normal:.6f} "
f"thresholds=(amplitude>={args.amplitude_min_m:.3f},"
f"plateau<{args.plateau_min_m:.3f},"
f"normal<={args.normal_jump_max_deg:.3f}) "
f"status={'PASS' if passed else 'FAIL'}")
print(f"[RingSetRSS] peak_rss_kib={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
raise SystemExit(0 if passed else 1)
if __name__ == "__main__":
main()
@@ -0,0 +1,265 @@
#!/usr/bin/env python3
"""Fail on contour terraces, stepped profiles, or insufficient Gradient amplitude."""
import argparse
import array
import math
import resource
import struct
import sys
from collections import defaultdict
def read_scene(path, wanted_lod, height_min, height_max, bounds):
triangles = []
selected_tiles = 0
x_min, x_max, y_min, y_max = bounds
with open(path, "rb") as stream:
if stream.read(8) != b"VFMSH001":
raise SystemExit(f"{path}: invalid mesh scene header")
version, voxel_um, tile_count = struct.unpack("<3I", stream.read(12))
stream.read(40)
if version != 1 or tile_count > 100000:
raise SystemExit(f"{path}: unsupported mesh scene")
for _ in range(tile_count):
key = struct.unpack("<4i", stream.read(16))
surface_count, _, vertex_count, index_count, mask_count = struct.unpack(
"<5I", stream.read(20))
tile_extent = 32.0 * (1 << key[3]) * voxel_um / 1_000_000.0
tile_x0, tile_y0 = key[0] * tile_extent, key[1] * tile_extent
tile_z0 = key[2] * tile_extent
if (wanted_lod is not None and key[3] != wanted_lod) or \
tile_x0 > x_max or tile_x0 + tile_extent < x_min or \
tile_y0 > y_max or tile_y0 + tile_extent < y_min or \
tile_z0 > height_max or tile_z0 + tile_extent < height_min:
stream.seek(vertex_count * 24 + index_count * 4 + mask_count, 1)
continue
selected_tiles += 1
positions = array.array("f")
positions.frombytes(stream.read(vertex_count * 12))
normals = array.array("f")
normals.frombytes(stream.read(vertex_count * 12))
indices = array.array("I")
indices.frombytes(stream.read(index_count * 4))
masks = stream.read(mask_count)
if sys.byteorder != "little":
positions.byteswap()
normals.byteswap()
indices.byteswap()
for offset in range(0, index_count, 3):
if masks and masks[offset // 3]:
continue
ids = indices[offset:offset + 3]
if max(ids) >= surface_count:
continue
verts = []
for index in ids:
p, n = index * 3, index * 3
verts.append(((positions[p], positions[p + 1], positions[p + 2]),
(normals[n], normals[n + 1], normals[n + 2])))
average_nz = sum(vertex[1][2] for vertex in verts) / 3.0
z_values = [vertex[0][2] for vertex in verts]
# Select the requested surface branch by its face height. An
# overlap or centroid test admits a giant coarse triangle that
# merely clips this window and can belong to the neighboring face.
mean_z = sum(z_values) / 3.0
vertex_margin = voxel_um / 1_000_000.0 * 0.5
if (mean_z < height_min or mean_z > height_max or
min(z_values) < height_min - vertex_margin or
max(z_values) > height_max + vertex_margin):
continue
if (max(vertex[0][0] for vertex in verts) < x_min or
min(vertex[0][0] for vertex in verts) > x_max or
max(vertex[0][1] for vertex in verts) < y_min or
min(vertex[0][1] for vertex in verts) > y_max):
continue
triangles.append((key[3], average_nz, tuple(verts)))
return voxel_um, triangles, selected_tiles
def build_buckets(triangles, upward, bounds, cell_size=2.0):
buckets = defaultdict(list)
x_min, x_max, y_min, y_max = bounds
for triangle in triangles:
_, average_nz, verts = triangle
if (upward and average_nz < 0.35) or (not upward and average_nz > -0.35):
continue
xs = [v[0][0] for v in verts]
ys = [v[0][1] for v in verts]
x0 = max(math.floor(min(xs) / cell_size), math.floor(x_min / cell_size))
x1 = min(math.floor(max(xs) / cell_size), math.floor(x_max / cell_size))
y0 = max(math.floor(min(ys) / cell_size), math.floor(y_min / cell_size))
y1 = min(math.floor(max(ys) / cell_size), math.floor(y_max / cell_size))
for iy in range(y0, y1 + 1):
for ix in range(x0, x1 + 1):
buckets[(ix, iy)].append(verts)
return buckets
def sample_surface(buckets, x, y, upward, cell_size, preferred_height=None):
found = None
for verts in buckets.get((math.floor(x / cell_size), math.floor(y / cell_size)), ()):
(a, na), (b, nb), (c, nc) = verts
denominator = (b[1] - c[1]) * (a[0] - c[0]) + (c[0] - b[0]) * (a[1] - c[1])
if abs(denominator) < 1.0e-12:
continue
u = ((b[1] - c[1]) * (x - c[0]) + (c[0] - b[0]) * (y - c[1])) / denominator
v = ((c[1] - a[1]) * (x - c[0]) + (a[0] - c[0]) * (y - c[1])) / denominator
w = 1.0 - u - v
if min(u, v, w) < -1.0e-6:
continue
z = u * a[2] + v * b[2] + w * c[2]
normal = tuple(u * na[axis] + v * nb[axis] + w * nc[axis] for axis in range(3))
length = math.sqrt(sum(value * value for value in normal))
if length < 1.0e-9:
continue
normal = tuple(value / length for value in normal)
if (normal[2] > 0) != upward:
continue
if found is None or (abs(z - preferred_height) < abs(found[0] - preferred_height)
if preferred_height is not None else z > found[0]):
found = (z, normal)
return found
def make_lines(cx, cy, radius, step):
lines = []
for index in range(8):
angle = index * math.tau / 8.0
count = round(radius / step)
points = [(cx + i * step * math.cos(angle), cy + i * step * math.sin(angle))
for i in range(count + 1)]
lines.append((f"radial-{index}", points))
count = round(2.0 * radius / step)
t_values = [-radius + i * step for i in range(count + 1)]
for name, points in (
("straight-x", [(cx + t, cy) for t in t_values]),
("straight-y", [(cx, cy + t) for t in t_values]),
("straight-diagonal", [(cx + t / math.sqrt(2.0), cy + t / math.sqrt(2.0))
for t in t_values]),
):
lines.append((name, points))
return lines
def audit_profile(points, buckets, upward, plateau_min_m, plateau_epsilon_m,
step_threshold_m, cell_size, preferred_height=None):
samples = [sample_surface(buckets, x, y, upward, cell_size, preferred_height)
for x, y in points]
valid = [(index, value) for index, value in enumerate(samples) if value is not None]
if len(valid) < max(8, len(points) * 0.75):
return {"coverage": len(valid) / len(points), "plateaus": [], "max_angle": math.inf,
"height_range": 0.0, "valid": False}
heights = [value[0] for _, value in valid]
plateau_runs = []
run_start = valid[0][0]
run_start_height = valid[0][1][0]
sample_spacing = math.hypot(points[1][0] - points[0][0],
points[1][1] - points[0][1])
for cursor in range(1, len(valid)):
prior_index, prior = valid[cursor - 1]
index, current = valid[cursor]
if index != prior_index + 1:
run_start = index
run_start_height = current[0]
continue
if abs(current[0] - run_start_height) <= plateau_epsilon_m:
continue
run_length = (prior_index - run_start + 1) * sample_spacing
if run_length >= plateau_min_m and abs(current[0] - prior[0]) >= step_threshold_m:
plateau_runs.append((run_length, abs(current[0] - prior[0]), run_start,
prior_index, index, prior[0], current[0]))
run_start = index
run_start_height = current[0]
max_angle = 0.0
for cursor in range(1, len(valid)):
prior_index, prior = valid[cursor - 1]
index, current = valid[cursor]
if index != prior_index + 1:
continue
dot = max(-1.0, min(1.0, sum(a * b for a, b in zip(prior[1], current[1]))))
max_angle = max(max_angle, math.degrees(math.acos(dot)))
return {"coverage": len(valid) / len(points), "plateaus": plateau_runs,
"max_angle": max_angle, "height_range": max(heights) - min(heights),
"height_min": min(heights), "height_max": max(heights),
"valid": True}
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("--surface", choices=("floor", "ceiling"), default="floor")
parser.add_argument("--center", nargs=2, type=float, default=(64.0, -32.0))
parser.add_argument("--radius", type=float, default=16.0)
parser.add_argument("--lod", required=True,
help="audit one LOD (0..8) or the streamed composite (`all`)")
parser.add_argument("--step", type=float, default=0.125)
parser.add_argument("--height-min-m", type=float, default=-130.0)
parser.add_argument("--height-max-m", type=float, default=-110.0)
parser.add_argument("--plateau-min-m", type=float, default=0.5)
parser.add_argument("--plateau-epsilon-m", type=float, default=0.0005)
parser.add_argument("--step-threshold-m", type=float, default=0.1)
parser.add_argument("--normal-jump-max-deg", type=float, default=20.0)
parser.add_argument("--amplitude-min-m", type=float, default=3.0)
args = parser.parse_args()
try:
wanted_lod = None if args.lod == "all" else int(args.lod)
except ValueError:
parser.error("--lod must be 0..8 or all")
if wanted_lod is not None and not 0 <= wanted_lod <= 8:
parser.error("--lod must be 0..8 or all")
bounds = (args.center[0] - args.radius, args.center[0] + args.radius,
args.center[1] - args.radius, args.center[1] + args.radius)
voxel_um, triangles, selected_tiles = read_scene(args.scene, wanted_lod,
args.height_min_m, args.height_max_m, bounds)
upward = args.surface == "floor"
max_lod = max((triangle[0] for triangle in triangles), default=0)
cell_size = max(2.0, 16.0 * voxel_um / 1_000_000.0 * (1 << max_lod))
buckets = build_buckets(triangles, upward, bounds, cell_size)
results = []
# The requested face is the outer boundary of its authored band: highest Z
# for a floor, lowest Z for a ceiling. Selecting the band midpoint can jump
# between two overlapping downward/upward sheets at a cave edge.
preferred_height = args.height_max_m if upward else args.height_min_m
for name, points in make_lines(*args.center, args.radius, args.step):
results.append((name, points, audit_profile(points, buckets, upward,
args.plateau_min_m, args.plateau_epsilon_m,
args.step_threshold_m, cell_size, preferred_height)))
valid = [result for _, _, result in results if result["valid"]]
if not valid:
raise SystemExit("no sampled surface profiles; check scene, center, orientation and LOD")
amplitude = max(result["height_max"] for result in valid) - min(
result["height_min"] for result in valid)
sampled_min = min(result["height_min"] for result in valid)
sampled_max = max(result["height_max"] for result in valid)
longest_plateau = max((run[0] for result in valid for run in result["plateaus"]),
default=0.0)
largest_step = max((run[1] for result in valid for run in result["plateaus"]),
default=0.0)
max_normal_jump = max(result["max_angle"] for result in valid)
min_coverage = min(result["coverage"] for _, _, result in results)
passed = (amplitude >= args.amplitude_min_m and longest_plateau < args.plateau_min_m
and max_normal_jump <= args.normal_jump_max_deg and min_coverage >= 0.75)
print(f"[RingTerraceAudit] scene={args.scene} surface={args.surface} lod={args.lod} "
f"max_lod={max_lod} "
f"height_window_m={args.height_min_m:.3f}..{args.height_max_m:.3f} "
f"voxel_um={voxel_um} triangles={len(triangles)} lines={len(results)} "
f"selected_tiles={selected_tiles} bucket_cell_m={cell_size:.3f} "
f"coverage_min={min_coverage:.3f} sampled_height_m={sampled_min:.6f}.."
f"{sampled_max:.6f} amplitude_range_m={amplitude:.6f} "
f"longest_flat_run_m={longest_plateau:.6f} following_step_m={largest_step:.6f} "
f"max_normal_delta_deg={max_normal_jump:.6f} status={'PASS' if passed else 'FAIL'}")
for name, points, result in results:
print(f"[RingTerraceProfile] line={name} coverage={result['coverage']:.3f} "
f"range_m={result['height_range']:.6f} flat_step_runs={len(result['plateaus'])} "
f"max_normal_delta_deg={result['max_angle']:.6f}")
for run in result["plateaus"]:
print(f"[RingTerraceViolation] line={name} flat_start_m=({points[run[2]][0]:.3f},"
f"{points[run[2]][1]:.3f}) flat_run_m={run[0]:.6f} "
f"step_m={run[1]:.6f} from_height_m={run[5]:.6f} "
f"to_height_m={run[6]:.6f}")
print(f"[RingTerraceRSS] peak_rss_kib={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
raise SystemExit(0 if passed else 1)
if __name__ == "__main__":
main()
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Encode the near/far tint-on/off L32 captures as compact JPEGs."""
import resource
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
SOURCE = ROOT / "Saved/Linux/l32"
DEST = Path(__file__).resolve().parent / "captures"
DEST.mkdir(parents=True, exist_ok=True)
captures = {
"fi-floor-near-tint-on": "cap-final-fi-near-on",
"fi-floor-near-tint-off": "cap-final-fi-near-off",
"fi-floor-far-tint-on": "cap-final-fi-far-on",
"fi-floor-far-tint-off": "cap-final-fi-far-off",
"sw-ceiling-near-tint-on": "cap-final-sw-near-on",
"sw-ceiling-near-tint-off": "cap-final-sw-near-off",
"sw-ceiling-far-tint-on": "cap-final-sw-far-on",
"sw-ceiling-far-tint-off": "cap-final-sw-far-off",
}
failed = False
for output_name, input_name in captures.items():
source = SOURCE / f"{input_name}.png"
destination = DEST / f"{output_name}.jpg"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "ffmpeg",
"-y", "-hide_banner", "-loglevel", "error", "-i", str(source),
"-frames:v", "1", "-q:v", "4", str(destination),
]
result = subprocess.run(command, check=False)
size = destination.stat().st_size if destination.exists() else 0
ok = source.exists() and result.returncode == 0 and size <= 300_000
failed |= not ok
print(f"[L32CaptureJPEG] source={source.name} output={destination.name} "
f"bytes={size} status={'PASS' if ok else 'FAIL'}", flush=True)
print(f"[L32CaptureJPEG] peak_rss_kib="
f"{resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}", flush=True)
raise SystemExit(1 if failed else 0)
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
"""Copy only tiles for one LOD and spatial window from a VFMSH scene."""
import argparse
import resource
import shutil
import struct
def main():
parser = argparse.ArgumentParser()
parser.add_argument("source")
parser.add_argument("destination")
parser.add_argument("--lod", type=int, required=True)
parser.add_argument("--bounds", nargs=6, type=float, required=True,
metavar=("XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"))
args = parser.parse_args()
if not 0 <= args.lod <= 8:
parser.error("--lod must be between 0 and 8")
x_min, x_max, y_min, y_max, z_min, z_max = args.bounds
if x_max <= x_min or y_max <= y_min or z_max <= z_min:
parser.error("bounds must have positive extents")
selected = []
with open(args.source, "rb") as src:
prefix = src.read(60)
if len(prefix) != 60 or prefix[:8] != b"VFMSH001":
raise SystemExit("source has an invalid VFMSH001 header")
version, voxel_um, tile_count = struct.unpack_from("<3I", prefix, 8)
if version != 1 or voxel_um == 0 or tile_count > 1_000_000:
raise SystemExit("source has an unsupported scene header")
for _ in range(tile_count):
header = src.read(36)
if len(header) != 36:
raise SystemExit("truncated tile header")
key = struct.unpack_from("<4i", header)
_, _, vertex_count, index_count, mask_count = struct.unpack_from("<5I", header, 16)
payload_offset = src.tell()
payload_size = vertex_count * 24 + index_count * 4 + mask_count
extent = 32.0 * (1 << key[3]) * voxel_um / 1_000_000.0
tx0, ty0, tz0 = key[0] * extent, key[1] * extent, key[2] * extent
intersects = (key[3] == args.lod and tx0 <= x_max and tx0 + extent >= x_min
and ty0 <= y_max and ty0 + extent >= y_min
and tz0 <= z_max and tz0 + extent >= z_min)
if intersects:
selected.append((header, payload_offset, payload_size))
src.seek(payload_size, 1)
if src.read(1):
raise SystemExit("source scene has trailing bytes")
if not selected:
raise SystemExit("no tiles matched the requested LOD and bounds")
with open(args.source, "rb") as src, open(args.destination, "wb") as dst:
prefix = bytearray(src.read(60))
struct.pack_into("<I", prefix, 16, len(selected))
dst.write(prefix)
for header, payload_offset, payload_size in selected:
dst.write(header)
src.seek(payload_offset)
remaining = payload_size
while remaining:
block = src.read(min(1 << 20, remaining))
if not block:
raise SystemExit("truncated tile payload")
dst.write(block)
remaining -= len(block)
print(f"[VFMeshLodWindow] source={args.source} lod={args.lod} "
f"selected_tiles={len(selected)} output={args.destination} "
f"output_bytes={__import__('os').path.getsize(args.destination)} "
f"peak_rss_kib={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss} status=PASS")
if __name__ == "__main__":
main()
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Stream VFMSH tiles and retain a focused, near-horizontal surface patch."""
import argparse
import math
import resource
import struct
def main():
parser = argparse.ArgumentParser()
parser.add_argument("source")
parser.add_argument("destination")
parser.add_argument("--center", nargs=2, type=float, required=True, metavar=("X", "Y"))
parser.add_argument("--radius-m", type=float, required=True)
parser.add_argument("--height-m", nargs=2, type=float, required=True, metavar=("MIN", "MAX"))
parser.add_argument("--min-abs-normal-z", type=float, default=0.7)
args = parser.parse_args()
if args.radius_m <= 0 or args.height_m[1] <= args.height_m[0]:
parser.error("radius and height interval must be positive")
if not 0.0 <= args.min_abs_normal_z <= 1.0:
parser.error("--min-abs-normal-z must be in [0,1]")
cx, cy = args.center
r2 = args.radius_m * args.radius_m
zmin, zmax = args.height_m
input_tiles = kept_tiles = kept_triangles = 0
with open(args.source, "rb") as src, open(args.destination, "wb+") as dst:
prefix = bytearray(src.read(60))
if len(prefix) != 60 or prefix[:8] != b"VFMSH001":
raise SystemExit("source has an invalid VFMSH001 header")
version, voxel_um, tile_count = struct.unpack_from("<3I", prefix, 8)
if version != 1 or voxel_um == 0 or tile_count > 1_000_000:
raise SystemExit("source has an unsupported scene header")
struct.pack_into("<I", prefix, 16, 0)
dst.write(prefix)
for _ in range(tile_count):
header = src.read(36)
if len(header) != 36:
raise SystemExit("truncated tile header")
key = struct.unpack_from("<4i", header)
surface_vertices, skirt_count, vertex_count, index_count, mask_count = \
struct.unpack_from("<5I", header, 16)
if vertex_count > 2_000_000 or index_count > 12_000_000:
raise SystemExit("tile exceeds the focused patch memory limit")
vertex_bytes = src.read(vertex_count * 24)
index_bytes = src.read(index_count * 4)
masks = src.read(mask_count)
if (len(vertex_bytes) != vertex_count * 24
or len(index_bytes) != index_count * 4 or len(masks) != mask_count):
raise SystemExit("truncated tile payload")
input_tiles += 1
positions = list(struct.iter_unpack("<3f", vertex_bytes[:vertex_count * 12]))
indices = struct.unpack(f"<{index_count}I", index_bytes) if index_count else ()
face_masks = masks if mask_count else bytes(index_count // 12)
filtered = []
for tri in range(index_count // 3):
i0, i1, i2 = indices[tri * 3:tri * 3 + 3]
if i0 >= vertex_count or i1 >= vertex_count or i2 >= vertex_count:
raise SystemExit("tile index points outside its vertex array")
if face_masks[tri] != 0:
continue
p0, p1, p2 = positions[i0], positions[i1], positions[i2]
mx = (p0[0] + p1[0] + p2[0]) / 3.0
my = (p0[1] + p1[1] + p2[1]) / 3.0
mz = (p0[2] + p1[2] + p2[2]) / 3.0
if (mx - cx) ** 2 + (my - cy) ** 2 > r2 or not zmin <= mz <= zmax:
continue
ab = (p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2])
ac = (p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2])
nz = ab[0] * ac[1] - ab[1] * ac[0]
length = math.sqrt((ab[1] * ac[2] - ab[2] * ac[1]) ** 2
+ (ab[2] * ac[0] - ab[0] * ac[2]) ** 2 + nz * nz)
if length == 0 or abs(nz) / length < args.min_abs_normal_z:
continue
filtered.extend((i0, i1, i2))
if not filtered:
continue
tile_header = struct.pack("<4i5I", *key, surface_vertices, 0,
vertex_count, len(filtered), 0)
dst.write(tile_header)
dst.write(vertex_bytes)
dst.write(struct.pack(f"<{len(filtered)}I", *filtered))
kept_tiles += 1
kept_triangles += len(filtered) // 3
dst.seek(16)
dst.write(struct.pack("<I", kept_tiles))
if kept_tiles == 0:
raise SystemExit("no surface triangles matched the requested patch")
print(f"[VFMeshSurfacePatch] source={args.source} input_tiles={input_tiles} "
f"tiles={kept_tiles} triangles={kept_triangles} center=({cx:.3f},{cy:.3f}) "
f"radius_m={args.radius_m:.3f} height_m={zmin:.3f}..{zmax:.3f} "
f"peak_rss_kib={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss} status=PASS")
if __name__ == "__main__":
main()
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
"""Find VFMSH tiles intersecting a small region without reading mesh payloads."""
import argparse
import glob
import os
import resource
import struct
def main():
parser = argparse.ArgumentParser()
parser.add_argument("directory")
parser.add_argument("--lod", type=int, required=True)
parser.add_argument("--bounds", nargs=6, type=float, required=True,
metavar=("XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"))
args = parser.parse_args()
xmin, xmax, ymin, ymax, zmin, zmax = args.bounds
matches = 0
for path in sorted(glob.glob(os.path.join(args.directory, "*.vfmesh"))):
with open(path, "rb") as stream:
if stream.read(8) != b"VFMSH001":
continue
version, voxel_um, tile_count = struct.unpack("<3I", stream.read(12))
stream.seek(40, 1)
if version != 1:
continue
for _ in range(tile_count):
key = struct.unpack("<4i", stream.read(16))
surface_count, _, vertex_count, index_count, mask_count = struct.unpack(
"<5I", stream.read(20))
extent = 32.0 * (1 << key[3]) * voxel_um / 1_000_000.0
x0, y0, z0 = (key[axis] * extent for axis in range(3))
intersects = (key[3] == args.lod and index_count > 0
and x0 <= xmax and x0 + extent >= xmin
and y0 <= ymax and y0 + extent >= ymin
and z0 <= zmax and z0 + extent >= zmin)
if intersects:
matches += 1
print(f"[VFMeshTileWindow] scene={os.path.basename(path)} key={key} "
f"vertices={vertex_count} indices={index_count} "
f"extent_m={extent:.3f}")
stream.seek(vertex_count * 24 + index_count * 4 + mask_count, 1)
print(f"[VFMeshTileWindowSummary] matching_tiles={matches} "
f"peak_rss_kib={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
if __name__ == "__main__":
main()
@@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""Stream selected-LOD tiles and find face windows that pass the ring audit."""
import argparse
import array
import importlib.util
from pathlib import Path
import resource
import struct
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("--lod", type=int, required=True)
parser.add_argument("--surface", choices=("floor", "ceiling"), required=True)
parser.add_argument("--height-min-m", type=float, required=True)
parser.add_argument("--height-max-m", type=float, required=True)
parser.add_argument("--preferred-height-m", type=float,
help="lock overlapping-face selection near this expected surface height")
parser.add_argument("--step-m", type=float, default=0.5)
parser.add_argument("--tile-key", nargs=3, type=int,
help="audit only this tile's x/y/z key (LOD is supplied separately)")
args = parser.parse_args()
audit_path = Path(__file__).with_name("AuditRingTerraceL32.py")
spec = importlib.util.spec_from_file_location("ring_audit_l32", audit_path)
audit = importlib.util.module_from_spec(spec)
spec.loader.exec_module(audit)
want_up = args.surface == "floor"
candidates = []
with open(args.scene, "rb") as stream:
if stream.read(8) != b"VFMSH001":
raise SystemExit("invalid VFMSH001 scene")
version, voxel_um, tile_count = struct.unpack("<3I", stream.read(12))
stream.seek(40, 1)
if version != 1:
raise SystemExit("unsupported mesh scene")
for _ in range(tile_count):
header = stream.read(36)
key = struct.unpack("<4i", header[:16])
surface_count, _, vertex_count, index_count, mask_count = struct.unpack(
"<5I", header[16:])
payload = vertex_count * 24 + index_count * 4 + mask_count
if key[3] != args.lod or (args.tile_key and tuple(key[:3]) != tuple(args.tile_key)):
stream.seek(payload, 1)
continue
positions = array.array("f")
positions.frombytes(stream.read(vertex_count * 12))
normals = array.array("f")
normals.frombytes(stream.read(vertex_count * 12))
indices = array.array("I")
indices.frombytes(stream.read(index_count * 4))
masks = stream.read(mask_count)
if sys.byteorder != "little":
positions.byteswap()
normals.byteswap()
indices.byteswap()
triangles = []
vertex_margin = voxel_um / 1_000_000.0 * 0.5
for offset in range(0, index_count, 3):
if masks and masks[offset // 3]:
continue
ids = indices[offset:offset + 3]
if max(ids) >= surface_count:
continue
verts = []
for index in ids:
p = index * 3
verts.append(((positions[p], positions[p + 1], positions[p + 2]),
(normals[p], normals[p + 1], normals[p + 2])))
average_nz = sum(vertex[1][2] for vertex in verts) / 3.0
if (want_up and average_nz < 0.35) or (not want_up and average_nz > -0.35):
continue
z_values = [vertex[0][2] for vertex in verts]
mean_z = sum(z_values) / 3.0
if (mean_z < args.height_min_m or mean_z > args.height_max_m or
min(z_values) < args.height_min_m - vertex_margin or
max(z_values) > args.height_max_m + vertex_margin):
continue
triangles.append((key[3], average_nz, tuple(verts)))
if not triangles:
continue
extent = 32.0 * (1 << key[3]) * voxel_um / 1_000_000.0
cx, cy = (key[0] + 0.5) * extent, (key[1] + 0.5) * extent
radius = extent * 0.5
bounds = (cx - radius, cx + radius, cy - radius, cy + radius)
cell_size = max(2.0, 16.0 * voxel_um / 1_000_000.0 * (1 << key[3]))
buckets = audit.build_buckets(triangles, want_up, bounds, cell_size)
profiles = []
preferred_height = args.preferred_height_m
if preferred_height is None:
preferred_height = args.height_max_m if want_up else args.height_min_m
for _, points in audit.make_lines(cx, cy, radius, args.step_m):
profiles.append(audit.audit_profile(points, buckets, want_up,
0.5, 0.0005, 0.1, cell_size, preferred_height))
valid = [profile for profile in profiles if profile["valid"]]
coverage = min(profile["coverage"] for profile in profiles)
amplitude = max((profile["height_max"] for profile in valid), default=0.0) - \
min((profile["height_min"] for profile in valid), default=0.0)
longest = max((run[0] for profile in valid for run in profile["plateaus"]),
default=0.0)
max_normal = max((profile["max_angle"] for profile in valid), default=float("inf"))
passed = (len(valid) == len(profiles) and coverage >= 0.75 and amplitude >= 3.0
and longest < 0.5 and max_normal <= 20.0)
candidates.append((passed, amplitude, -max_normal, key, cx, cy,
len(triangles), coverage, longest, max_normal))
stream.seek(payload - (vertex_count * 24 + index_count * 4 + mask_count), 1)
candidates.sort(reverse=True, key=lambda item: (item[0], item[1], item[2]))
print(f"[RingWindowSearch] lod={args.lod} surface={args.surface} tiles={len(candidates)} "
f"height_window_m={args.height_min_m:.3f}..{args.height_max_m:.3f} "
f"step_m={args.step_m:.3f}")
for passed, amplitude, neg_normal, key, cx, cy, count, coverage, longest, normal in candidates[:40]:
print(f"[RingWindowCandidate] status={'PASS' if passed else 'FAIL'} key={key} "
f"center_m=({cx:.3f},{cy:.3f}) triangles={count} coverage={coverage:.3f} "
f"amplitude_m={amplitude:.6f} longest_flat_m={longest:.6f} "
f"normal_jump_deg={normal:.6f}")
print(f"[RingWindowRSS] peak_rss_kib="
f"{resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
if __name__ == "__main__":
main()
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
"""Find open SurfaceWorld columns below the resolved transition ceiling."""
import argparse
import csv
import subprocess
from pathlib import Path
def main():
parser = argparse.ArgumentParser()
parser.add_argument("probe")
parser.add_argument("owner")
parser.add_argument("output")
parser.add_argument("--z", type=float, default=-130.0)
parser.add_argument("--minimum", type=float, default=-96.0)
parser.add_argument("--maximum", type=float, default=96.0)
parser.add_argument("--spacing", type=float, default=16.0)
args = parser.parse_args()
probe = str(Path(args.probe).resolve())
owner = str(Path(args.owner).resolve())
output = Path(args.output)
output.parent.mkdir(parents=True, exist_ok=True)
rows = []
count = round((args.maximum - args.minimum) / args.spacing)
for iy in range(count + 1):
y = args.minimum + iy * args.spacing
for ix in range(count + 1):
x = args.minimum + ix * args.spacing
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
probe, owner, "surface-world", str(x), str(y),
str(args.z - 2.0), str(args.z + 2.0), "0.25"]
result = subprocess.run(command, capture_output=True, text=True, timeout=1800,
check=False)
samples = [line for line in result.stdout.splitlines()
if line.startswith(f"{args.z:.6f},")]
density = float(samples[0].split(",")[1]) if result.returncode == 0 and samples else float("nan")
rows.append((x, y, args.z, density, result.returncode))
print(f"[SurfaceWorldAirScan] x_m={x:.1f} y_m={y:.1f} z_m={args.z:.2f} "
f"density_vox={density:.6f} exit={result.returncode}", flush=True)
with output.open("w", newline="", encoding="utf-8") as stream:
writer = csv.writer(stream)
writer.writerow(("x_m", "y_m", "z_m", "density_vox", "exit_code"))
writer.writerows(rows)
open_samples = [row for row in rows if row[3] > 0.0]
print(f"[SurfaceWorldAirScanSummary] samples={len(rows)} open={len(open_samples)} "
f"output={output} status={'PASS' if open_samples else 'FAIL'}")
return 0 if open_samples else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,118 @@
#include "Json.h"
#include "OwnerWorldLoader.h"
#include "StandaloneCoreScheduler.h"
#include "WorldAssemblyPrototype.h"
#include "StandaloneSnapshotAdapter.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iterator>
#include <memory>
#include <string>
int main(int argc,char** argv)
{
if(argc!=8)
{
std::fprintf(stderr,"usage: %s owner.json surface-world|floating-islands x_m y_m zmin_m zmax_m step_m\n",argv[0]);
return 2;
}
const std::string recipe=argv[2];
if(recipe!="surface-world"&&recipe!="floating-islands")return 2;
const double x=std::strtod(argv[3],nullptr),y=std::strtod(argv[4],nullptr);
const double zmin=std::strtod(argv[5],nullptr),zmax=std::strtod(argv[6],nullptr);
const double step=std::strtod(argv[7],nullptr);
if(!std::isfinite(x)||!std::isfinite(y)||!std::isfinite(zmin)||!std::isfinite(zmax)
||!std::isfinite(step)||zmax<=zmin||step<=0.0)return 2;
VFJson::Value root;
std::string error;
{
std::ifstream input(argv[1],std::ios::binary);
if(!input){std::fprintf(stderr,"owner JSON open failed\n");return 2;}
std::string text{std::istreambuf_iterator<char>(input),std::istreambuf_iterator<char>{}};
if(!VFJson::Parser(std::move(text)).Parse(root,error))
{std::fprintf(stderr,"owner JSON parse failed: %s\n",error.c_str());return 2;}
}
if(recipe=="floating-islands"
&&!StandaloneWorldAssemblyPrototype::SelectTopStrateAsFloatingIslands(root,error))
{std::fprintf(stderr,"FI selection failed: %s\n",error.c_str());return 2;}
auto owner=std::make_shared<FStandaloneOwnerWorld>();
if(!StandaloneOwnerLoader::Resolve(root,*owner,error))
{std::fprintf(stderr,"owner resolve failed: %s\n",error.c_str());return 2;}
VoxelForgeCore::WorldAssemblyManifest assembly;
if(!StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype(
*owner,root,error,{},&assembly))
{std::fprintf(stderr,"assembly setup failed: %s\n",error.c_str());return 2;}
if(recipe=="floating-islands"
&&!StandaloneWorldAssemblyPrototype::AttachFloatingIslandWorldAssembly(
*owner,root,assembly,error))
{std::fprintf(stderr,"FI setup failed: %s\n",error.c_str());return 2;}
VoxelForgeCore::ResolvedLayoutSnapshotV3 resolvedLayout;
if(!StandaloneWorldAssemblyPrototype::BuildResolvedLayoutSnapshot(
*owner,assembly,recipe,resolvedLayout,error))
{std::fprintf(stderr,"resolved layout build failed: %s\n",error.c_str());return 2;}
auto* rootObject=std::get_if<VFJson::Value::Object>(&root.Data);
if(!rootObject)return 2;
VFJson::Value layoutJson;
layoutJson.Data=resolvedLayout.ToJson();
(*rootObject)["resolved_layout_json"]=std::move(layoutJson);
auto snapshot=VoxelForgeCore::MakeStandaloneSnapshotFromParsedJson(
root,owner->Seed,3,8,false,false,error);
if(!snapshot)
{std::fprintf(stderr,"snapshot resolve failed: %s\n",error.c_str());return 2;}
const auto* layout=snapshot.resolvedLayout();
if(!layout){std::fprintf(stderr,"resolved layout missing\n");return 2;}
for(const auto& stratum:layout->strates)
std::printf("[DensityStratum] order=%d strate=%d generator=%s mode=%s width_um=%lld bedrock_um=%lld..%lld ceiling_um=%lld..%lld\n",
stratum.order,stratum.strateIndex,stratum.generatorKind.c_str(),
stratum.transitionMode.c_str(),static_cast<long long>(stratum.transitionWidthMicrometres),
static_cast<long long>(stratum.bedrock.bottomMicrometres),
static_cast<long long>(stratum.bedrock.topMicrometres),
static_cast<long long>(stratum.ceiling.bottomMicrometres),
static_cast<long long>(stratum.ceiling.topMicrometres));
const auto interface=std::find_if(layout->strates.begin(),layout->strates.end(),
[](const auto& stratum){return stratum.order==0;});
if(interface==layout->strates.end())return 2;
VoxelForgeCore::World world(std::move(snapshot));
VoxelForgeCore::ShapeBuildRequest request;
request.minVoxel={static_cast<std::int32_t>(std::floor((x-32.0)*4.0)),
static_cast<std::int32_t>(std::floor((y-32.0)*4.0)),
static_cast<std::int32_t>(std::floor((zmin-4.0)*4.0))};
request.maxVoxel={static_cast<std::int32_t>(std::ceil((x+32.0)*4.0)),
static_cast<std::int32_t>(std::ceil((y+32.0)*4.0)),
static_cast<std::int32_t>(std::ceil((zmax+4.0)*4.0))};
request.clipMinVoxel=request.minVoxel;
request.clipMaxVoxel=request.maxVoxel;
request.workerLimit=12;
request.includeFarWorld=false;
FStandaloneCoreScheduler scheduler;
if(!world.compile(request,scheduler,error))
{std::fprintf(stderr,"shape compile failed: %s\n",error.c_str());return 2;}
std::printf("[DensityLine] recipe=%s mode=%s width_um=%lld seam_um=%lld band_top_um=%lld band_bottom_um=%lld xy_m=%.6f,%.6f core_voxel_m=0.25 status=PASS\n",
recipe.c_str(),interface->transitionMode.c_str(),
static_cast<long long>(interface->transitionWidthMicrometres),
static_cast<long long>(interface->bedrock.bottomMicrometres),
static_cast<long long>(interface->bedrock.topMicrometres),
static_cast<long long>(interface->bedrock.bottomMicrometres),x,y);
std::printf("z_m,density_vox,lattice_vox,unclamped_vox,dispatch\n");
const auto count=static_cast<std::size_t>(std::floor((zmax-zmin)/step+1.0e-9));
for(std::size_t i=0;i<=count;++i)
{
const double z=zmin+static_cast<double>(i)*step;
const VoxelForgeCore::Vec3d p{x*4.0,y*4.0,z*4.0};
const VoxelForgeCore::Vec3i lattice{
static_cast<std::int32_t>(std::llround(x*4.0)),
static_cast<std::int32_t>(std::llround(y*4.0)),
static_cast<std::int32_t>(std::llround(z*4.0))};
std::printf("%.6f,%.9f,%.9f,%.9f,%s\n",z,world.densityAt(p),
world.densityAtLattice(lattice),world.unclampedDensityAt(p),
world.densityDispatchPathAt(p).c_str());
}
return 0;
}
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""Dump a bounded surface line from a VFMSH scene using the ring-audit sampler."""
import argparse
import importlib.util
from pathlib import Path
import resource
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("--surface", choices=("floor", "ceiling"), required=True)
parser.add_argument("--center", nargs=2, type=float, required=True)
parser.add_argument("--radius", type=float, required=True)
parser.add_argument("--lod", type=int, required=True)
parser.add_argument("--height-min-m", type=float, required=True)
parser.add_argument("--height-max-m", type=float, required=True)
parser.add_argument("--line", choices=("x", "y", "diagonal"), default="x")
parser.add_argument("--stride-m", type=float, default=8.0)
args = parser.parse_args()
audit_path = Path(__file__).with_name("AuditRingTerraceL32.py")
spec = importlib.util.spec_from_file_location("ring_audit_l32", audit_path)
audit = importlib.util.module_from_spec(spec)
spec.loader.exec_module(audit)
cx, cy = args.center
bounds = (cx - args.radius, cx + args.radius,
cy - args.radius, cy + args.radius)
voxel_um, triangles, tiles = audit.read_scene(args.scene, args.lod,
args.height_min_m, args.height_max_m, bounds)
cell_size = max(2.0, 16.0 * voxel_um / 1_000_000.0 * (1 << args.lod))
buckets = audit.build_buckets(triangles, args.surface == "floor", bounds, cell_size)
count = round(2.0 * args.radius / args.stride_m)
print(f"[SurfaceProfile] lod={args.lod} surface={args.surface} tiles={tiles} "
f"triangles={len(triangles)} line={args.line} stride_m={args.stride_m}")
print("index,x_m,y_m,z_m,nx,ny,nz")
for index in range(count + 1):
t = -args.radius + index * args.stride_m
if args.line == "x":
x, y = cx + t, cy
elif args.line == "y":
x, y = cx, cy + t
else:
x, y = cx + t / 2.0**0.5, cy + t / 2.0**0.5
preferred_height = args.height_max_m if args.surface == "floor" else args.height_min_m
hit = audit.sample_surface(buckets, x, y, args.surface == "floor", cell_size,
preferred_height)
if hit is None:
print(f"{index},{x:.3f},{y:.3f},nan,nan,nan,nan")
else:
z, normal = hit
print(f"{index},{x:.3f},{y:.3f},{z:.6f}," +
",".join(f"{value:.7f}" for value in normal))
print(f"[SurfaceProfileRSS] peak_rss_kib="
f"{resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
if __name__ == "__main__":
main()
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""Compare the v20 transition-column cache with the uncached v20 binary."""
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l32"
BINARIES = {
"base": OUT / "bin/VoxelForgeCoreHeadless-l32-clang-v20",
"cache": OUT / "bin/transition-cache/VoxelForgeCoreHeadless-l32-transition-cache",
}
ORDER = (("base", "cache"), ("cache", "base"), ("base", "cache"),
("cache", "base"), ("base", "cache"))
READY = re.compile(r"\bwhole_view_ready=([0-9.]+)s")
rows = []
failed = False
for pair, builds in enumerate(ORDER, 1):
for build in builds:
name = f"cache-compare-sw-pair{pair}-{build}"
logfile = OUT / f"{name}.log"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
str(BINARIES[build]), str(ROOT / "Standalone/data/owner_world.json"),
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=3",
"--max-clip-level=8", "--max-level=-1", "--recipe=surface-world",
]
started = time.monotonic()
try:
with logfile.open("w", encoding="utf-8") as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT,
timeout=900, check=False)
except subprocess.TimeoutExpired:
result = None
elapsed = time.monotonic() - started
text = logfile.read_text(encoding="utf-8", errors="replace")
matches = READY.findall(text)
valid = result is not None and result.returncode == 0 and len(matches) == 1
ready = float(matches[0]) if len(matches) == 1 else float("nan")
rows.append((pair, build, ready, elapsed,
result.returncode if result else "TIMEOUT", valid))
print(f"pair={pair} build={build} whole_view_ready={ready:.3f}s "
f"process_elapsed={elapsed:.1f}s {'PASS' if valid else 'FAIL'}", flush=True)
failed |= not valid
csv = OUT / "transition-cache-compare.csv"
csv.write_text(
"pair,build,whole_view_ready_seconds,process_elapsed_seconds,exit_code,status\n" +
"".join(f"{pair},{build},{ready:.6f},{elapsed:.3f},{code},"
f"{'PASS' if ok else 'FAIL'}\n"
for pair, build, ready, elapsed, code, ok in rows), encoding="utf-8")
for build in BINARIES:
values = [row[2] for row in rows if row[1] == build]
values.sort()
median = values[len(values) // 2]
print(f"[TransitionCacheCost] build={build} median_whole_view_ready_s={median:.3f}")
print(f"[TransitionCacheCost] runs={len(rows)} status={'FAIL' if failed else 'PASS'}")
raise SystemExit(1 if failed or len(rows) != 10 else 0)
@@ -0,0 +1,68 @@
# VoxelForge L32 report
## Cause and fix
The old Gradient transition wrote constant solid-density values per band. Those values are not signed distance to the displaced boundary, so Marching Cubes crossed band levels as contour-like terraces. The hash surface quantization was not the cause: sampling across the final FI floor gives density -0.53345 at z=-121.50 m and +0.46655 at -121.25 m; the SW ceiling gives +0.01514 at -126.50 m and -0.98486 at -126.25 m. Both cross linearly at about 4 density units/m.
L32 restores the width/8 Gradient displacement (2 m each side, about 4 m peak-to-peak at 16 m owner width). Density is now signed distance to the union of the displaced solid intervals, continuous across band boundaries. Cap samples follow the same displaced faces. Passage-mouth fades use cubic smoothstep across a 2 m fade from the protected mouth radius; this preserves the face while blending the column flare. Version/evaluator is v20.
## Surface and interface audits
Branch-locked radial and straight profiles pass on both faces at LOD0 through LOD8. Every tested LOD has at least 3.15 m height range; no repeated-height plateau or following step was found. LOD0/1 profiles use 0.125 m samples (SW LOD1 also checked at 0.0625 m); LOD2–8 use 0.5 m samples. The largest adjacent-normal change was 17.50° on the fine SW LOD1 scan, below the 20° audit limit. Peak RSS for the final Python ring scans was 373,596 KiB (FI LOD0); the passage-fade scans peaked at 52,128 KiB. Mesh scans use tile/chunk processing.
Interleaved also passes 11 radial/straight profiles at each LOD0–8: all selected windows have full coverage, no flats or steps, and at most 0.367° adjacent-normal change. Their local height ranges are 0.032–3.174 m; the 3 m minimum is the Gradient amplitude check, not an Interleaved requirement. Peak RSS for this tile-streamed sweep was 24,468 KiB.
Both ring negative controls fail as intended: L30 has 0.742 m range, a 1.875 m flat run followed by a 0.241 m step, and a 27.34° normal jump; L31's flat fix has only 0.000046 m range. The passage-mouth audit passes on both overlapping faces: upper max normal change 15.06°, lower 7.96°, with full coverage and no flats or steps.
Hole/interface and minimum-band audits pass for Hard, Gradient and Interleaved, for both recipes and compilers: zero hole columns and zero air samples. Wider-than-declared and thinner-than-minimum controls are rejected. Minimum bands are 0.5 m FI, 1.0 m SW and 6.25 m lower band; maximum Interleaved crossing is 6.487 m against the 16 m bound. Passage audit passes all 16 recipe-stamped rows; recipe-mismatch and disconnected-end controls are detected.
Determinism passes 24/24: the L25 command and 24 m crossing, both recipes, Clang and GCC, workers 1/8/12.
## Captures and hashes
Tint-on and tint-off JPEGs are in `captures/`; all are under 30 KB (limit 300 KB):
- `fi-floor-near-tint-on.jpg`, `fi-floor-near-tint-off.jpg`
- `fi-floor-far-tint-on.jpg`, `fi-floor-far-tint-off.jpg`
- `sw-ceiling-near-tint-on.jpg`, `sw-ceiling-near-tint-off.jpg`
- `sw-ceiling-far-tint-on.jpg`, `sw-ceiling-far-tint-off.jpg`
They show the FI floor and SW ceiling from inside each stratum, with grazing light, at LOD0 and LOD8. Capture SHA256 values:
| Capture | SHA256 |
|---|---|
| fi-floor-far-tint-off.jpg | `239b6be70c177e267d2db95f206fdcdc8834779a7948fdaaddd136b4163d1f34` |
| fi-floor-far-tint-on.jpg | `3ecefd555275036a7045a541f02bb1873e22302495009dbd80b4ac58ce716b58` |
| fi-floor-near-tint-off.jpg | `847f10acfb420c2bbded61bdee7f578cde19469777b2ef4c5a0eba08b406611c` |
| fi-floor-near-tint-on.jpg | `4a5d3e3f8e8254639fa1840a2fb4497f2ab19f64bb4734e13abe3c3cfcfb4008` |
| sw-ceiling-far-tint-off.jpg | `f5ec099076c507bed5a703302d89b665e139804a8f8895a68c1d5705aabf9f61` |
| sw-ceiling-far-tint-on.jpg | `b82618814c8320be2de1ac53ba10e9ab4469299a8b53b776be32c6ca9a659988` |
| sw-ceiling-near-tint-off.jpg | `5789ce59a7748aa278c1b95edae45aec87721721260c1a3aefe6c4cc1e47cd7a` |
| sw-ceiling-near-tint-on.jpg | `aa4351c5effc5e93fc0879257fe056b3f4625e7842f5118f28588fb2c5c1afe2` |
Final Core binary SHA256:
- Clang: `052694a569c92ef407c25bd9a534c7123ef800f46733e5c428e965c32d905fdc`
- GCC: `c8656901ce18861f12168849165785937a2495233604314df9e005ed1e92afdd`
## Cost and edits
Five interleaved pairs per recipe against L31. Median whole-view-ready time was SW 1.723 s → 1.756 s (+1.92%) and FI 16.963 s → 17.221 s (+1.52%); paired results were mixed and within observed run noise. No Unreal files changed. The five edited files are the Core public header, `FarShellsInternal.h`, `ResolvedLayoutInternal.h`, `ShapeWorldInternal.h` and `LinuxOffscreenCapture.cpp`; Unreal compilation was not available here.
## Failed and retried runs
- The initial multi-LOD Python audit was stopped by system RAM pressure (reported peak unavailable). Subsequent mesh audits ran with CPU/address-space caps and streamed or selected tiles; peak RSS is recorded above. The first whole-mesh FI LOD8 candidate scan was interrupted and replaced by a targeted tile scan.
- Early ring-window searches and narrow-height audits selected the wrong one of two overlapping faces. The FI LOD3/4 branch probes measured 1.423 m amplitude / a 1.0 m flat run; the SW LOD1 low-face probe reached 20.19° normal change. Face-locked, broad-window scans replaced them and pass. The exploratory `ring-*`, `ringset-*`, `search-*` and `window-search-*` logs preserve rejected window candidates. The L30/L31 failures above are intentional negative controls.
- The first Interleaved layout/export probe omitted the runner's required streaming flags and exited with usage; the retry produced the LOD0–8 export. Its broad 0.5 m candidate scan applied the Gradient 3 m window heuristic and rejected LOD0–4 (one LOD1 candidate switched overlapping faces at 62.92°); selected branch-locked profiles at those LODs and passing LOD5–8 windows show no plateaus or steps. An unsupported `--help` probe also returned usage with exit 2.
- The exact-source passage audit at midpoint preference switched faces and reported a 47.79° jump; upper- and lower-face locked reruns pass. An early wrong-camera export selected zero tiles; the exact camera export was rerun. Initial multi-LOD capture meshes mixed neighboring shells, so the final captures use focused LOD0/LOD8 surface patches.
- One fine-normal probe had a tuple-index error and was corrected. A SW far-mesh filter had an argument/layout parsing error and was corrected. The density CSV was overwritten by verbose output; the probe was rebuilt from final Core objects and rerun.
- The transition-cache build failed on a nested `Shape` initializer; the retry built, but the cache showed no gain and was removed. `/usr/bin/time` was unavailable for one capture attempt; the capped renderer was rerun directly. The first determinism run was interrupted and resumed; the final matrix passes 24/24. One log-search command used unavailable `rg`; a capped streaming-Python scan replaced it.
- Performance experiments were rejected or superseded: initial transition path +36.11% SW/+7.18% FI, planar query +14.89%/+2.28%, 3x3 coverage +6.06%/+1.65%, 5-point coverage +4.04%/+2.03%, single-transition fast path +3.52%/+1.39%; cache trial was slower (2.188 s vs 2.171 s). The retained hash-prefix version is the five-pair result above. Logs and exports are under `Saved/Linux/l32/`.
## Orchestrator review (Claude)
- Merged. Captures checked by me: the FI floor (near, tint off) is a smooth rolling surface with no rings or terraces;
the SW ceiling and far views are smooth. Gradient is restored at width/8 (about 4 m peak-to-peak) with signed-distance
density; the ring audit rejects both L30 (rings) and L31 (flat). The memory-pressure kill mid-round was resumed;
audits now run capped and tile-streamed.
- Cumulative SW cost vs L24 is roughly +5% after L28–L32 (features: columns, transitions, smooth faces). FI is ≈ +2%.
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""Run the recipe-stamped L31 passage audit matrix and reject mislabeled runs."""
import json
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l32"
OUT.mkdir(parents=True, exist_ok=True)
BINARIES = {
"clang": OUT / "bin/VoxelForgeCoreHeadless-l32-clang-v20",
"gcc": OUT / "bin/VoxelForgeCoreHeadless-l32-gcc-v20",
}
MARKERS = (
"[ResolvedPassageAuditSummary]",
"[PassageOpenAirAuditSummary]",
"[PassageNaturalnessSummary]",
"[PassageNoLongBridgeAudit]",
"[PassageRockColumnAuditSummary]",
)
rows = []
failed = False
for recipe in ("surface-world", "floating-islands"):
for style in range(4):
data = ROOT / f"Saved/Linux/linux25-owner-{recipe}-style{style}.json"
for compiler, binary in BINARIES.items():
name = f"passage-{recipe}-style{style}-{compiler}"
logfile = OUT / f"{name}.log"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", str(binary), str(data), "--workers=12", "--world-assembler-prototype",
"--stream-benchmark", "--stream-pipeline", "--force-generate",
"--clip-radius=3", "--max-clip-level=8", "--max-level=-1",
f"--recipe={recipe}", "--audit-resolved-layout-passages",
]
started = time.monotonic()
try:
with logfile.open("w", encoding="utf-8") as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT,
timeout=900, check=False)
except subprocess.TimeoutExpired:
result = None
elapsed = time.monotonic() - started
text = logfile.read_text(encoding="utf-8", errors="replace")
stamps = re.findall(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
text, re.M)
recipe_ok = stamps == [(recipe, recipe, "PASS")]
markers_ok = all(re.search(re.escape(marker) + r".*status=PASS", text)
for marker in MARKERS)
capsule_ok = bool(re.search(
r"^\[ResolvedPassageAudit\].* blocked=0 support_samples=\d+ "
r"unsupported=0 grade_failures=0 mouth_content=2/2 mouth_radius=2/2 "
r"walkability=PASS$", text, re.M))
island_route_ok = (recipe != "floating-islands" or bool(re.search(
r"^\[FloatingIslandRouteAudit\].* blocked=0 support_samples=\d+ "
r"unsupported=0 grade_failures=0 status=PASS$", text, re.M)))
binding_ok = bool(re.search(
r"\[ResolvedPassageAuditSummary\].*route_bindings=[1-9][0-9]* "
r"route_binding_failures=0 .*status=PASS", text))
walk_ok = "[Walkability] PASS" in text
if recipe == "floating-islands":
control_ok = "[PassageColumnDisconnectedEndControl]" in text and bool(
re.search(r"\[PassageColumnDisconnectedEndControl\].*detected=true", text))
else:
control_ok = True
ok = (result is not None and result.returncode == 0 and recipe_ok
and markers_ok and capsule_ok and island_route_ok and binding_ok
and walk_ok and control_ok)
actual_recipe = stamps[0][1] if len(stamps) == 1 else "MISSING"
rows.append((recipe, actual_recipe, style, compiler, elapsed,
result.returncode if result else "TIMEOUT", ok))
print(f"{name} elapsed={elapsed:.1f}s exit={result.returncode if result else 'TIMEOUT'} "
f"recipe={stamps[0][1] if stamps else 'MISSING'} "
f"capsule={'PASS' if capsule_ok and island_route_ok else 'FAIL'} "
f"column_control={'PASS' if control_ok else 'FAIL'} {'PASS' if ok else 'FAIL'}",
flush=True)
if not ok:
failed = True
summary = OUT / "passage-audit-matrix.csv"
summary.write_text(
"requested_recipe,actual_recipe,style,compiler,elapsed_seconds,exit_code,status\n" +
"".join(f"{requested},{actual},{style},{compiler},{elapsed:.3f},{code},"
f"{'PASS' if ok else 'FAIL'}\n"
for requested, actual, style, compiler, elapsed, code, ok in rows), encoding="utf-8")
control_log = OUT / "recipe-mismatch-control.log"
control_owner = OUT / "recipe-mismatch-control-owner.json"
control_owner_data = json.loads(
(ROOT / "Saved/Linux/linux25-owner-surface-world-style0.json").read_text(encoding="utf-8"))
top_owner_stratum = max(control_owner_data["strates"], key=lambda stratum: stratum["top_chunk_z"])
top_owner_stratum["asset"]["GeneratorType"] = 6 # ECaveGeneratorType::FloatingIslands
control_owner.write_text(json.dumps(control_owner_data, separators=(",", ":")), encoding="utf-8")
control_command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", str(BINARIES["clang"]),
str(control_owner),
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=3",
"--max-clip-level=8", "--max-level=-1", "--recipe=surface-world",
"--audit-resolved-layout-passages",
]
with control_log.open("w", encoding="utf-8") as stream:
control = subprocess.run(control_command, stdout=stream, stderr=subprocess.STDOUT,
timeout=900, check=False)
control_text = control_log.read_text(encoding="utf-8", errors="replace")
control_ok = (control.returncode == 2 and
"[WorldAssemblerRecipeAudit] requested=surface-world actual=floating-islands "
"top_generator=FloatingIslands " in control_text and
"floating_islands_stratum=present status=FAIL" in control_text)
print(f"[L32RecipeMismatchControl] requested=surface-world actual=floating-islands "
f"exit={control.returncode} detected={'true' if control_ok else 'false'} "
f"{'PASS' if control_ok else 'FAIL'}", flush=True)
print(f"[L32PassageMatrix] runs={len(rows)} pass={sum(row[-1] for row in rows)} "
f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True)
raise SystemExit(1 if failed or not control_ok or len(rows) != 16 else 0)
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Run five interleaved whole-view pairs against the L31 binary."""
import os
import re
import statistics
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l32"
OUT.mkdir(parents=True, exist_ok=True)
RUN_TAG = os.environ.get("VOXELFORGE_COST_TAG", "").strip()
BINARIES = {
"l31": ROOT / "Saved/Linux/l31/bin/VoxelForgeCoreHeadless-linux31-clang",
"l32": Path(os.environ.get("VOXELFORGE_L32_COST_BINARY",
str(OUT / "bin/VoxelForgeCoreHeadless-l32-clang-v20"))),
}
ORDERS = (("l31", "l32"), ("l32", "l31"), ("l31", "l32"),
("l32", "l31"), ("l31", "l32"))
READY = re.compile(r"\bwhole_view_ready=([0-9.]+)s")
rows = []
failed = False
for recipe in ("surface-world", "floating-islands"):
for pair, order in enumerate(ORDERS, 1):
for build in order:
tag = f"-{RUN_TAG}" if RUN_TAG else ""
name = f"cost{tag}-{recipe}-pair{pair}-{build}"
logfile = OUT / f"{name}.log"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
str(BINARIES[build]), str(ROOT / "Standalone/data/owner_world.json"),
"--workers=12", "--world-assembler-prototype", "--stream-benchmark",
"--stream-pipeline", "--force-generate", "--clip-radius=3",
"--max-clip-level=8", "--max-level=-1", f"--recipe={recipe}",
]
started = time.monotonic()
try:
with logfile.open("w", encoding="utf-8") as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT,
timeout=900, check=False)
except subprocess.TimeoutExpired:
result = None
elapsed = time.monotonic() - started
text = logfile.read_text(encoding="utf-8", errors="replace")
matches = READY.findall(text)
if build == "l32":
stamps = re.findall(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
text, re.M)
actual_recipe = stamps[0][1] if len(stamps) == 1 else "missing"
stamp_ok = stamps == [(recipe, recipe, "PASS")]
else:
configured = re.findall(r"^\[HeadlessConfig\].*\brecipe=([^\s]+)", text, re.M)
actual_recipe = configured[0] if len(configured) == 1 else "missing"
floating_plan = "[FloatingIslandWorldAssembly]" in text
surface_plan = "[WorldAssemblerPrototype]" in text
plan_matches = ((actual_recipe == "floating-islands" and floating_plan)
or (actual_recipe == "surface-world" and not floating_plan
and surface_plan))
marker = (f"[L32BaselineRecipeAudit] requested={recipe} actual={actual_recipe} "
f"headless_recipe={configured[0] if len(configured) == 1 else 'missing'} "
f"floating_island_plan={'present' if floating_plan else 'absent'} "
f"surface_world_plan={'present' if surface_plan else 'absent'} "
f"status={'PASS' if actual_recipe == recipe and plan_matches else 'FAIL'}\n")
with logfile.open("a", encoding="utf-8") as stream:
stream.write(marker)
text += marker
stamp_ok = actual_recipe == recipe and plan_matches and len(configured) == 1
valid = (result is not None and result.returncode == 0 and len(matches) == 1
and "hash=off" in text and "cache_hits=0" in text and stamp_ok)
ready = float(matches[0]) if len(matches) == 1 else float("nan")
rows.append((recipe, pair, build, ready, elapsed,
result.returncode if result else "TIMEOUT", valid))
print(f"{recipe} pair={pair} build={build} whole_view_ready={ready:.3f}s "
f"process_elapsed={elapsed:.1f}s {'PASS' if valid else 'FAIL'}", flush=True)
failed |= not valid
summary = OUT / (f"cost-runs-{RUN_TAG}.csv" if RUN_TAG else "cost-runs.csv")
summary.write_text(
"recipe,pair,build,whole_view_ready_seconds,process_elapsed_seconds,exit_code,status\n" +
"".join(f"{recipe},{pair},{build},{ready:.6f},{elapsed:.3f},{code},"
f"{'PASS' if ok else 'FAIL'}\n"
for recipe, pair, build, ready, elapsed, code, ok in rows), encoding="utf-8")
for recipe in ("surface-world", "floating-islands"):
by_build = {build: [row[3] for row in rows if row[0] == recipe and row[2] == build]
for build in BINARIES}
l31 = statistics.median(by_build["l31"])
l32 = statistics.median(by_build["l32"])
paired = []
for pair in range(1, 6):
values = {row[2]: row[3] for row in rows if row[0] == recipe and row[1] == pair}
paired.append((values["l32"] - values["l31"]) / values["l31"] * 100.0)
print(f"[L32CostSummary] recipe={recipe} pairs=5 median_l31_s={l31:.3f} "
f"median_l32_s={l32:.3f} median_change_pct={(l32/l31-1)*100.0:+.2f} "
f"paired_change_pct={','.join(f'{value:+.2f}' for value in paired)}")
print(f"[L32Cost] runs={len(rows)} status={'FAIL' if failed else 'PASS'} summary={summary}",
flush=True)
raise SystemExit(1 if failed or len(rows) != 20 else 0)
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""Check the L25 hash command and 24 m crossing across compilers and workers."""
import os
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l32"
OUT.mkdir(parents=True, exist_ok=True)
RUN_TAG = os.environ.get("VOXELFORGE_DETERMINISM_TAG", "").strip()
RUN_RESUME = os.environ.get("VOXELFORGE_DETERMINISM_RESUME", "0") == "1"
BINARIES = {
"clang": Path(os.environ.get("VOXELFORGE_L32_CLANG_BINARY",
str(OUT / "bin/VoxelForgeCoreHeadless-l32-clang-v20"))),
"gcc": Path(os.environ.get("VOXELFORGE_L32_GCC_BINARY",
str(OUT / "bin/VoxelForgeCoreHeadless-l32-gcc-v20"))),
}
HASH_PATTERN = re.compile(
r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
candidate_reference = {}
rows = []
failed = False
prior_elapsed = {}
if RUN_RESUME and RUN_TAG:
prior_log = OUT / f"determinism-{RUN_TAG}-runner.log"
if prior_log.exists():
for line in prior_log.read_text(encoding="utf-8", errors="replace").splitlines():
match = re.match(r"^(\S+) elapsed=([0-9.]+)s .* PASS$", line)
if match:
prior_elapsed[match.group(1)] = float(match.group(2))
def run(kind, compiler, recipe, workers):
global failed
tag = f"-{RUN_TAG}" if RUN_TAG else ""
name = f"{kind}{tag}-{compiler}-{recipe}-w{workers}"
logfile = OUT / f"{name}.log"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
str(BINARIES[compiler]), str(ROOT / "Standalone/data/owner_world.json"),
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
"--stream-hash", "--force-generate", "--clip-radius=3", "--max-clip-level=8",
"--far-horizon-lod8-step=0", f"--workers={workers}", f"--recipe={recipe}",
]
if kind == "crossing24":
command.extend(("--camera-step=24,0,0", "--region-crossing"))
if RUN_RESUME and name in prior_elapsed and logfile.exists():
result = subprocess.CompletedProcess(command, 0)
elapsed = prior_elapsed[name]
else:
started = time.monotonic()
try:
with logfile.open("w", encoding="utf-8") as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT,
timeout=900, check=False)
except subprocess.TimeoutExpired:
result = None
elapsed = time.monotonic() - started
text = logfile.read_text(encoding="utf-8", errors="replace")
stamps = re.findall(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
text, re.M)
hashes = HASH_PATTERN.findall(text)
key = (kind, recipe)
reference = candidate_reference.get(key)
stable = reference is None or hashes == reference
if reference is None and hashes:
candidate_reference[key] = hashes
ok = (result is not None and result.returncode == 0
and stamps == [(recipe, recipe, "PASS")]
and "hash=on" in text and len(hashes) == 12 and stable)
rows.append((kind, recipe, compiler, workers, elapsed,
result.returncode if result else "TIMEOUT", len(hashes), ok))
print(f"{name} elapsed={elapsed:.1f}s recipe={stamps[0][1] if stamps else 'MISSING'} "
f"hashes={len(hashes)} stable_across_matrix={'yes' if stable else 'no'} "
f"{'PASS' if ok else 'FAIL'}", flush=True)
failed |= not ok
for kind in ("l25", "crossing24"):
for recipe in ("surface-world", "floating-islands"):
for compiler in ("clang", "gcc"):
for workers in (1, 8, 12):
run(kind, compiler, recipe, workers)
summary = OUT / (f"determinism-{RUN_TAG}.csv" if RUN_TAG else "determinism.csv")
summary.write_text(
"kind,recipe,compiler,workers,elapsed_seconds,exit_code,hash_rows,status\n" +
"".join(f"{kind},{recipe},{compiler},{workers},{elapsed:.3f},{code},{count},"
f"{'PASS' if ok else 'FAIL'}\n"
for kind, recipe, compiler, workers, elapsed, code, count, ok in rows),
encoding="utf-8")
print(f"[L32Determinism] runs={len(rows)} pass={sum(row[-1] for row in rows)} "
f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True)
raise SystemExit(1 if failed or len(rows) != 24 else 0)
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Run L31 route/proof and transition invariants with recipe-stamped logs."""
import re
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l32"
BINARIES = {
"clang": OUT / "bin/VoxelForgeCoreHeadless-l32-clang-v20",
"gcc": OUT / "bin/VoxelForgeCoreHeadless-l32-gcc-v20",
}
rows = []
failed = False
def run(name, binary, data, recipe, extra, checks):
global failed
logfile = OUT / f"{name}.log"
command = [
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", str(binary), str(data), "--workers=12", "--world-assembler-prototype",
"--stream-benchmark", "--stream-pipeline", "--force-generate",
"--clip-radius=3", "--max-clip-level=8", "--max-level=-1",
f"--recipe={recipe}", *extra,
]
started = time.monotonic()
try:
with logfile.open("w", encoding="utf-8") as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT,
timeout=900, check=False)
except subprocess.TimeoutExpired:
result = None
elapsed = time.monotonic() - started
text = logfile.read_text(encoding="utf-8", errors="replace")
stamps = re.findall(
r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$",
text, re.M)
stamp_ok = stamps == [(recipe, recipe, "PASS")]
checks_ok = all(check(text) for check in checks)
ok = result is not None and result.returncode == 0 and stamp_ok and checks_ok
rows.append((name, recipe, elapsed, result.returncode if result else "TIMEOUT", ok))
print(f"{name} elapsed={elapsed:.1f}s recipe={stamps[0][1] if stamps else 'MISSING'} "
f"stamp={'PASS' if stamp_ok else 'FAIL'} checks={'PASS' if checks_ok else 'FAIL'} "
f"{'PASS' if ok else 'FAIL'}", flush=True)
failed |= not ok
owner = ROOT / "Standalone/data/owner_world.json"
for recipe in ("surface-world", "floating-islands"):
for compiler, binary in BINARIES.items():
name = f"invariant-route-proof-{recipe}-{compiler}"
run(name, binary, owner, recipe,
["--stream-hash", "--audit-uniform-block-proofs", "--audit-route-parity"],
[lambda text: bool(re.search(
r"^\[RouteParityAudit\].*status=PASS$", text, re.M)),
lambda text: bool(re.search(
r"^\[UniformBlockProofAudit\].*violations=0(?:\s|$)", text, re.M))])
for recipe in ("surface-world", "floating-islands"):
for compiler, binary in BINARIES.items():
for mode in ("hard", "gradient", "interleaved"):
name = f"invariant-transition-{recipe}-{mode}-{compiler}"
run(name, binary, owner, recipe,
[f"--transition-mode={mode}", "--audit-strate-transitions"],
[lambda text: bool(re.search(
r"^\[StrateTransitionAuditSummary\].*hole_columns=0 air_samples=0 .*status=PASS$",
text, re.M)),
lambda text: bool(re.search(
r"^\[StrateTransitionNegativeControls\].*status=PASS$", text, re.M))])
summary = OUT / "invariant-audits.csv"
summary.write_text(
"run,recipe,elapsed_seconds,exit_code,status\n" +
"".join(f"{name},{recipe},{elapsed:.3f},{code},{'PASS' if ok else 'FAIL'}\n"
for name, recipe, elapsed, code, ok in rows),
encoding="utf-8")
print(f"[L32InvariantAudits] runs={len(rows)} pass={sum(row[-1] for row in rows)} "
f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True)
raise SystemExit(1 if failed or len(rows) != 16 else 0)
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""Stream one VFMSH tile at a time to locate LOD/interface patches."""
import argparse
import array
import resource
import struct
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument("scene")
parser.add_argument("--lod", type=int, required=True)
parser.add_argument("--surface", choices=("floor", "ceiling"), required=True)
parser.add_argument("--height-min-m", type=float, required=True)
parser.add_argument("--height-max-m", type=float, required=True)
args = parser.parse_args()
candidates = []
scanned = 0
with open(args.scene, "rb") as stream:
if stream.read(8) != b"VFMSH001":
raise SystemExit("invalid VFMSH001 scene")
version, voxel_um, tile_count = struct.unpack("<3I", stream.read(12))
stream.seek(40, 1)
if version != 1:
raise SystemExit("unsupported mesh scene")
for _ in range(tile_count):
key = struct.unpack("<4i", stream.read(16))
surface_count, _, vertex_count, index_count, mask_count = struct.unpack(
"<5I", stream.read(20))
payload = vertex_count * 24 + index_count * 4 + mask_count
if key[3] != args.lod:
stream.seek(payload, 1)
continue
scanned += 1
positions = array.array("f")
positions.frombytes(stream.read(vertex_count * 12))
normals = array.array("f")
normals.frombytes(stream.read(vertex_count * 12))
indices = array.array("I")
indices.frombytes(stream.read(index_count * 4))
masks = stream.read(mask_count)
if sys.byteorder != "little":
positions.byteswap()
normals.byteswap()
indices.byteswap()
hits = 0
sum_x = sum_y = sum_z = 0.0
min_z, max_z = float("inf"), float("-inf")
want_up = args.surface == "floor"
for offset in range(0, index_count, 3):
if masks and masks[offset // 3]:
continue
a, b, c = indices[offset:offset + 3]
if max(a, b, c) >= surface_count:
continue
nz = (normals[a * 3 + 2] + normals[b * 3 + 2] + normals[c * 3 + 2]) / 3.0
if (nz > 0) != want_up:
continue
za, zb, zc = positions[a * 3 + 2], positions[b * 3 + 2], positions[c * 3 + 2]
if ((za + zb + zc) / 3.0 < args.height_min_m
or (za + zb + zc) / 3.0 > args.height_max_m):
continue
hits += 1
sum_x += (positions[a * 3] + positions[b * 3] + positions[c * 3]) / 3.0
sum_y += (positions[a * 3 + 1] + positions[b * 3 + 1] + positions[c * 3 + 1]) / 3.0
z = (za + zb + zc) / 3.0
sum_z += z
min_z, max_z = min(min_z, za, zb, zc), max(max_z, za, zb, zc)
if hits:
extent = 32.0 * (1 << key[3]) * voxel_um / 1_000_000.0
candidates.append((hits, key, sum_x / hits, sum_y / hits,
sum_z / hits, min_z, max_z, extent))
candidates.sort(reverse=True, key=lambda item: item[0])
print(f"[VFMeshTileScan] lod={args.lod} surface={args.surface} scanned_tiles={scanned} "
f"candidate_tiles={len(candidates)} peak_rss_kib="
f"{resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
for hits, key, x, y, z, low, high, extent in candidates[:40]:
print(f"[VFMeshTile] key={key} triangles={hits} centroid_m=({x:.3f},{y:.3f},{z:.3f}) "
f"z_m={low:.3f}..{high:.3f} extent_m={extent:.3f}")
if __name__ == "__main__":
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+56 -14
View File
@@ -296,6 +296,7 @@ uniform float uHeightRange;
uniform float uTileEdgeWidth;
uniform vec3 uLightDirection;
uniform int uHeadlamp;
uniform int uGrazingLight;
uniform int uClipEnabled;
uniform vec4 uClipPlane;
void main()
@@ -315,10 +316,11 @@ void main()
float heightT=clamp(0.5+(vHeight-uHeightCenter)/max(uHeightRange,0.001),0.0,1.0);
float smoothHeightT=heightT*heightT*(3.0-2.0*heightT);
vec3 heightTint=uHeightTint!=0
?mix(vec3(0.80,0.91,1.0),vec3(1.0,0.91,0.77),smoothHeightT)
?mix(vec3(0.62,0.78,1.0),vec3(1.0,0.82,0.62),smoothHeightT)
:vec3(1.0);
float diffuse=max(dot(n,normalize(uLightDirection)),0.0);
float illumination=uHeadlamp!=0?0.78+0.34*diffuse:0.62+0.38*diffuse;
float illumination=uGrazingLight!=0?0.32+1.20*diffuse:
uHeadlamp!=0?0.78+0.34*diffuse:0.62+0.38*diffuse;
color=vec3(0.64,0.62,0.56)*heightTint*illumination;
}
if(uTileEdges!=0&&vTileData.z>0.0)
@@ -380,8 +382,11 @@ void main()
}
bool Render(FScene& Scene,const std::filesystem::path& Output,int Width,int Height,
double HorizontalFovDegrees,bool ReadableMode,bool HeightTint,bool Headlamp,bool TileEdges,
double TileEdgeWidthMeters,bool ClipPlaneEnabled,
double HorizontalFovDegrees,double HeightRangeMeters,
double HeightCenterMeters,bool ReadableMode,
bool HeightTint,bool Headlamp,bool TileEdges,
double TileEdgeWidthMeters,bool HasLightDirection,
const std::array<double,3>& LightDirection,bool ClipPlaneEnabled,
const std::array<double,4>& ClipPlane)
{
EGLDisplay Display=MakeDisplay();
@@ -478,19 +483,24 @@ void main()
glUniform1i(glGetUniformLocation(Program,"uTileEdges"),TileEdges?1:0);
glUniform1i(glGetUniformLocation(Program,"uHeightTint"),HeightTint?1:0);
glUniform1f(glGetUniformLocation(Program,"uHeightCenter"),
static_cast<float>(Scene.CameraMeters[2]));
glUniform1f(glGetUniformLocation(Program,"uHeightRange"),64.0f);
static_cast<float>(HeightCenterMeters));
glUniform1f(glGetUniformLocation(Program,"uHeightRange"),
static_cast<float>(HeightRangeMeters));
glUniform1f(glGetUniformLocation(Program,"uTileEdgeWidth"),
static_cast<float>(TileEdgeWidthMeters));
glUniform1i(glGetUniformLocation(Program,"uClipEnabled"),ClipPlaneEnabled?1:0);
glUniform1i(glGetUniformLocation(Program,"uHeadlamp"),Headlamp?1:0);
glUniform1i(glGetUniformLocation(Program,"uGrazingLight"),HasLightDirection?1:0);
glUniform4f(glGetUniformLocation(Program,"uClipPlane"),
static_cast<float>(ClipPlane[0]),static_cast<float>(ClipPlane[1]),
static_cast<float>(ClipPlane[2]),static_cast<float>(ClipPlane[3]));
const std::array<double,3> ActiveLightDirection=HasLightDirection?LightDirection:
Headlamp?std::array<double,3>{-Forward[0],-Forward[1],-Forward[2]}:
std::array<double,3>{-0.42,-0.58,0.70};
glUniform3f(glGetUniformLocation(Program,"uLightDirection"),
Headlamp?static_cast<float>(-Forward[0]):-0.42f,
Headlamp?static_cast<float>(-Forward[1]):-0.58f,
Headlamp?static_cast<float>(-Forward[2]):0.70f);
static_cast<float>(ActiveLightDirection[0]),
static_cast<float>(ActiveLightDirection[1]),
static_cast<float>(ActiveLightDirection[2]));
glDrawElements(GL_TRIANGLES,static_cast<GLsizei>(Scene.Indices.size()),GL_UNSIGNED_INT,nullptr);
glFinish();
std::vector<std::uint8_t> Pixels(static_cast<std::size_t>(Width)*Height*4);
@@ -527,12 +537,14 @@ int main(int argc,char** argv)
{
if(argc<3)
{
std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--camera-m=X,Y,Z] [--yaw-deg=N] [--pitch-deg=N] [--shade=readable|normal] [--height-tint=on|off] [--headlamp=on|off] [--tile-edges=on|off] [--tile-edge-width-m=N] [--clip-plane=NX,NY,NZ,D]\n",argv[0]);
std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--height-range-m=N] [--height-center-m=N] [--camera-m=X,Y,Z] [--yaw-deg=N] [--pitch-deg=N] [--shade=readable|normal] [--height-tint=on|off] [--headlamp=on|off] [--light-direction=X,Y,Z] [--tile-edges=on|off] [--tile-edge-width-m=N] [--clip-plane=NX,NY,NZ,D]\n",argv[0]);
return 2;
}
int Width=2560,Height=1440;double Fov=90.0;
int Width=2560,Height=1440;double Fov=90.0,HeightRangeMeters=64.0;
double HeightCenterMeters=0.0;bool HasHeightCenter=false;
bool HasYaw=false,HasPitch=false;double Yaw=0.0,Pitch=0.0;
bool HasCamera=false;std::array<double,3> Camera{};
bool HasLightDirection=false;std::array<double,3> LightDirection{};
bool ReadableMode=true,HeightTint=true,TileEdges=false,Headlamp=false;double TileEdgeWidthMeters=0.15;
bool ClipPlaneEnabled=false;std::array<double,4> ClipPlane{};
for(int I=3;I<argc;++I)
@@ -550,6 +562,22 @@ int main(int argc,char** argv)
if(End==Value.c_str()||*End!='\0'||Fov<=1.0||Fov>=179.0)
{std::fprintf(stderr,"Invalid horizontal FOV\n");return 2;}
}
else if(Arg.starts_with("--height-range-m="))
{
char* End=nullptr;const std::string Value(Arg.substr(17));
HeightRangeMeters=std::strtod(Value.c_str(),&End);
if(End==Value.c_str()||*End!='\0'||!std::isfinite(HeightRangeMeters)
||HeightRangeMeters<=0.0||HeightRangeMeters>1000000.0)
{std::fprintf(stderr,"Invalid height tint range\n");return 2;}
}
else if(Arg.starts_with("--height-center-m="))
{
char* End=nullptr;const std::string Value(Arg.substr(18));
HeightCenterMeters=std::strtod(Value.c_str(),&End);
if(End==Value.c_str()||*End!='\0'||!std::isfinite(HeightCenterMeters))
{std::fprintf(stderr,"Invalid height tint center\n");return 2;}
HasHeightCenter=true;
}
else if(Arg.starts_with("--camera-m="))
{
const std::string Value(Arg.substr(11));
@@ -589,6 +617,17 @@ int main(int argc,char** argv)
else if(Mode=="off")Headlamp=false;
else {std::fprintf(stderr,"Invalid headlamp mode\n");return 2;}
}
else if(Arg.starts_with("--light-direction="))
{
const std::string Value(Arg.substr(18));
if(std::sscanf(Value.c_str(),"%lf,%lf,%lf",&LightDirection[0],
&LightDirection[1],&LightDirection[2])!=3
||!std::isfinite(LightDirection[0])||!std::isfinite(LightDirection[1])
||!std::isfinite(LightDirection[2])
||std::hypot(LightDirection[0],LightDirection[1],LightDirection[2])<=0.0)
{std::fprintf(stderr,"Invalid light direction; use X,Y,Z with non-zero length\n");return 2;}
HasLightDirection=true;
}
else if(Arg.starts_with("--tile-edges="))
{
const std::string_view Mode=Arg.substr(13);
@@ -623,13 +662,16 @@ int main(int argc,char** argv)
if(HasCamera)Scene.CameraMeters=Camera;
if(HasYaw)Scene.YawDegrees=Yaw;
if(HasPitch)Scene.PitchDegrees=Pitch;
std::printf("[OffscreenScene] voxels_per_meter=%.6f camera_m=(%.3f,%.3f,%.3f) yaw=%.2f pitch=%.2f height_m=%.3f..%.3f shade=%s height_tint=%s tile_edges=%s vertices=%zu triangles=%llu\n",
if(!HasHeightCenter)HeightCenterMeters=Scene.CameraMeters[2];
std::printf("[OffscreenScene] voxels_per_meter=%.6f camera_m=(%.3f,%.3f,%.3f) yaw=%.2f pitch=%.2f height_m=%.3f..%.3f height_center_m=%.3f shade=%s height_tint=%s tile_edges=%s vertices=%zu triangles=%llu\n",
1000000.0/Scene.VoxelSizeMicrons,Scene.CameraMeters[0],Scene.CameraMeters[1],Scene.CameraMeters[2],
Scene.YawDegrees,Scene.PitchDegrees,Scene.MinimumHeight,Scene.MaximumHeight,
HeightCenterMeters,
ReadableMode?"readable":"normal",HeightTint?"on":"off",
TileEdges?"on":"off",Scene.Vertices.size(),
static_cast<unsigned long long>(Scene.Triangles));
return Render(Scene,argv[2],Width,Height,Fov,ReadableMode,HeightTint,Headlamp,TileEdges,
TileEdgeWidthMeters,ClipPlaneEnabled,ClipPlane)?0:3;
return Render(Scene,argv[2],Width,Height,Fov,HeightRangeMeters,HeightCenterMeters,ReadableMode,
HeightTint,Headlamp,TileEdges,
TileEdgeWidthMeters,HasLightDirection,LightDirection,ClipPlaneEnabled,ClipPlane)?0:3;
}