Files
VoxelForge/Standalone/Source/StreamBenchmarkPipeline.h
T
Fr0zkaandClaude Opus 5.5 036bd530fc fix(core): worker-count-dependent tiles near passage support columns (L44); random-camera determinism sweep
L27 added passage support columns, but World::isTileShapeFree only bounded the route and bridge, so tiles
touched by a column could be approved for early native-only generation; depending on scheduling they used
that incomplete field or the compiled one (six LOD0 tiles differed between W1 and W12 at an SW camera near
the arrival mouth). The shape-free proof now includes a conservative envelope for every possible column.
The compiled world is unchanged (the old W1 variant), so no version bump. verify tiers gain a seeded
(SplitMix64 0x4c3434) random-camera W1/W8/W12 sweep across both recipes and several clip settings; it fails
before the fix and passes after. fast/medium/full PASS; cost within noise. Research R11: suspect review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-23 23:00:21 +02:00

3925 lines
251 KiB
C++

#pragma once
#include "OwnerWorldLoader.h"
#include "StreamingWorld.h"
#include "LinuxScreenSpaceGate.h"
#include <algorithm>
#include <array>
#include <bit>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <ctime>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <future>
#include <limits>
#include <numeric>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace StandaloneStreamBenchmark
{
struct FRouteDensityComparison
{
std::uint64_t samples=0;
std::uint64_t signMismatches=0;
std::uint64_t crossingEdgeMismatches=0;
std::uint64_t sharedCrossingEdges=0;
std::uint64_t exactQuerySamples=0;
std::uint64_t exactQueryMismatches=0;
double maxAbsoluteDelta=0.0;
double sumAbsoluteDelta=0.0;
double maxSurfaceDisplacementVoxels=0.0;
double sumSurfaceDisplacementVoxels=0.0;
bool valid=false;
};
inline FRouteDensityComparison CompareRouteDensities(
const VoxelForgeCore::TileMesh& A,const VoxelForgeCore::TileMesh& B,
const VoxelForgeCore::World& World)
{
FRouteDensityComparison Result;
if(A.debugDensitySamples.empty()
||A.debugDensitySamples.size()!=B.debugDensitySamples.size())return Result;
const double Root=std::cbrt(static_cast<double>(A.debugDensitySamples.size()));
const std::int32_t Dim=static_cast<std::int32_t>(std::llround(Root));
if(Dim<4||static_cast<std::size_t>(Dim)*Dim*Dim!=A.debugDensitySamples.size())return Result;
const std::int32_t GridDim=Dim-3;
const std::int32_t Extent=CHUNK_SIZE<<A.key.lod;
if(GridDim<=0||Extent%GridDim!=0)return Result;
const std::int32_t Step=Extent/GridDim;
const FVoxelTileKey NativeKey(
FIntVector(A.key.coordinate.x,A.key.coordinate.y,A.key.coordinate.z),A.key.lod);
const FIntVector Origin=NativeKey.OriginVoxels();
const auto Index=[Dim](std::int32_t X,std::int32_t Y,std::int32_t Z)
{return (static_cast<std::size_t>(Z)*Dim+Y)*Dim+X;};
const auto IsSolid=[](float Density){return Density<0.0f;};
const auto EdgeCrosses=[&](const std::vector<float>& Values,
std::int32_t X0,std::int32_t Y0,std::int32_t Z0,
std::int32_t X1,std::int32_t Y1,std::int32_t Z1)
{
return IsSolid(Values[Index(X0,Y0,Z0)])!=IsSolid(Values[Index(X1,Y1,Z1)]);
};
for(std::int32_t Z=0;Z<Dim;++Z)
for(std::int32_t Y=0;Y<Dim;++Y)
for(std::int32_t X=0;X<Dim;++X)
{
const std::size_t I=Index(X,Y,Z);
const float DA=A.debugDensitySamples[I],DB=B.debugDensitySamples[I];
if(!std::isfinite(DA)||!std::isfinite(DB))return Result;
const double Delta=std::abs(static_cast<double>(DA)-DB);
Result.maxAbsoluteDelta=std::max(Result.maxAbsoluteDelta,Delta);
Result.sumAbsoluteDelta+=Delta;
Result.signMismatches+=IsSolid(DA)!=IsSolid(DB)?1u:0u;
++Result.samples;
const std::int32_t WorldX=Origin.X+(X-1)*Step;
const std::int32_t WorldY=Origin.Y+(Y-1)*Step;
const std::int32_t WorldZ=Origin.Z+(Z-1)*Step;
const VoxelForgeCore::Vec3i Lattice{WorldX,WorldY,WorldZ};
const float ExactLattice=World.densityAtLattice(Lattice);
const float ExactPoint=World.densityAt({static_cast<double>(WorldX),
static_cast<double>(WorldY),static_cast<double>(WorldZ)});
++Result.exactQuerySamples;
if(std::bit_cast<std::uint32_t>(DA)!=std::bit_cast<std::uint32_t>(ExactLattice)
||std::bit_cast<std::uint32_t>(DA)!=std::bit_cast<std::uint32_t>(ExactPoint))
++Result.exactQueryMismatches;
}
const auto CompareEdge=[&](std::int32_t X0,std::int32_t Y0,std::int32_t Z0,
std::int32_t X1,std::int32_t Y1,std::int32_t Z1)
{
const bool CrossA=EdgeCrosses(A.debugDensitySamples,X0,Y0,Z0,X1,Y1,Z1);
const bool CrossB=EdgeCrosses(B.debugDensitySamples,X0,Y0,Z0,X1,Y1,Z1);
if(CrossA!=CrossB)++Result.crossingEdgeMismatches;
if(!CrossA||!CrossB)return;
const float A0=A.debugDensitySamples[Index(X0,Y0,Z0)];
const float A1=A.debugDensitySamples[Index(X1,Y1,Z1)];
const float B0=B.debugDensitySamples[Index(X0,Y0,Z0)];
const float B1=B.debugDensitySamples[Index(X1,Y1,Z1)];
const double TA=static_cast<double>(A0)/(static_cast<double>(A0)-A1);
const double TB=static_cast<double>(B0)/(static_cast<double>(B0)-B1);
const double Displacement=std::abs(TA-TB)*Step;
Result.maxSurfaceDisplacementVoxels=std::max(
Result.maxSurfaceDisplacementVoxels,Displacement);
Result.sumSurfaceDisplacementVoxels+=Displacement;
++Result.sharedCrossingEdges;
};
for(std::int32_t Z=0;Z<Dim;++Z)
for(std::int32_t Y=0;Y<Dim;++Y)
for(std::int32_t X=0;X<Dim;++X)
{
if(X+1<Dim)CompareEdge(X,Y,Z,X+1,Y,Z);
if(Y+1<Dim)CompareEdge(X,Y,Z,X,Y+1,Z);
if(Z+1<Dim)CompareEdge(X,Y,Z,X,Y,Z+1);
}
Result.valid=true;
return Result;
}
inline bool SameTileOutput(const VoxelForgeCore::TileMesh& A,
const VoxelForgeCore::TileMesh& B)
{
return A.hasDensityHash&&B.hasDensityHash&&A.hasMeshHash&&B.hasMeshHash
&&A.hasPayloadHash&&B.hasPayloadHash&&A.hasTopologyHash&&B.hasTopologyHash
&&A.densityHash==B.densityHash&&A.meshHash==B.meshHash
&&A.payloadHash==B.payloadHash&&A.topologyHash==B.topologyHash;
}
struct FSceneExportWriter
{
std::ofstream File;
bool bGood=true;
std::uint32_t TileCount=0;
template<typename T> void Write(const T& Value)
{
File.write(reinterpret_cast<const char*>(&Value),sizeof(Value));
bGood=bGood&&static_cast<bool>(File);
}
bool Open(const std::filesystem::path& Path,std::uint32_t VoxelSizeMicrons,
const FVector& CameraVoxels,float YawDegrees,float PitchDegrees,
std::uint32_t ExpectedTiles)
{
std::error_code Error;
if(!Path.parent_path().empty())
std::filesystem::create_directories(Path.parent_path(),Error);
if(Error)return false;
File.open(Path,std::ios::binary|std::ios::trunc);
if(!File)return false;
constexpr char Magic[8]={'V','F','M','S','H','0','0','1'};
File.write(Magic,sizeof(Magic));
const std::uint32_t Version=1;
Write(Version);Write(VoxelSizeMicrons);Write(ExpectedTiles);
const double MicronsToMeters=static_cast<double>(VoxelSizeMicrons)/1000000.0;
const double Camera[3]={CameraVoxels.X*MicronsToMeters,
CameraVoxels.Y*MicronsToMeters,CameraVoxels.Z*MicronsToMeters};
for(const double Value:Camera)Write(Value);
const double Yaw=YawDegrees,Pitch=PitchDegrees;
Write(Yaw);Write(Pitch);
return bGood;
}
void Add(const FStandaloneCpuTile& Tile)
{
const std::int32_t Key[4]={Tile.Key.Coord.X,Tile.Key.Coord.Y,
Tile.Key.Coord.Z,Tile.Key.Level};
for(const auto Value:Key)Write(Value);
const std::uint32_t SurfaceVertexCount=Tile.SurfaceVertexCount;
const std::uint32_t SkirtTriangleCount=Tile.SkirtTriangleCount;
const std::uint32_t VertexCount=static_cast<std::uint32_t>(Tile.Vertices.size());
const std::uint32_t IndexCount=static_cast<std::uint32_t>(Tile.Indices.size());
const std::uint32_t MaskCount=static_cast<std::uint32_t>(Tile.TriangleSkirtFaceMasks.size());
Write(SurfaceVertexCount);Write(SkirtTriangleCount);
Write(VertexCount);Write(IndexCount);Write(MaskCount);
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
for(const float Value:Vertex.Position)Write(Value);
for(const FStandaloneCpuVertex& Vertex:Tile.Vertices)
for(const float Value:Vertex.Normal)Write(Value);
if(IndexCount)
File.write(reinterpret_cast<const char*>(Tile.Indices.data()),
static_cast<std::streamsize>(sizeof(std::uint32_t)*Tile.Indices.size()));
if(MaskCount)
File.write(reinterpret_cast<const char*>(Tile.TriangleSkirtFaceMasks.data()),
static_cast<std::streamsize>(Tile.TriangleSkirtFaceMasks.size()));
bGood=bGood&&static_cast<bool>(File);
++TileCount;
}
bool Close(std::uint32_t ExpectedTiles)
{
File.flush();
const bool bComplete=bGood&&static_cast<bool>(File)&&TileCount==ExpectedTiles;
File.close();
return bComplete;
}
};
inline void HashWord(uint64& Hash,uint64 Word,int32 Bytes=8)
{
for(int32 I=0;I<Bytes;++I)
{
Hash^=static_cast<uint8>(Word>>(I*8));
Hash*=1099511628211ull;
}
}
struct FHashedTile
{
FVoxelTileKey Key;
uint64 Hash=14695981039346656037ull;
};
inline bool TileKeyLessForHash(const FVoxelTileKey& A,const FVoxelTileKey& B)
{
if(A.Level!=B.Level)return A.Level<B.Level;
if(A.Coord.Z!=B.Coord.Z)return A.Coord.Z<B.Coord.Z;
if(A.Coord.Y!=B.Coord.Y)return A.Coord.Y<B.Coord.Y;
return A.Coord.X<B.Coord.X;
}
inline uint64 HashTileRows(std::vector<FHashedTile>& Rows)
{
std::sort(Rows.begin(),Rows.end(),[](const FHashedTile& A,const FHashedTile& B)
{return TileKeyLessForHash(A.Key,B.Key);});
uint64 Hash=14695981039346656037ull;
for(const FHashedTile& Row:Rows)
{
HashWord(Hash,static_cast<uint32>(Row.Key.Level),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.X),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Y),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Z),4);
HashWord(Hash,Row.Hash);
}
return Hash;
}
inline bool AuditResolvedStrateTransitions(const VoxelForgeCore::World& Field,
const FStandaloneOwnerWorld& Owner,
const VoxelForgeCore::ResolvedLayoutSnapshotV3& Layout)
{
constexpr std::int64_t XYExtentMicrometres=256000000;
constexpr std::int64_t XYStepMicrometres=8000000;
const std::int64_t coreMicrometres=std::max<std::uint32_t>(1,Owner.CoreVoxelSizeMicrons);
const std::int64_t zStepMicrometres=std::max<std::int64_t>(1,coreMicrometres/2);
const std::int64_t minimumBandMicrometres=2*coreMicrometres;
std::uint64_t interfacesPassed=0,totalColumns=0,passageColumnsSkipped=0;
std::uint64_t holeColumns=0,airSamples=0,solidSamples=0;
bool negativeWidthRejected=false,negativeThinBandRejected=false;
for(std::size_t interfaceIndex=0;interfaceIndex+1<Layout.strates.size();++interfaceIndex)
{
const auto& upper=Layout.strates[interfaceIndex];
const auto& lower=Layout.strates[interfaceIndex+1];
std::int64_t minimumOffset=std::numeric_limits<std::int64_t>::max();
std::int64_t maximumOffset=std::numeric_limits<std::int64_t>::min();
std::int64_t maximumCrossingDepth=0;
std::int64_t minimumUpperThickness=std::numeric_limits<std::int64_t>::max();
std::int64_t minimumLowerThickness=std::numeric_limits<std::int64_t>::max();
std::uint64_t columns=0,skipped=0,holes=0,air=0,solid=0;
bool firstHoleReported=false;
const std::int64_t seam=upper.bedrock.bottomMicrometres;
const auto passageCoversColumn=[&](std::int64_t xUm,std::int64_t yUm,
std::int64_t zMinimumUm,std::int64_t zMaximumUm)
{
constexpr double Q=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
for(const auto& passage:Layout.passages)
{
if(passage.upperStrateIndex!=upper.strateIndex
||passage.lowerStrateIndex!=lower.strateIndex)continue;
for(std::size_t pointIndex=1;pointIndex<passage.controlPoints.size();++pointIndex)
{
const auto& a=passage.controlPoints[pointIndex-1];
const auto& b=passage.controlPoints[pointIndex];
const double ax=a.positionSubvoxels[0]*coreMicrometres/Q;
const double ay=a.positionSubvoxels[1]*coreMicrometres/Q;
const double az=a.positionSubvoxels[2]*coreMicrometres/Q;
const double bx=b.positionSubvoxels[0]*coreMicrometres/Q;
const double by=b.positionSubvoxels[1]*coreMicrometres/Q;
const double bz=b.positionSubvoxels[2]*coreMicrometres/Q;
const double radius=std::max(a.radiusSubvoxels,b.radiusSubvoxels)
*coreMicrometres/Q+750000.0;
if(std::max(az,bz)+radius<zMinimumUm
||std::min(az,bz)-radius>zMaximumUm)continue;
const double dx=bx-ax,dy=by-ay;
const double lengthSquared=dx*dx+dy*dy;
const double t=lengthSquared>0.0
?std::clamp(((xUm-ax)*dx+(yUm-ay)*dy)/lengthSquared,0.0,1.0):0.0;
const double ex=xUm-(ax+t*dx),ey=yUm-(ay+t*dy);
if(ex*ex+ey*ey<=radius*radius)return true;
}
}
return false;
};
for(std::int64_t iy=-XYExtentMicrometres/XYStepMicrometres;
iy<=XYExtentMicrometres/XYStepMicrometres;++iy)
for(std::int64_t ix=-XYExtentMicrometres/XYStepMicrometres;
ix<=XYExtentMicrometres/XYStepMicrometres;++ix)
{
const std::int64_t xUm=ix*XYStepMicrometres;
const std::int64_t yUm=iy*XYStepMicrometres;
const auto bands=VoxelForgeCore::EvaluateResolvedLayoutTransitionBandsV1(
upper,lower,Owner.Seed,Layout.strateLayoutChunkSizeMicrometres,xUm,yUm);
const std::int64_t offset=bands.upperBedrockBottomMicrometres-seam;
minimumOffset=std::min(minimumOffset,offset);
maximumOffset=std::max(maximumOffset,offset);
maximumCrossingDepth=std::max(maximumCrossingDepth,
bands.crossingDepthMicrometres);
minimumUpperThickness=std::min(minimumUpperThickness,
bands.upperBedrockTopMicrometres-bands.upperBedrockBottomMicrometres);
minimumLowerThickness=std::min(minimumLowerThickness,
bands.lowerCeilingTopMicrometres-bands.lowerCeilingBottomMicrometres);
const std::int64_t zMinimum=std::min(bands.upperBedrockBottomMicrometres,
bands.lowerCeilingBottomMicrometres);
const std::int64_t zMaximum=std::max(bands.upperBedrockTopMicrometres,
bands.lowerCeilingTopMicrometres);
if(passageCoversColumn(xUm,yUm,zMinimum,zMaximum)){++skipped;continue;}
++columns;
bool hasHole=false;
for(std::int64_t zUm=zMinimum+zStepMicrometres/2;
zUm<zMaximum-zStepMicrometres/2;zUm+=zStepMicrometres)
{
const VoxelForgeCore::Vec3d point{
static_cast<double>(xUm)/coreMicrometres,
static_cast<double>(yUm)/coreMicrometres,
static_cast<double>(zUm)/coreMicrometres};
const float density=Field.densityAt(point);
if(!std::isfinite(density)||density>=0.0f)
{
if(!firstHoleReported)
{
std::printf("[StrateTransitionFirstHole] x_um=%lld y_um=%lld z_um=%lld z_min_um=%lld z_max_um=%lld density=%.9g dispatch=%s\n",
static_cast<long long>(xUm),static_cast<long long>(yUm),
static_cast<long long>(zUm),static_cast<long long>(zMinimum),
static_cast<long long>(zMaximum),density,
Field.densityDispatchPathAt(point).c_str());
firstHoleReported=true;
}
hasHole=true;++air;
}
else ++solid;
}
if(hasHole)++holes;
}
const std::int64_t boundaryPeakToPeak=maximumOffset-minimumOffset;
const std::int64_t allowedWidth=upper.transitionMode=="Hard"
||upper.transitionFallsBackToHard?0:upper.transitionWidthMicrometres;
if(interfaceIndex==0)
{
auto wide=Layout;
wide.strates[0].transitionMode="Interleaved";
wide.strates[0].transitionFallsBackToHard=false;
wide.strates[0].transitionWidthMicrometres=8000000;
wide.strates[0].transitionInterpenetrationMicrometres=8000001;
std::vector<VoxelForgeCore::ResolvedLayoutIssueV2> issues;
std::string error;
negativeWidthRejected=!wide.validate(
VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,issues,error);
auto thin=Layout;
auto& bedrock=thin.strates[0].bedrock;
bedrock.topMicrometres=bedrock.bottomMicrometres+minimumBandMicrometres-1;
thin.strates[0].content.bottomMicrometres=bedrock.topMicrometres;
negativeThinBandRejected=!thin.validate(
VoxelForgeCore::ResolvedLayoutValidationModeV3::strict,issues,error);
}
const bool passed=columns>0&&holes==0&&maximumCrossingDepth<=allowedWidth
&&minimumUpperThickness>=minimumBandMicrometres
&&minimumLowerThickness>=minimumBandMicrometres;
interfacesPassed+=passed?1u:0u;
totalColumns+=columns;passageColumnsSkipped+=skipped;
holeColumns+=holes;airSamples+=air;solidSamples+=solid;
std::printf("[StrateTransitionInterface] upper=%d lower=%d mode=%s width_um=%lld max_crossing_depth_um=%lld boundary_peak_to_peak_um=%lld allowed_um=%lld upper_min_band_um=%lld lower_min_band_um=%lld columns=%llu passage_columns=%llu hole_columns=%llu air_samples=%llu status=%s\n",
upper.strateIndex,lower.strateIndex,upper.transitionMode.c_str(),
static_cast<long long>(upper.transitionWidthMicrometres),
static_cast<long long>(maximumCrossingDepth),
static_cast<long long>(boundaryPeakToPeak),static_cast<long long>(allowedWidth),
static_cast<long long>(minimumUpperThickness),static_cast<long long>(minimumLowerThickness),
static_cast<unsigned long long>(columns),static_cast<unsigned long long>(skipped),
static_cast<unsigned long long>(holes),static_cast<unsigned long long>(air),
passed?"PASS":"FAIL");
}
const bool controlsPassed=negativeWidthRejected&&negativeThinBandRejected;
std::printf("[StrateTransitionNegativeControls] wider_than_declared=%s thinner_than_minimum=%s minimum_band_um=%lld status=%s\n",
negativeWidthRejected?"REJECTED":"ACCEPTED",
negativeThinBandRejected?"REJECTED":"ACCEPTED",
static_cast<long long>(minimumBandMicrometres),controlsPassed?"PASS":"FAIL");
const bool passed=!Layout.strates.empty()&&interfacesPassed+1==Layout.strates.size()
&&holeColumns==0&&airSamples==0&&controlsPassed;
std::printf("[StrateTransitionAuditSummary] interfaces=%llu passed=%llu columns=%llu skipped_passage_columns=%llu hole_columns=%llu air_samples=%llu solid_samples=%llu status=%s\n",
static_cast<unsigned long long>(Layout.strates.size()-1),
static_cast<unsigned long long>(interfacesPassed),
static_cast<unsigned long long>(totalColumns),
static_cast<unsigned long long>(passageColumnsSkipped),
static_cast<unsigned long long>(holeColumns),
static_cast<unsigned long long>(airSamples),
static_cast<unsigned long long>(solidSamples),passed?"PASS":"FAIL");
return passed;
}
inline int RunPipelinedStreamingBenchmark(std::shared_ptr<FStandaloneOwnerWorld> OwnerWorld,
const VoxelForgeCore::ResolvedWorldSnapshot& CoreSnapshot,
const FVector& CameraPositionVoxels,int32 WorkerCount,int32 MaxLevel,
VoxelForgeCore::DetailVariant DetailVariant,const VoxelForgeCore::JobScheduler& Scheduler,
bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,bool bSkipUV,bool bSkipColors,
std::chrono::steady_clock::time_point ColdStart,bool bProfileColumnOverlap,
int32 FarHorizonLOD8InteriorStepVoxels,bool bReportMeshCoverage=false,
const std::filesystem::path& MeshExportPath={},float CameraYawDegrees=0.0f,
float CameraPitchDegrees=0.0f,bool bScreenSpaceGate=false,
bool bUseSharedColumnCache=true,FVector CameraStepVoxels=FVector::ZeroVector,
bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false,
bool bRegionCrossing=false,
bool bAuditTileShapeReadiness=false,int DiagnosticSlowShapeCompileMs=0,
bool bAuditBasePageEquivalence=false,bool bAuditRouteParity=false,
bool bAuditResolvedLayoutBoundaries=false,
bool bAuditResolvedLayoutPassages=false,
bool bAuditStrateTransitions=false,
const VoxelForgeCore::ResolvedLayoutSnapshotV3* ResolvedLayout=nullptr,
bool bPrintTileHashes=false)
{
using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld;
const VoxelForgeCore::WorldAssemblyManifest* Assembly=CoreSnapshot.worldAssembly();
std::array<double,9> ClosestDisplayDistances{};
std::array<std::int64_t,9> PixelBudgetsSubvoxels{};
if(bScreenSpaceGate)
{
ClosestDisplayDistances=StandaloneScreenSpaceGate::ClosestDisplayedDistancesMeters(
World,CameraPositionVoxels,World.CoreVoxelSizeMicrons);
const double VoxelMeters=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
for(int32 Lod=3;Lod<=World.MaxClipLevel&&Lod<9;++Lod)
PixelBudgetsSubvoxels[static_cast<std::size_t>(Lod)]=static_cast<std::int64_t>(std::floor(
ClosestDisplayDistances[static_cast<std::size_t>(Lod)]
*StandaloneScreenSpaceGate::OnePixelRadians/VoxelMeters
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
}
const bool bRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels;
const bool bEnhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls;
VoxelForgeCore::World Shape(CoreSnapshot);
FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels);
const auto CoreTiles=Shape.desiredTiles(
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z});
Desired.Tiles.clear();Desired.Tiles.reserve(CoreTiles.size());
for(const auto& Key:CoreTiles)
Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
if(MaxLevel>=0)
Desired.Tiles.erase(std::remove_if(Desired.Tiles.begin(),Desired.Tiles.end(),
[&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),Desired.Tiles.end());
const bool bHasCameraStep=std::abs(CameraStepVoxels.X)+std::abs(CameraStepVoxels.Y)
+std::abs(CameraStepVoxels.Z)>1.0e-6f;
FStandaloneDesiredTileSet MovedDesired;
if(bHasCameraStep)
{
const FVector MovedCamera=CameraPositionVoxels+CameraStepVoxels;
MovedDesired=StandaloneWorldMesher::BuildDesiredSet(World,MovedCamera);
const auto MovedCoreTiles=Shape.desiredTiles({MovedCamera.X,MovedCamera.Y,MovedCamera.Z});
MovedDesired.Tiles.clear();MovedDesired.Tiles.reserve(MovedCoreTiles.size());
for(const auto& Key:MovedCoreTiles)
MovedDesired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
if(MaxLevel>=0)
MovedDesired.Tiles.erase(std::remove_if(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),MovedDesired.Tiles.end());
}
if(!Desired.Tiles.empty())
{
FIntVector volumeMin(INT32_MAX,INT32_MAX,INT32_MAX);
FIntVector volumeMax(INT32_MIN,INT32_MIN,INT32_MIN);
int32 minimumLod=INT32_MAX,maximumLod=INT32_MIN;
for(const FVoxelTileKey& tile:Desired.Tiles)
{
const FIntVector origin=tile.OriginVoxels();
const int32 extent=tile.ExtentVoxels();
volumeMin.X=std::min(volumeMin.X,origin.X);
volumeMin.Y=std::min(volumeMin.Y,origin.Y);
volumeMin.Z=std::min(volumeMin.Z,origin.Z);
volumeMax.X=std::max(volumeMax.X,origin.X+extent);
volumeMax.Y=std::max(volumeMax.Y,origin.Y+extent);
volumeMax.Z=std::max(volumeMax.Z,origin.Z+extent);
minimumLod=std::min(minimumLod,tile.Level);
maximumLod=std::max(maximumLod,tile.Level);
}
std::printf("[PipelineVolume] tiles=%zu lod=%d..%d min_voxel=(%d,%d,%d) max_voxel=(%d,%d,%d)\n",
Desired.Tiles.size(),minimumLod,maximumLod,volumeMin.X,volumeMin.Y,volumeMin.Z,
volumeMax.X,volumeMax.Y,volumeMax.Z);
}
FIntVector FineMin(INT32_MAX,INT32_MAX,INT32_MAX),FineMax(INT32_MIN,INT32_MIN,INT32_MIN);
FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN);
const auto AccumulateBounds=[&](const std::vector<FVoxelTileKey>& Tiles)
{
for(const FVoxelTileKey& Tile:Tiles)
{
const FIntVector Origin=Tile.OriginVoxels();const int32 Extent=Tile.ExtentVoxels();
ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z);
ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent);
if(Tile.Level<World.FullResClipLevels)
{
FineMin.X=std::min(FineMin.X,Origin.X);FineMin.Y=std::min(FineMin.Y,Origin.Y);FineMin.Z=std::min(FineMin.Z,Origin.Z);
FineMax.X=std::max(FineMax.X,Origin.X+Extent);FineMax.Y=std::max(FineMax.Y,Origin.Y+Extent);FineMax.Z=std::max(FineMax.Z,Origin.Z+Extent);
}
}
};
AccumulateBounds(Desired.Tiles);
if(bHasCameraStep&&!bRegionCrossing)AccumulateBounds(MovedDesired.Tiles);
if(FineMin.X==INT32_MAX||ClipMin.X==INT32_MAX)
{std::fprintf(stderr,"[StreamPipeline] no desired detail or clipmap tiles.\n");return 7;}
const FIntVector CenterChunk=Desired.CenterChunk;
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> Neighborhood;
Neighborhood.reserve(32);
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level==0&&std::abs(Tile.Coord.X-CenterChunk.X)<=1
&&std::abs(Tile.Coord.Y-CenterChunk.Y)<=1&&std::abs(Tile.Coord.Z-CenterChunk.Z)<=1)
Neighborhood.insert(Tile);
if(Neighborhood.size()!=27)
{std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;}
FStandaloneDesiredTileSet ShapeFreeDesired=Desired;
ShapeFreeDesired.Tiles.clear();
std::vector<FVoxelTileKey> ShapeFreeTiles;
ShapeFreeTiles.reserve(Neighborhood.size());
int32 ShapeFreeNeighborhood=0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey CoreKey{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
if(!Shape.isTileShapeFree(CoreKey))continue;
ShapeFreeDesired.Tiles.push_back(Tile);
ShapeFreeTiles.push_back(Tile);
if(Neighborhood.contains(Tile))++ShapeFreeNeighborhood;
}
if(bAuditTileShapeReadiness)
{
FVoxelTileKey DeliberatelyWrong(FIntVector(0,0,31250),0);
for(int32 Z=100000;Z<100100;++Z)
{
DeliberatelyWrong=FVoxelTileKey(FIntVector(0,0,Z),0);
if(!Shape.isTileShapeFree({{0,0,Z},0}))break;
}
VoxelForgeCore::TileGenerationOptions NegativeControlOptions;
NegativeControlOptions.diagnosticForceNativeOnly=true;
std::string NegativeControlError;
const auto MisMarked=Shape.generateTile(
{{DeliberatelyWrong.Coord.X,DeliberatelyWrong.Coord.Y,DeliberatelyWrong.Coord.Z},0},
NegativeControlOptions,NegativeControlError);
const bool bGuardCaught=!MisMarked
&&NegativeControlError.find("shape-free guard")!=std::string::npos;
std::printf("[ShapeReadinessNegativeControl] deliberately_mismarked=(%d,%d,%d,lod0) result=%s guard_caught=%d error=%s\n",
DeliberatelyWrong.Coord.X,DeliberatelyWrong.Coord.Y,DeliberatelyWrong.Coord.Z,
MisMarked?"generated":"rejected",bGuardCaught?1:0,
NegativeControlError.c_str());
if(!bGuardCaught)
{std::fprintf(stderr,"[StreamPipeline] shape-free guard did not reject the deliberately mis-marked tile.\n");return 9;}
}
std::printf("[ShapeReadiness] shape_free_desired=%zu/%zu near_ring=%d/27 proof=single_SurfaceWorld_plan_no_features_routes_passages_edits_or_owner_primitive_overlap\n",
ShapeFreeTiles.size(),Desired.Tiles.size(),ShapeFreeNeighborhood);
// The initial desired set now owns all clipmap metadata needed by this Core-only run.
// Release the separate compatibility-world generation graph before compiling Core.
World.Generator.reset();
World.Manager.reset();
World.DefinitionStorage.clear();
World.BiomeStorage.clear();
World.OperationStorage.clear();
World.DensitySamples.clear();
const bool bIncludeFarWorld=MaxLevel<0||MaxLevel>=World.FullResClipLevels;
VoxelForgeCore::ShapeBuildRequest ShapeRequest;
ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z};
ShapeRequest.maxVoxel={FineMax.X,FineMax.Y,FineMax.Z};
ShapeRequest.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z};
ShapeRequest.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z};
ShapeRequest.workerLimit=static_cast<uint32>(std::clamp(WorkerCount,1,16));
ShapeRequest.detail=DetailVariant;ShapeRequest.includeFarWorld=bIncludeFarWorld;
ShapeRequest.roundTunnels=bRoundTunnels;
ShapeRequest.enhancedTunnelWalls=bEnhancedTunnelWalls;
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache);
Streamer.SetUniformBlockProofAuditEnabled(bAuditUniformBlockProofs);
if(bScreenSpaceGate||bReportLodWorkProfile)Streamer.SetMesherStageProfilingEnabled(true);
const auto StreamStart=Clock::now();
const FStandaloneStreamingUpdate EarlyUpdate=Streamer.StartWithDesired(ShapeFreeDesired);
if(EarlyUpdate.DesiredTiles!=static_cast<int32>(ShapeFreeDesired.Tiles.size()))
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] expected %zu shape-free tiles but queued %d.\n",
ShapeFreeDesired.Tiles.size(),EarlyUpdate.DesiredTiles);return 7;
}
const auto ShapeBuildStart=Clock::now();
auto ShapeBuildFuture=std::async(std::launch::async,
[&Shape,&Scheduler,ShapeRequest,DiagnosticSlowShapeCompileMs]() mutable
{
if(DiagnosticSlowShapeCompileMs>0)
std::this_thread::sleep_for(std::chrono::milliseconds(DiagnosticSlowShapeCompileMs));
std::string Error;
const bool bCompiled=Shape.compile(ShapeRequest,Scheduler,Error);
return std::pair<bool,std::string>{bCompiled,std::move(Error)};
});
const auto [bShapeCompiled,BuildError]=ShapeBuildFuture.get();
if(!bShapeCompiled)
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;
}
if(bAuditStrateTransitions)
{
if(ResolvedLayout==nullptr||!CoreSnapshot.resolvedLayout())
{Streamer.Stop();std::fprintf(stderr,"[StrateTransitionAudit] missing resolved-layout snapshot\n");return 2;}
const bool passed=AuditResolvedStrateTransitions(Shape,World,*ResolvedLayout);
Streamer.Stop();
return passed?0:11;
}
if(bAuditResolvedLayoutPassages)
{
if(ResolvedLayout==nullptr||!CoreSnapshot.resolvedLayout())
{Streamer.Stop();std::fprintf(stderr,"[ResolvedPassageAudit] missing resolved-layout snapshot\n");return 2;}
struct FWalkAudit
{
std::uint64_t segments=0,centers=0,capsuleSamples=0,blocked=0;
std::uint64_t supportSamples=0,unsupported=0,gradeFailures=0;
std::array<std::array<double,4>,8> firstBlocked{};
std::array<std::array<double,4>,8> firstUnsupported{};
std::array<std::array<bool,5>,8> firstSupportMasks{};
std::size_t firstBlockedCount=0,firstUnsupportedCount=0;
std::array<double,4> firstDeepUnsupported{};
std::array<bool,5> firstDeepSupportMask{};
bool hasDeepUnsupported=false;
bool passed=false;
};
struct FPassageSegmentSupportAudit
{
std::uint64_t centers=0,unsupported=0,nativeUnsupported=0;
std::array<double,3> firstUnsupported{};
std::array<double,4> firstNativeDensities{};
std::uint32_t firstNativeSupportedProbes=0;
bool hasUnsupported=false;
};
const double coreMetres=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
const auto auditPlayerPath=[&](const VoxelForgeCore::World& Field,
const std::vector<std::array<double,3>>& path,
double supportStartMetres,double supportStepMetres,
double supportMaximumMetres,std::uint32_t minimumSupportProbes,
double supportProbeRadiusMetres,
const VoxelForgeCore::World* nativeField=nullptr,
std::vector<FPassageSegmentSupportAudit>* segmentSupport=nullptr)
{
FWalkAudit audit;
if(path.size()<2)return audit;
if(segmentSupport)segmentSupport->assign(path.size()-1,{});
constexpr std::array<double,7> heights{{-0.84,-0.60,-0.30,0.0,0.30,0.60,0.84}};
constexpr std::array<std::array<double,2>,8> directions{{
{{1.0,0.0}},{{0.7071067811865475,0.7071067811865475}},{{0.0,1.0}},
{{-0.7071067811865475,0.7071067811865475}},{{-1.0,0.0}},
{{-0.7071067811865475,-0.7071067811865475}},{{0.0,-1.0}},
{{0.7071067811865475,-0.7071067811865475}}}};
const auto solidAt=[&](double xMetres,double yMetres,double zMetres)
{
++audit.capsuleSamples;
const VoxelForgeCore::Vec3d position{xMetres/coreMetres,yMetres/coreMetres,zMetres/coreMetres};
const float density=Field.densityAt(position);
if(density<0.0f)
{
if(audit.firstBlockedCount<audit.firstBlocked.size())
{
audit.firstBlocked[audit.firstBlockedCount++]={xMetres,yMetres,zMetres,density};
std::printf("[ResolvedWalkDispatch] kind=blocked xyz_m=(%.3f,%.3f,%.3f) path=%s\n",
xMetres,yMetres,zMetres,Field.densityDispatchPathAt(position).c_str());
}
++audit.blocked;return true;
}
return false;
};
for(std::size_t segment=1;segment<path.size();++segment)
{
++audit.segments;
const auto& a=path[segment-1];const auto& b=path[segment];
const double dx=b[0]-a[0],dy=b[1]-a[1],dz=b[2]-a[2];
const double horizontal=std::hypot(dx,dy)*coreMetres;
const double vertical=std::abs(dz)*coreMetres;
if(horizontal<=1.0e-6||vertical>horizontal*0.2679491924311227)
++audit.gradeFailures;
const double length=std::sqrt(dx*dx+dy*dy+dz*dz)*coreMetres;
const std::uint64_t intervals=std::max<std::uint64_t>(1,
static_cast<std::uint64_t>(std::ceil(length/0.5)));
for(std::uint64_t step=0;step<=intervals;++step)
{
if(segment>1&&step==0)continue;
const double t=static_cast<double>(step)/intervals;
const double x=(a[0]+dx*t)*coreMetres;
const double y=(a[1]+dy*t)*coreMetres;
const double z=(a[2]+dz*t)*coreMetres;
++audit.centers;
FPassageSegmentSupportAudit* segmentAudit=segmentSupport
?&(*segmentSupport)[segment-1]:nullptr;
if(segmentAudit)++segmentAudit->centers;
for(const double h:heights)
{
const double capOffset=std::max(0.0,std::abs(h)-0.54);
const double radial=std::abs(h)<=0.54?0.34
:std::sqrt(std::max(0.0,0.34*0.34-capOffset*capOffset));
solidAt(x,y,z+h);
for(const auto& direction:directions)
solidAt(x+direction[0]*radial,y+direction[1]*radial,z+h);
}
const double footZ=z-0.88;
const std::array<std::array<double,2>,5> supportOffsets{{
{{0.0,0.0}},{{supportProbeRadiusMetres,0.0}},
{{-supportProbeRadiusMetres,0.0}},
{{0.0,supportProbeRadiusMetres}},
{{0.0,-supportProbeRadiusMetres}}}};
std::uint32_t supportedProbes=0;
std::uint32_t nativeSupportedProbes=0;
double firstUnsupportedX=x,firstUnsupportedY=y,lastUnsupportedDensity=0.0;
std::array<bool,5> supportMask{};
for(std::size_t offsetIndex=0;offsetIndex<supportOffsets.size();++offsetIndex)
{
const auto& offset=supportOffsets[offsetIndex];
const double supportX=x+offset[0],supportY=y+offset[1];
bool supported=false;
for(double depth=supportStartMetres;
depth<=supportMaximumMetres+1.0e-6;depth+=supportStepMetres)
{
++audit.supportSamples;
lastUnsupportedDensity=Field.densityAt({supportX/coreMetres,
supportY/coreMetres,(footZ-depth)/coreMetres});
if(lastUnsupportedDensity<0.0)
{
supported=true;break;
}
}
if(nativeField)
{
for(double depth=supportStartMetres;
depth<=supportMaximumMetres+1.0e-6;depth+=supportStepMetres)
if(nativeField->densityAt({supportX/coreMetres,
supportY/coreMetres,(footZ-depth)/coreMetres})<0.0f)
{++nativeSupportedProbes;break;}
}
if(supported){++supportedProbes;supportMask[offsetIndex]=true;}
else{firstUnsupportedX=supportX;firstUnsupportedY=supportY;}
}
if(nativeField&&segmentAudit
&&nativeSupportedProbes<minimumSupportProbes)
++segmentAudit->nativeUnsupported;
if(supportedProbes<minimumSupportProbes)
{
++audit.unsupported;
if(segmentAudit)
{
++segmentAudit->unsupported;
if(!segmentAudit->hasUnsupported)
{
segmentAudit->hasUnsupported=true;
segmentAudit->firstUnsupported={x,y,footZ};
segmentAudit->firstNativeSupportedProbes=nativeSupportedProbes;
if(nativeField)
{
constexpr std::array<double,4> depths{{0.125,1.0,2.0,4.0}};
for(std::size_t depthIndex=0;depthIndex<depths.size();++depthIndex)
segmentAudit->firstNativeDensities[depthIndex]=nativeField->densityAt({
x/coreMetres,y/coreMetres,
(footZ-depths[depthIndex])/coreMetres});
}
}
}
if(!audit.hasDeepUnsupported&&footZ<-80.0)
{
audit.hasDeepUnsupported=true;
audit.firstDeepUnsupported={firstUnsupportedX,firstUnsupportedY,
footZ,lastUnsupportedDensity};
audit.firstDeepSupportMask=supportMask;
}
if(audit.firstUnsupportedCount<audit.firstUnsupported.size())
{
const std::size_t sample=audit.firstUnsupportedCount++;
audit.firstUnsupported[sample]={
firstUnsupportedX,firstUnsupportedY,footZ,lastUnsupportedDensity};
audit.firstSupportMasks[sample]=supportMask;
std::printf("[ResolvedWalkDispatch] kind=unsupported xyz_m=(%.3f,%.3f,%.3f) support_probes=%u/5 mask=%d%d%d%d%d path=%s\n",
firstUnsupportedX,firstUnsupportedY,footZ,supportedProbes,
supportMask[0],supportMask[1],supportMask[2],supportMask[3],supportMask[4],
Field.densityDispatchPathAt({firstUnsupportedX/coreMetres,
firstUnsupportedY/coreMetres,footZ/coreMetres}).c_str());
}
}
}
}
audit.passed=audit.centers>0&&audit.blocked==0&&audit.unsupported==0
&&audit.gradeFailures==0;
return audit;
};
const auto qToMetres=[&](std::int64_t q)
{return static_cast<double>(q)*World.CoreVoxelSizeMicrons
/(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel*1000000.0);};
struct FPassageNaturalnessAudit
{
double maximumFlatRunMetres=0.0;
double wallReliefPeakToPeakMetres=0.0;
std::uint64_t wallSamples=0,missingWallSamples=0;
bool passed=false;
};
struct FPassageMouthProfileAudit
{
double floorFlatStepRunMetres=0.0,floorStepMetres=0.0;
double wallFlatStepRunMetres=0.0,wallStepMetres=0.0;
std::uint64_t floorSamples=0,wallSamples=0,missingFloorSamples=0,missingWallSamples=0;
bool passed=false;
};
struct FPassageRippleAudit
{
double periodMetres=0.0,amplitudeMetres=0.0,localPeakAmplitudeMetres=0.0;
double coherentPeriodMetres=0.0,coherentAmplitudeMetres=0.0;
double controlAmplitudeMetres=0.0;
double floorPeriodMetres=0.0,floorAmplitudeMetres=0.0;
double floorControlAmplitudeMetres=0.0;
double floorCoherentPeriodMetres=0.0,floorCoherentAmplitudeMetres=0.0;
std::vector<std::array<double,6>> floorPeakProfile;
double floorPeakWindowStartMetres=0.0;
std::uint64_t samples=0,expectedSamples=0;
std::uint64_t floorSamples=0,floorExpectedSamples=0;
bool controlDetected=false,passed=false;
bool floorControlDetected=false;
};
constexpr double MaximumFlatRunMetres=8.0;
constexpr double MinimumWallReliefMetres=0.20;
constexpr double PassageProfileSpacingMetres=0.125;
constexpr double PassageProfilePlateauMinimumMetres=0.50;
constexpr double PassageProfilePlateauEpsilonMetres=0.020;
constexpr double PassageProfileStepThresholdMetres=0.100;
constexpr double PassageMouthProfileReachMetres=12.0;
const auto auditProfilePlateaus=[&](const std::vector<std::array<double,2>>& profile)
{
std::pair<double,double> result{};
if(profile.size()<2)return result;
std::size_t runStart=0;
for(std::size_t i=1;i<profile.size();++i)
{
if(profile[i][0]-profile[i-1][0]
>PassageProfileSpacingMetres*1.5)
{runStart=i;continue;}
if(std::abs(profile[i][1]-profile[runStart][1])
<=PassageProfilePlateauEpsilonMetres)continue;
const double flatLength=profile[i-1][0]-profile[runStart][0];
const double step=std::abs(profile[i][1]-profile[i-1][1]);
if(flatLength>=PassageProfilePlateauMinimumMetres
&&step>=PassageProfileStepThresholdMetres)
{
result.first=std::max(result.first,flatLength);
result.second=std::max(result.second,step);
}
runStart=i;
}
return result;
};
const auto auditPassageMouthProfiles=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageMouthProfileAudit audit;
if(passage.controlPoints.size()<2)return audit;
const std::size_t end=std::min(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
if(end<1)return audit;
struct FProfilePose
{
double distance=0.0,x=0.0,y=0.0,z=0.0,radius=0.0;
};
std::vector<FProfilePose> path;
path.reserve(end*8+1);
double distance=0.0;
for(std::size_t segment=0;segment<end;++segment)
{
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double ar=qToMetres(a.radiusSubvoxels);
const double br=qToMetres(b.radiusSubvoxels);
const double length=std::sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)+(bz-az)*(bz-az));
if(!(length>1.0e-8))continue;
const std::size_t steps=std::max<std::size_t>(1,
static_cast<std::size_t>(std::ceil(length/PassageProfileSpacingMetres)));
for(std::size_t step=segment==0?0:1;step<=steps;++step)
{
const double t=static_cast<double>(step)/steps;
path.push_back({distance+length*t,std::lerp(ax,bx,t),
std::lerp(ay,by,t),std::lerp(az,bz,t),std::lerp(ar,br,t)});
}
distance+=length;
}
if(path.size()<3)return audit;
const double lowerMouthDistance=distance;
constexpr double DensitySearchStepMetres=0.0625;
const auto densityMetres=[&](double x,double y,double z)
{
const float value=Field.densityAt({x/coreMetres,y/coreMetres,z/coreMetres});
return std::isfinite(value)?static_cast<double>(value)*coreMetres
:std::numeric_limits<double>::quiet_NaN();
};
const auto firstFloorCrossing=[&](const FProfilePose& pose,double x,double y)->double
{
const double expectedFloor=pose.z-pose.radius;
const double maximumRise=std::min(2.0*pose.radius-0.25,
std::max(0.75,pose.radius-1.20+0.50));
double previousZ=expectedFloor-1.50;
double previous=densityMetres(x,y,previousZ);
if(!std::isfinite(previous))return std::numeric_limits<double>::quiet_NaN();
double highestFloor=std::numeric_limits<double>::quiet_NaN();
for(double z=previousZ+DensitySearchStepMetres;
z<=expectedFloor+maximumRise+DensitySearchStepMetres*0.25;
z+=DensitySearchStepMetres)
{
const double current=densityMetres(x,y,z);
if(!std::isfinite(current))return std::numeric_limits<double>::quiet_NaN();
if(previous<=0.0&&current>=0.0)
{
const double denominator=current-previous;
const double t=std::abs(denominator)>1.0e-12
?std::clamp(-previous/denominator,0.0,1.0):0.0;
highestFloor=std::lerp(z-DensitySearchStepMetres,z,t);
}
previous=current;
}
return highestFloor;
};
const auto findWallRadius=[&](const FProfilePose& pose,double nx,double ny)
{
const double maximum=pose.radius+2.0;
double previousRadius=0.0;
double previous=densityMetres(pose.x,pose.y,pose.z);
if(!std::isfinite(previous)||previous<0.0)
return std::numeric_limits<double>::quiet_NaN();
for(double radius=DensitySearchStepMetres;radius<=maximum;
radius+=DensitySearchStepMetres)
{
const double current=densityMetres(pose.x+nx*radius,
pose.y+ny*radius,pose.z);
if(!std::isfinite(current))return std::numeric_limits<double>::quiet_NaN();
if(previous>=0.0&&current<=0.0)
{
const double denominator=previous-current;
const double t=std::abs(denominator)>1.0e-12
?std::clamp(previous/denominator,0.0,1.0):0.0;
return std::lerp(previousRadius,radius,t);
}
previous=current;previousRadius=radius;
}
return std::numeric_limits<double>::quiet_NaN();
};
std::array<std::array<std::vector<std::array<double,2>>,3>,2> floorProfiles;
std::array<std::array<std::vector<std::array<double,2>>,2>,2> wallProfiles;
std::array<double,2> endpointFloorCounts{};
for(std::size_t i=0;i<path.size();++i)
{
const auto& pose=path[i];
const bool inUpperWindow=pose.distance<=PassageMouthProfileReachMetres;
const bool inLowerWindow=lowerMouthDistance-pose.distance
<=PassageMouthProfileReachMetres;
if(!inUpperWindow&&!inLowerWindow)continue;
for(std::size_t endpoint=0;endpoint<2;++endpoint)
{
if((endpoint==0&&!inUpperWindow)||(endpoint==1&&!inLowerWindow))continue;
const double localDistance=endpoint==0?pose.distance
:lowerMouthDistance-pose.distance;
const double tangentX=i==0?path[i+1].x-path[i].x
:i+1>=path.size()?path[i].x-path[i-1].x
:path[i+1].x-path[i-1].x;
const double tangentY=i==0?path[i+1].y-path[i].y
:i+1>=path.size()?path[i].y-path[i-1].y
:path[i+1].y-path[i-1].y;
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6)
{audit.missingFloorSamples+=3;audit.missingWallSamples+=2;continue;}
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
for(std::size_t lane=0;lane<3;++lane)
{
const double lateral=lane==0?0.0:lane==1?0.75:-0.75;
const double floor=firstFloorCrossing(pose,
pose.x+nx*lateral,pose.y+ny*lateral);
if(lane!=0&&localDistance>=4.0&&localDistance<=5.5)
std::printf("[PassageMouthProfileProbe] id=%s endpoint=%s d_m=%.3f lane_m=%.2f x_m=%.3f y_m=%.3f route_floor_m=%.3f field_floor_m=%.3f\n",
passage.stableId.c_str(),endpoint==0?"upper":"lower",
localDistance,lateral,pose.x+nx*lateral,
pose.y+ny*lateral,pose.z-pose.radius,floor);
if(std::isfinite(floor))
{
floorProfiles[endpoint][lane].push_back({localDistance,floor});
++endpointFloorCounts[endpoint];++audit.floorSamples;
}
else ++audit.missingFloorSamples;
}
if(i%4!=0)continue;
for(std::size_t side=0;side<2;++side)
{
const double sign=side==0?-1.0:1.0;
const double radius=findWallRadius(pose,sign*nx,sign*ny);
if(std::isfinite(radius))
{
wallProfiles[endpoint][side].push_back({localDistance,radius});
++audit.wallSamples;
}
else ++audit.missingWallSamples;
}
}
}
double worstEndpointFloorCoverage=1.0;
for(std::size_t endpoint=0;endpoint<2;++endpoint)
{
for(std::size_t lane=0;lane<3;++lane)
std::sort(floorProfiles[endpoint][lane].begin(),
floorProfiles[endpoint][lane].end(),
[](const auto& a,const auto& b){return a[0]<b[0];});
for(std::size_t side=0;side<2;++side)
std::sort(wallProfiles[endpoint][side].begin(),
wallProfiles[endpoint][side].end(),
[](const auto& a,const auto& b){return a[0]<b[0];});
const double expectedFloor=std::min<double>(path.size(),
PassageMouthProfileReachMetres/PassageProfileSpacingMetres)+1.0;
worstEndpointFloorCoverage=std::min(worstEndpointFloorCoverage,
expectedFloor>0?endpointFloorCounts[endpoint]/expectedFloor:0.0);
// Lateral probes confirm floor coverage, but do not define a longitudinal
// floor profile: the normal rotates around tight bends and can jump across
// unrelated terrain. The centerline is the stable passage-floor trace.
const auto floorStep=auditProfilePlateaus(floorProfiles[endpoint][0]);
audit.floorFlatStepRunMetres=std::max(audit.floorFlatStepRunMetres,
floorStep.first);
audit.floorStepMetres=std::max(audit.floorStepMetres,floorStep.second);
for(std::size_t side=0;side<2;++side)
{
const auto wallStep=auditProfilePlateaus(wallProfiles[endpoint][side]);
audit.wallFlatStepRunMetres=std::max(audit.wallFlatStepRunMetres,wallStep.first);
audit.wallStepMetres=std::max(audit.wallStepMetres,wallStep.second);
}
}
audit.passed=worstEndpointFloorCoverage>=0.75
&&audit.wallSamples>=8
&&audit.floorFlatStepRunMetres==0.0&&audit.wallFlatStepRunMetres==0.0;
return audit;
};
std::vector<std::array<double,2>> l23TerracedControl;
for(std::size_t tread=0;tread<8;++tread)
for(std::size_t sample=0;sample<=16;++sample)
l23TerracedControl.push_back({(tread*16+sample)*PassageProfileSpacingMetres,
static_cast<double>(tread)*0.25});
const auto l23TerraceControlResult=auditProfilePlateaus(l23TerracedControl);
const bool l23TerraceControlDetected=l23TerraceControlResult.first
>=PassageProfilePlateauMinimumMetres
&&l23TerraceControlResult.second>=PassageProfileStepThresholdMetres;
const auto auditPassageNaturalness=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageNaturalnessAudit audit;
const std::size_t end=std::min<std::size_t>(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
double flatRun=0.0;
for(std::size_t i=1;i<=end;++i)
{
const auto& a=passage.controlPoints[i-1];
const auto& b=passage.controlPoints[i];
const double dx=qToMetres(b.positionSubvoxels[0]-a.positionSubvoxels[0]);
const double dy=qToMetres(b.positionSubvoxels[1]-a.positionSubvoxels[1]);
const double floorA=qToMetres(a.positionSubvoxels[2]-a.radiusSubvoxels)+1.13;
const double floorB=qToMetres(b.positionSubvoxels[2]-b.radiusSubvoxels)+1.13;
const double dz=floorB-floorA;
const double horizontal=std::hypot(dx,dy);
if(horizontal>1.0e-6&&std::abs(dz)/horizontal
<std::tan(0.5*3.14159265358979323846/180.0))
{flatRun+=horizontal;audit.maximumFlatRunMetres=std::max(
audit.maximumFlatRunMetres,flatRun);}
else flatRun=0.0;
}
if(end>=6)
{
const std::size_t sampleCount=std::min<std::size_t>(64,end-4);
double minimumRadius=std::numeric_limits<double>::infinity();
double maximumRadius=-std::numeric_limits<double>::infinity();
for(std::size_t sample=0;sample<sampleCount;++sample)
{
const std::size_t index=2+(sample*(end-4))
/std::max<std::size_t>(1,sampleCount-1);
const auto& point=passage.controlPoints[index];
const auto& before=passage.controlPoints[index-1];
const auto& after=passage.controlPoints[index+1];
const double tangentX=qToMetres(after.positionSubvoxels[0]-before.positionSubvoxels[0]);
const double tangentY=qToMetres(after.positionSubvoxels[1]-before.positionSubvoxels[1]);
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6){++audit.missingWallSamples;continue;}
const double radiusMetres=qToMetres(point.radiusSubvoxels);
const double sampleRadius=std::max(0.20,radiusMetres-0.18);
const double centerX=qToMetres(point.positionSubvoxels[0]);
const double centerY=qToMetres(point.positionSubvoxels[1]);
const double centerZ=qToMetres(point.positionSubvoxels[2]);
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
for(const double side:{-1.0,1.0})
{
const VoxelForgeCore::Vec3d probe{
(centerX+side*nx*sampleRadius)/coreMetres,
(centerY+side*ny*sampleRadius)/coreMetres,
centerZ/coreMetres};
const double density=Field.densityAt(probe);
if(!std::isfinite(density)){++audit.missingWallSamples;continue;}
const double densityMetres=density*coreMetres;
if(densityMetres< -0.75||densityMetres>0.75)
{++audit.missingWallSamples;continue;}
// For the carved SDF, r + density is the wall radius. Its
// variation along the passage measures the applied rock relief.
const double wallRadius=sampleRadius+densityMetres;
minimumRadius=std::min(minimumRadius,wallRadius);
maximumRadius=std::max(maximumRadius,wallRadius);
++audit.wallSamples;
}
}
if(audit.wallSamples>0&&std::isfinite(minimumRadius)
&&std::isfinite(maximumRadius))
audit.wallReliefPeakToPeakMetres=maximumRadius-minimumRadius;
}
audit.passed=audit.maximumFlatRunMetres<=MaximumFlatRunMetres
&&audit.wallReliefPeakToPeakMetres>=MinimumWallReliefMetres
&&audit.wallSamples>=8;
return audit;
};
const auto auditPassageRipples=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageRippleAudit audit;
constexpr double SampleSpacingMetres=0.125;
constexpr double WindowLengthMetres=32.0;
constexpr double MinimumPeriodMetres=0.5;
constexpr double MaximumPeriodMetres=8.0;
constexpr double PeriodStepMetres=0.0625;
constexpr double RippleAmplitudeLimitMetres=0.035;
constexpr double FloorRippleAmplitudeLimitMetres=0.015;
struct FPathPoint
{
double x=0.0,y=0.0,z=0.0,radius=0.0,distance=0.0;
};
const std::size_t end=std::min<std::size_t>(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
if(end<2)return audit;
std::vector<FPathPoint> path;
path.reserve(end+1);
for(std::size_t i=0;i<=end;++i)
{
const auto& point=passage.controlPoints[i];
FPathPoint value{qToMetres(point.positionSubvoxels[0]),
qToMetres(point.positionSubvoxels[1]),
qToMetres(point.positionSubvoxels[2]),
qToMetres(point.radiusSubvoxels),0.0};
if(!path.empty())
{
const auto& previous=path.back();
value.distance=previous.distance+std::sqrt(
(value.x-previous.x)*(value.x-previous.x)
+(value.y-previous.y)*(value.y-previous.y)
+(value.z-previous.z)*(value.z-previous.z));
}
path.push_back(value);
}
const double total=path.back().distance;
if(total<WindowLengthMetres)return audit;
const auto interpolate=[&](double distance)
{
distance=std::clamp(distance,0.0,total);
const auto upper=std::lower_bound(path.begin()+1,path.end(),distance,
[](const FPathPoint& point,double value){return point.distance<value;});
const auto& b=*upper;
const auto& a=*(upper-1);
const double length=b.distance-a.distance;
const double t=length>1.0e-9?(distance-a.distance)/length:0.0;
return FPathPoint{std::lerp(a.x,b.x,t),std::lerp(a.y,b.y,t),
std::lerp(a.z,b.z,t),std::lerp(a.radius,b.radius,t),distance};
};
const auto sinusoidAmplitude=[&](const std::vector<std::array<double,2>>& samples,
double& bestPeriod)
{
if(samples.size()<64)return 0.0;
double best=0.0;
for(double period=MinimumPeriodMetres;
period<=MaximumPeriodMetres+1.0e-9;period+=PeriodStepMetres)
{
const double angular=6.2831853071795864769/period;
double cc=0.0,ss=0.0,cs=0.0,yc=0.0,ys=0.0;
for(const auto& sample:samples)
{
const double phase=angular*sample[0];
const double c=std::cos(phase),s=std::sin(phase);
cc+=c*c;ss+=s*s;cs+=c*s;
yc+=sample[1]*c;ys+=sample[1]*s;
}
const double determinant=cc*ss-cs*cs;
if(determinant<=1.0e-9)continue;
const double cosine=(yc*ss-ys*cs)/determinant;
const double sine=(ys*cc-yc*cs)/determinant;
const double amplitude=std::hypot(cosine,sine);
if(amplitude>best){best=amplitude;bestPeriod=period;}
}
return best;
};
const auto appendDetrendedProfile=[&](const std::vector<double>& values,
double startDistance,std::vector<std::array<double,2>>& output)
{
if(values.size()<64)return;
const double meanIndex=0.5*static_cast<double>(values.size()-1);
double mean=0.0,xy=0.0,xx=0.0;
for(double value:values)mean+=value;
mean/=static_cast<double>(values.size());
for(std::size_t i=0;i<values.size();++i)
{
const double x=(static_cast<double>(i)-meanIndex)*SampleSpacingMetres;
xy+=x*(values[i]-mean);xx+=x*x;
}
const double slope=xx>0.0?xy/xx:0.0;
for(std::size_t i=0;i<values.size();++i)
{
const double x=(static_cast<double>(i)-meanIndex)*SampleSpacingMetres;
output.push_back({startDistance+static_cast<double>(i)*SampleSpacingMetres,
values[i]-mean-slope*x});
}
};
const auto appendDetrendedPairs=[](
const std::vector<std::array<double,2>>& values,
std::vector<std::array<double,2>>& output)
{
if(values.size()<64)return;
double meanX=0.0,meanY=0.0;
for(const auto& value:values){meanX+=value[0];meanY+=value[1];}
meanX/=static_cast<double>(values.size());
meanY/=static_cast<double>(values.size());
double xy=0.0,xx=0.0;
for(const auto& value:values)
{
const double x=value[0]-meanX;
xy+=x*(value[1]-meanY);xx+=x*x;
}
const double slope=xx>0.0?xy/xx:0.0;
for(const auto& value:values)
output.push_back({value[0],value[1]-meanY
-slope*(value[0]-meanX)});
};
std::vector<double> beadControl;
beadControl.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
constexpr double BeadSpacingMetres=1.5;
constexpr double BeadSphereRadiusMetres=2.0;
for(std::size_t i=0;i<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);++i)
{
const double x=static_cast<double>(i)*SampleSpacingMetres;
const double nearest=std::abs(std::remainder(x,BeadSpacingMetres));
beadControl.push_back(std::sqrt(std::max(0.0,
BeadSphereRadiusMetres*BeadSphereRadiusMetres-nearest*nearest)));
}
std::vector<std::array<double,2>> beadSamples;
appendDetrendedProfile(beadControl,0.0,beadSamples);
double ignoredPeriod=0.0;
audit.controlAmplitudeMetres=sinusoidAmplitude(beadSamples,ignoredPeriod);
audit.controlDetected=audit.controlAmplitudeMetres>=RippleAmplitudeLimitMetres;
audit.floorControlAmplitudeMetres=audit.controlAmplitudeMetres;
audit.floorControlDetected=audit.floorControlAmplitudeMetres
>=FloorRippleAmplitudeLimitMetres;
const std::array<double,5> windowStarts{{0.03,0.31,0.457,0.61,0.91}};
std::vector<std::array<double,2>> coherentSamples;
std::vector<std::array<double,2>> coherentFloorSamples;
for(const double fraction:windowStarts)
{
const double start=(total-WindowLengthMetres)*fraction;
std::vector<double> radii;
radii.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
std::vector<std::array<double,2>> floorResiduals;
floorResiduals.reserve(static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)+1);
std::vector<std::array<double,6>> floorDebugSamples;
floorDebugSamples.reserve(static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)+1);
for(std::size_t sample=0;
sample<=static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres);
++sample)
{
++audit.expectedSamples;
++audit.floorExpectedSamples;
const double distance=start+static_cast<double>(sample)*SampleSpacingMetres;
const auto pose=interpolate(distance);
// Recover the composed walk surface from its zero crossing.
// The support strip is segment-built and is not itself a true
// signed-distance field, so a fixed centerline radius misses
// the stepped top that the player actually walks on.
const double expectedFloor=pose.z-pose.radius+0.20;
constexpr double FloorProbeStepMetres=0.25;
constexpr int FloorProbeCount=7;
double previousDensity=0.0,previousZ=0.0;
bool havePrevious=false,haveFloor=false;
double bestFloor=0.0,bestDistance=std::numeric_limits<double>::infinity();
for(int vertical=0;vertical<FloorProbeCount;++vertical)
{
const double z=expectedFloor-1.0+vertical*FloorProbeStepMetres;
const double density=static_cast<double>(Field.densityAt({
pose.x/coreMetres,pose.y/coreMetres,z/coreMetres}))*coreMetres;
if(havePrevious&&previousDensity<0.0&&density>=0.0)
{
const double denominator=density-previousDensity;
const double crossing=denominator>1.0e-12
?previousZ+(z-previousZ)*(-previousDensity)/denominator:z;
const double candidateDistance=std::abs(crossing-expectedFloor);
if(candidateDistance<bestDistance)
{bestDistance=candidateDistance;bestFloor=crossing;haveFloor=true;}
}
previousDensity=density;previousZ=z;havePrevious=true;
}
if(haveFloor)
{
floorResiduals.push_back({distance,bestFloor-expectedFloor});
floorDebugSamples.push_back({distance,expectedFloor,bestFloor,
pose.x,pose.y,pose.z});
++audit.floorSamples;
}
const auto before=interpolate(std::max(0.0,distance-0.25));
const auto after=interpolate(std::min(total,distance+0.25));
const double tangentX=after.x-before.x,tangentY=after.y-before.y;
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6)continue;
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
const double sampleRadius=std::max(0.20,pose.radius-0.18);
const double x0=pose.x/coreMetres,y0=pose.y/coreMetres,z0=pose.z/coreMetres;
const double offset=sampleRadius/coreMetres;
const double left=static_cast<double>(Field.densityAt(
{x0+nx*offset,y0+ny*offset,z0}))*coreMetres;
const double right=static_cast<double>(Field.densityAt(
{x0-nx*offset,y0-ny*offset,z0}))*coreMetres;
if(!std::isfinite(left)||!std::isfinite(right)
||left< -0.75||left>0.75||right< -0.75||right>0.75)continue;
radii.push_back(sampleRadius+0.5*(left+right));
++audit.samples;
}
if(radii.size()<static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)*3/4)continue;
std::vector<std::array<double,2>> windowSamples;
appendDetrendedProfile(radii,start,windowSamples);
double localPeriod=0.0;
const double localAmplitude=sinusoidAmplitude(windowSamples,localPeriod);
if(localAmplitude>audit.localPeakAmplitudeMetres)
{
audit.localPeakAmplitudeMetres=localAmplitude;
audit.periodMetres=localPeriod;
}
coherentSamples.insert(coherentSamples.end(),windowSamples.begin(),
windowSamples.end());
double floorWindowPeriod=0.0,floorWindowAmplitude=0.0;
if(floorResiduals.size()>=static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)*3/4)
{
std::vector<std::array<double,2>> floorWindowSamples;
appendDetrendedPairs(floorResiduals,floorWindowSamples);
floorWindowAmplitude=sinusoidAmplitude(floorWindowSamples,
floorWindowPeriod);
if(floorWindowAmplitude>audit.floorAmplitudeMetres)
{
audit.floorAmplitudeMetres=floorWindowAmplitude;
audit.floorPeriodMetres=floorWindowPeriod;
audit.floorPeakWindowStartMetres=start;
audit.floorPeakProfile=std::move(floorDebugSamples);
}
coherentFloorSamples.insert(coherentFloorSamples.end(),
floorWindowSamples.begin(),floorWindowSamples.end());
}
const double floorWindowCoverage=static_cast<double>(floorResiduals.size())
/(WindowLengthMetres/SampleSpacingMetres+1.0);
double floorResidualMinimum=0.0,floorResidualMaximum=0.0;
if(!floorResiduals.empty())
{
const auto extrema=std::minmax_element(floorResiduals.begin(),
floorResiduals.end(),[](const auto& a,const auto& b)
{return a[1]<b[1];});
floorResidualMinimum=(*extrema.first)[1];
floorResidualMaximum=(*extrema.second)[1];
}
std::printf("[PassageFloorRippleWindow] id=%s start_m=%.3f "
"period_m=%.3f amplitude_m=%.4f coverage=%.3f "
"residual_range_m=%.4f..%.4f threshold_m=0.015\n",
passage.stableId.c_str(),start,floorWindowPeriod,floorWindowAmplitude,
floorWindowCoverage,floorResidualMinimum,floorResidualMaximum);
}
audit.coherentAmplitudeMetres=sinusoidAmplitude(coherentSamples,
audit.coherentPeriodMetres);
audit.floorCoherentAmplitudeMetres=sinusoidAmplitude(coherentFloorSamples,
audit.floorCoherentPeriodMetres);
audit.amplitudeMetres=audit.localPeakAmplitudeMetres;
const double coverage=audit.expectedSamples>0
?static_cast<double>(audit.samples)/audit.expectedSamples:0.0;
const double floorCoverage=audit.floorExpectedSamples>0
?static_cast<double>(audit.floorSamples)/audit.floorExpectedSamples:0.0;
audit.passed=audit.controlDetected&&coverage>=0.75
&&audit.localPeakAmplitudeMetres<RippleAmplitudeLimitMetres
&&audit.floorControlDetected&&floorCoverage>=0.75
&&audit.floorAmplitudeMetres<FloorRippleAmplitudeLimitMetres;
return audit;
};
const auto looksNatural=[&](double flatRun,double reliefPeakToPeak)
{return flatRun<=MaximumFlatRunMetres
&&reliefPeakToPeak>=MinimumWallReliefMetres;};
const auto findStratum=[&](std::int32_t index)->const VoxelForgeCore::ResolvedLayoutStratumV2*
{
const auto it=std::find_if(ResolvedLayout->strates.begin(),ResolvedLayout->strates.end(),
[index](const auto& s){return s.strateIndex==index;});
return it==ResolvedLayout->strates.end()?nullptr:&*it;
};
const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages();
VoxelForgeCore::World blockedWorld(controlSnapshot);
std::string blockedCompileError;
const bool blockedCompiled=controlSnapshot
&&blockedWorld.compile(ShapeRequest,Scheduler,blockedCompileError);
if(!blockedCompiled)
{
Streamer.Stop();
std::fprintf(stderr,"[ResolvedPassageBlockedControl] compile_failed=%s\n",
blockedCompileError.c_str());
return 10;
}
struct FPassageOpenAirAudit
{
std::uint64_t supportSamples=0,violations=0,legacyViolations=0;
std::uint64_t columnSamples=0,shortSpanSamples=0;
std::uint64_t routeSupportSamples=0,routeSupportViolations=0;
std::array<std::array<double,4>,8> firstViolations{};
std::size_t firstViolationCount=0;
};
constexpr double PassageSupportAuditSpacingMetres=0.25;
constexpr std::array<double,2> PassageSupportAuditDepthsMetres{{0.125,0.375}};
constexpr std::array<std::array<double,2>,16> PassageSupportAuditDirections{{
{{1.0000000000000000,0.0000000000000000}},
{{0.9238795325112867,0.3826834323650898}},
{{0.7071067811865476,0.7071067811865476}},
{{0.3826834323650898,0.9238795325112867}},
{{0.0000000000000000,1.0000000000000000}},
{{-0.3826834323650898,0.9238795325112867}},
{{-0.7071067811865476,0.7071067811865476}},
{{-0.9238795325112867,0.3826834323650898}},
{{-1.0000000000000000,0.0000000000000000}},
{{-0.9238795325112867,-0.3826834323650898}},
{{-0.7071067811865476,-0.7071067811865476}},
{{-0.3826834323650898,-0.9238795325112867}},
{{0.0000000000000000,-1.0000000000000000}},
{{0.3826834323650898,-0.9238795325112867}},
{{0.7071067811865476,-0.7071067811865476}},
{{0.9238795325112867,-0.3826834323650898}}}};
const auto auditPassageOpenAir=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::World& Native,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage,
std::size_t passageIndex)
{
FPassageOpenAirAudit audit;
const auto inspect=[&](double xMetres,double yMetres,double floorMetres,
double depthMetres,double supportThicknessMetres,bool routeSupport=false,
std::size_t passageSegment=std::numeric_limits<std::size_t>::max())
{
if(depthMetres<=0.0||depthMetres>supportThicknessMetres+1.0e-6)return;
++audit.supportSamples;
audit.routeSupportSamples+=routeSupport;
const VoxelForgeCore::Vec3d sample{xMetres/coreMetres,yMetres/coreMetres,
(floorMetres-depthMetres)/coreMetres};
const float nativeDensity=Native.densityAt(sample);
const float passageDensity=Field.densityAt(sample);
const float legacySupportDensity=std::min(nativeDensity,
static_cast<float>(-depthMetres/coreMetres));
if(nativeDensity>=0.0f&&legacySupportDensity<0.0f)
++audit.legacyViolations;
if(nativeDensity>=0.0f&&passageDensity<0.0f)
{
const bool connectedColumn=!routeSupport
&&passageSegment!=std::numeric_limits<std::size_t>::max()
&&Field.isPassageColumnSample(passageIndex,passageSegment,sample);
if(connectedColumn){++audit.columnSamples;return;}
const bool groundedShortSpan=!routeSupport
&&passageSegment!=std::numeric_limits<std::size_t>::max()
&&Field.isPassageShortSpanSample(passageIndex,passageSegment,sample);
if(groundedShortSpan){++audit.shortSpanSamples;return;}
audit.routeSupportViolations+=routeSupport;
if(audit.firstViolationCount<audit.firstViolations.size())
audit.firstViolations[audit.firstViolationCount++]={xMetres,yMetres,
floorMetres-depthMetres,passageDensity};
++audit.violations;
}
};
const auto inspectFloorDisc=[&](double xMetres,double yMetres,double floorMetres,
double supportRadiusMetres,double depthMetres,double supportThicknessMetres,
bool routeSupport=false,
std::size_t passageSegment=std::numeric_limits<std::size_t>::max())
{
const std::size_t radialSteps=static_cast<std::size_t>(std::ceil(
supportRadiusMetres/PassageSupportAuditSpacingMetres));
for(std::size_t radialStep=0;radialStep<=radialSteps;++radialStep)
{
const double radial=std::min(supportRadiusMetres,
radialStep*PassageSupportAuditSpacingMetres);
for(const auto& direction:PassageSupportAuditDirections)
inspect(xMetres+direction[0]*radial,yMetres+direction[1]*radial,
floorMetres,depthMetres,supportThicknessMetres,routeSupport,
passageSegment);
}
};
for(std::size_t segment=1;segment<passage.controlPoints.size();++segment)
{
const auto& a=passage.controlPoints[segment-1];
const auto& b=passage.controlPoints[segment];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double length=std::sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)+(bz-az)*(bz-az));
const std::size_t intervals=std::max<std::size_t>(1,static_cast<std::size_t>(
std::ceil(length/PassageSupportAuditSpacingMetres)));
for(std::size_t sample=0;sample<=intervals;++sample)
{
if(segment>1&&sample==0)continue;
const double t=static_cast<double>(sample)/intervals;
const double centerX=ax+(bx-ax)*t,centerY=ay+(by-ay)*t;
const double centerZ=az+(bz-az)*t;
const double radius=qToMetres(a.radiusSubvoxels)
+(qToMetres(b.radiusSubvoxels)-qToMetres(a.radiusSubvoxels))*t;
const double floorZ=centerZ-radius+0.20;
for(const double depth:PassageSupportAuditDepthsMetres)
inspectFloorDisc(centerX,centerY,floorZ,radius,depth,1.0,
false,segment-1);
}
}
const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& value)
{return value.strateIndex==passage.upperStrateIndex;});
if(upperStratum!=ResolvedLayout->strates.end())
{
std::array<const VoxelForgeCore::ResolvedLayoutAnchorV2*,5> route{};
std::size_t routeCount=0;
for(const auto& anchor:upperStratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
{
if(routeCount<route.size())route[routeCount++]=&anchor;
else
{
std::move(route.begin()+1,route.end(),route.begin());
route.back()=&anchor;
}
}
const double mouthX=qToMetres(passage.upperMouthSubvoxels[0]);
const double mouthY=qToMetres(passage.upperMouthSubvoxels[1]);
constexpr double RouteSupportReachMetres=13.0;
constexpr double RouteFloorOffsetMetres=1.20;
constexpr double RouteSupportThicknessMetres=1.0;
constexpr double RouteSupportDepthStepMetres=0.125;
for(std::size_t segment=1;segment<routeCount;++segment)
{
const auto& a=*route[segment-1];
const auto& b=*route[segment];
const double ax=qToMetres(a.values[0]),ay=qToMetres(a.values[1]);
const double az=qToMetres(a.values[2]);
const double bx=qToMetres(b.values[0]),by=qToMetres(b.values[1]);
const double bz=qToMetres(b.values[2]);
const double dx=bx-ax,dy=by-ay,dz=bz-az;
const double length=std::sqrt(dx*dx+dy*dy+dz*dz);
const std::size_t intervals=std::max<std::size_t>(1,
static_cast<std::size_t>(std::ceil(length
/PassageSupportAuditSpacingMetres)));
const double routeRadius=a.values.size()>=4
?std::max(0.75,qToMetres(a.values[3])):0.75;
for(std::size_t sample=0;sample<=intervals;++sample)
{
if(segment>1&&sample==0)continue;
const double t=static_cast<double>(sample)/intervals;
const double centerX=ax+dx*t,centerY=ay+dy*t;
const double centerZ=az+dz*t;
for(std::size_t radialStep=0;radialStep<=static_cast<std::size_t>(
std::ceil(routeRadius/PassageSupportAuditSpacingMetres));++radialStep)
{
const double radial=std::min(routeRadius,
radialStep*PassageSupportAuditSpacingMetres);
for(const auto& direction:PassageSupportAuditDirections)
{
const double x=centerX+direction[0]*radial;
const double y=centerY+direction[1]*radial;
if(std::hypot(x-mouthX,y-mouthY)>RouteSupportReachMetres)continue;
const double floorZ=centerZ-RouteFloorOffsetMetres;
for(double depth=RouteSupportDepthStepMetres;
depth<=RouteSupportThicknessMetres+1.0e-6;
depth+=RouteSupportDepthStepMetres)
inspect(x,y,floorZ,depth,RouteSupportThicknessMetres,true);
}
}
}
}
}
return audit;
};
struct FPassageColumnAudit
{
std::uint64_t columns=0,shortSpans=0,connectedEnds=0,routeSections=0;
std::uint64_t routeSectionFailures=0,wallSections=0,wallFailures=0;
double minimumWallMetres=std::numeric_limits<double>::infinity();
double minimumSurfaceRadiusMetres=std::numeric_limits<double>::infinity();
double maximumSurfaceRadiusMetres=0.0;
double surfaceRadiusReliefMetres=0.0;
double longestShortSpanMetres=0.0;
bool passed=true;
bool disconnectedEndControlApplicable=false;
bool disconnectedEndControlDetected=false;
};
const auto auditPassageColumns=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::World& Native,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage,
std::size_t passageIndex)
{
FPassageColumnAudit audit;
const double qMetres=coreMetres
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
constexpr std::array<std::array<double,2>,5> supportOffsets{{
{{0.0,0.0}},{{0.45,0.0}},{{-0.45,0.0}},{{0.0,0.45}},{{0.0,-0.45}}}};
const auto endpointSupportCount=[&](const std::array<double,4>& point)
{
const double x=point[0]*qMetres,y=point[1]*qMetres;
const double floor=point[2]*qMetres-point[3]*qMetres+0.13;
std::uint32_t supported=0;
for(const auto& offset:supportOffsets)
{
bool solid=false;
for(const double depth:{0.125,0.25})
if(Native.densityAt({(x+offset[0])/coreMetres,
(y+offset[1])/coreMetres,(floor-depth)/coreMetres})<0.0f)
{solid=true;break;}
supported+=solid;
}
return supported;
};
const auto endpointConnected=[&](const std::array<double,4>& point)
{return endpointSupportCount(point)>=3;};
struct FColumnCapProbe
{
std::uint64_t columnSamples=0,nativeOverlapSamples=0;
double firstOverlapDepthMetres=std::numeric_limits<double>::infinity();
double minimumNativeDensity=std::numeric_limits<double>::infinity();
};
const auto probeColumnCap=[&](const VoxelForgeCore::PassageVoidCrossingAuditV1& crossing,
std::size_t segment,double capZMetres,bool upperCap,double depthLimitMetres)
{
FColumnCapProbe probe;
constexpr double DepthStepMetres=0.25;
constexpr double RadialStepMetres=0.50;
constexpr std::size_t DirectionCount=16;
const double axisX=qToMetres(crossing.columnAxisSubvoxels[0]);
const double axisY=qToMetres(crossing.columnAxisSubvoxels[1]);
for(double depth=DepthStepMetres;depth<=depthLimitMetres+1.0e-6;
depth+=DepthStepMetres)
{
const double z=capZMetres+(upperCap?-depth:depth);
const double maxRadius=qToMetres(crossing.columnMaximumRadiusSubvoxels);
const std::size_t radialSteps=static_cast<std::size_t>(
std::ceil(maxRadius/RadialStepMetres));
for(std::size_t radialStep=0;radialStep<=radialSteps;++radialStep)
{
const double radius=std::min(maxRadius,
radialStep*RadialStepMetres);
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846
*direction/DirectionCount;
const VoxelForgeCore::Vec3d sample{
(axisX+radius*std::cos(angle))/coreMetres,
(axisY+radius*std::sin(angle))/coreMetres,z/coreMetres};
if(!Field.isPassageColumnSample(passageIndex,segment,sample))continue;
++probe.columnSamples;
const double nativeDensity=Native.densityAt(sample);
probe.minimumNativeDensity=std::min(probe.minimumNativeDensity,
nativeDensity);
if(nativeDensity<0.0)
{
++probe.nativeOverlapSamples;
probe.firstOverlapDepthMetres=std::min(
probe.firstOverlapDepthMetres,depth);
}
}
}
}
return probe;
};
const auto columnSolidAt=[&](std::size_t segment,double x,double y,double z)
{
return Field.isPassageColumnSample(passageIndex,segment,
{x/coreMetres,y/coreMetres,z/coreMetres});
};
const auto shortSpanSolidAt=[&](std::size_t segment,double x,double y,double z)
{
return Field.isPassageShortSpanSample(passageIndex,segment,
{x/coreMetres,y/coreMetres,z/coreMetres});
};
const auto crossings=Field.passageVoidCrossings();
double controlLowestRouteZ=std::numeric_limits<double>::infinity();
bool disconnectedEndControlApplicable=false;
bool disconnectedEndControlDetected=false;
for(const auto& crossing:crossings)
{
if(crossing.passageIndex!=passageIndex)continue;
const bool connectedStart=endpointConnected(crossing.startPointSubvoxels);
const bool connectedEnd=endpointConnected(crossing.endPointSubvoxels);
if(!crossing.needsColumn)
{
++audit.shortSpans;
audit.longestShortSpanMetres=std::max(audit.longestShortSpanMetres,
crossing.unsupportedLengthMetres);
const bool shortSpanPass=connectedStart&&connectedEnd
&&crossing.unsupportedLengthMetres<=12.5
&&crossing.lastSegment+1<passage.controlPoints.size();
audit.passed&=shortSpanPass;
std::printf("[PassageGroundedShortSpanAudit] id=%s segments=%zu..%zu length_m=%.3f threshold_m=12.500 connected=%d/2 status=%s\n",
passage.stableId.c_str(),crossing.firstSegment,crossing.lastSegment,
crossing.unsupportedLengthMetres,
static_cast<int>(connectedStart)+static_cast<int>(connectedEnd),
shortSpanPass?"PASS":"FAIL");
const std::size_t segment=std::min(crossing.firstSegment,
passage.controlPoints.size()-2);
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double x=(qToMetres(a.positionSubvoxels[0])
+qToMetres(b.positionSubvoxels[0]))*0.5;
const double y=(qToMetres(a.positionSubvoxels[1])
+qToMetres(b.positionSubvoxels[1]))*0.5;
const double z=(qToMetres(a.positionSubvoxels[2])
+qToMetres(b.positionSubvoxels[2]))*0.5
-qToMetres(a.radiusSubvoxels+b.radiusSubvoxels)*0.5+0.13;
audit.passed&=shortSpanSolidAt(segment,x,y,z-0.25);
continue;
}
if(crossing.lastSegment+1>=passage.controlPoints.size())
{audit.passed=false;continue;}
const double capTopMetres=qToMetres(crossing.columnTopZSubvoxels);
const double capBottomMetres=qToMetres(crossing.columnBottomZSubvoxels);
const auto topCap=probeColumnCap(crossing,crossing.firstSegment,
capTopMetres,true,6.0);
const auto bottomCap=probeColumnCap(crossing,crossing.lastSegment,
capBottomMetres,false,6.0);
const bool topCapConnected=topCap.nativeOverlapSamples>0;
const bool bottomCapConnected=bottomCap.nativeOverlapSamples>0;
const std::uint32_t routeStartSupport=endpointSupportCount(
crossing.startPointSubvoxels);
const std::uint32_t routeEndSupport=endpointSupportCount(
crossing.endPointSubvoxels);
std::printf("[PassageColumnRouteEndpointSupport] id=%s start=%u/5 start_z_m=%.3f end=%u/5 end_z_m=%.3f threshold=3/5\n",
passage.stableId.c_str(),routeStartSupport,
qToMetres(crossing.startPointSubvoxels[2]),routeEndSupport,
qToMetres(crossing.endPointSubvoxels[2]));
const auto printCap=[&](const char* endName,const char* side,double capZ,
const FColumnCapProbe& probe,bool connected)
{
std::printf("[PassageColumnCapAudit] id=%s end=%s side=%s cap_z_m=%.3f column_samples=%llu native_overlap_samples=%llu first_overlap_depth_m=%.3f minimum_native_density=%.6f search_depth_m=6.000 status=%s\n",
passage.stableId.c_str(),endName,side,capZ,
static_cast<unsigned long long>(probe.columnSamples),
static_cast<unsigned long long>(probe.nativeOverlapSamples),
probe.firstOverlapDepthMetres,probe.minimumNativeDensity,
connected?"PASS":"FAIL");
};
printCap("top","upper",capTopMetres,topCap,topCapConnected);
printCap("bottom","lower",capBottomMetres,bottomCap,bottomCapConnected);
const auto upper=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[&](const auto& value)
{return value.strateIndex==passage.upperStrateIndex;});
const double startRouteZ=qToMetres(crossing.startPointSubvoxels[2]);
const double endRouteZ=qToMetres(crossing.endPointSubvoxels[2]);
const double lowerRouteZ=std::min(startRouteZ,endRouteZ);
if(upper!=ResolvedLayout->strates.end()
&&upper->generatorKind=="FloatingIslands"
&&lowerRouteZ<controlLowestRouteZ)
{
controlLowestRouteZ=lowerRouteZ;
// Move the hypothetical lower cap 20 m upward into the FI air gap.
// Its first 2 m are still inside the original column bounds, but a
// truncated column there has no native substrate to join.
const double hypotheticalBottomZ=lowerRouteZ+20.0;
const auto disconnectedControl=probeColumnCap(crossing,
crossing.lastSegment,hypotheticalBottomZ,false,2.0);
disconnectedEndControlApplicable=disconnectedControl.columnSamples>0;
disconnectedEndControlDetected=disconnectedEndControlApplicable
&&disconnectedControl.nativeOverlapSamples==0;
std::printf("[PassageColumnDisconnectedEndControl] source=air_gap_truncated_lower_cap cap_z_m=%.3f column_samples=%llu native_overlap_samples=%llu minimum_native_density=%.6f detected=%s\n",
hypotheticalBottomZ,
static_cast<unsigned long long>(disconnectedControl.columnSamples),
static_cast<unsigned long long>(disconnectedControl.nativeOverlapSamples),
disconnectedControl.minimumNativeDensity,
disconnectedEndControlDetected?"true":"false");
}
++audit.columns;
audit.connectedEnds+=topCapConnected+bottomCapConnected;
const double axisX=qToMetres(crossing.columnAxisSubvoxels[0]);
const double axisY=qToMetres(crossing.columnAxisSubvoxels[1]);
const double minimumRadius=qToMetres(crossing.columnMinimumRadiusSubvoxels);
const double maximumRadius=qToMetres(crossing.columnMaximumRadiusSubvoxels);
const double minimumWall=minimumRadius-crossing.maximumRouteOffsetMetres
-crossing.maximumBoreRadiusMetres-0.50;
audit.minimumWallMetres=std::min(audit.minimumWallMetres,minimumWall);
const std::size_t segmentCount=crossing.lastSegment-crossing.firstSegment+1;
const std::size_t probeCount=std::min<std::size_t>(128,segmentCount);
std::uint64_t crossingRouteFailures=0,crossingWallFailures=0;
for(std::size_t probe=0;probe<probeCount;++probe)
{
const std::size_t segment=crossing.firstSegment
+std::min(segmentCount-1,(probe*segmentCount)/probeCount);
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double bx=qToMetres(b.positionSubvoxels[0]);
const double by=qToMetres(b.positionSubvoxels[1]);
const double bz=qToMetres(b.positionSubvoxels[2]);
const double x=(ax+bx)*0.5,y=(ay+by)*0.5;
const double z=(az+bz)*0.5;
const double radius=(qToMetres(a.radiusSubvoxels)
+qToMetres(b.radiusSubvoxels))*0.5;
const double floor=z-radius+0.13;
const VoxelForgeCore::Vec3d supportPoint{
x/coreMetres,y/coreMetres,(floor-2.0)/coreMetres};
const bool solidUnderRoute=columnSolidAt(segment,x,y,floor-2.0)
||Native.densityAt(supportPoint)<0.0f;
++audit.routeSections;
audit.routeSectionFailures+=!solidUnderRoute;
crossingRouteFailures+=!solidUnderRoute;
const double radial=std::hypot(x-axisX,y-axisY);
const double wallRadius=radial+radius+1.5;
const double outwardX=radial>1.0e-6?(x-axisX)/radial:1.0;
const double outwardY=radial>1.0e-6?(y-axisY)/radial:0.0;
const bool wallSolid=columnSolidAt(segment,
axisX+outwardX*wallRadius,axisY+outwardY*wallRadius,z);
++audit.wallSections;
audit.wallFailures+=!wallSolid;
crossingWallFailures+=!wallSolid;
if(!wallSolid&&crossingWallFailures<=8)
std::printf("[PassageRockColumnWallProbe] id=%s segment=%zu xyz_m=(%.3f,%.3f,%.3f) axis_m=(%.3f,%.3f) centerline_radius_m=%.3f bore_radius_m=%.3f wall_probe_radius_m=%.3f\n",
passage.stableId.c_str(),segment,x,y,z,axisX,axisY,radial,radius,wallRadius);
}
double crossingMinimumSurfaceRadius=std::numeric_limits<double>::infinity();
double crossingMaximumSurfaceRadius=0.0;
std::array<double,6> meanRadiusByHeight{};
std::size_t heightSamples=0;
constexpr double RayStepMetres=0.25;
constexpr std::array<double,6> HeightFractions{{0.25,0.35,0.45,0.55,0.65,0.75}};
constexpr std::size_t DirectionCount=16;
const double topMetres=qToMetres(crossing.columnTopZSubvoxels);
const double bottomMetres=qToMetres(crossing.columnBottomZSubvoxels);
const double rayStart=crossing.maximumRouteOffsetMetres
+crossing.maximumBoreRadiusMetres+0.75;
for(const double heightFraction:HeightFractions)
{
const double z=topMetres+(bottomMetres-topMetres)*heightFraction;
double heightMeanRadius=0.0;
std::uint64_t heightRayCount=0;
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846
*direction/DirectionCount;
double lastSolidRadius=0.0;
bool enteredColumn=false;
const std::size_t raySteps=static_cast<std::size_t>(std::ceil(
(maximumRadius+2.0-rayStart)/RayStepMetres));
for(std::size_t step=0;step<=raySteps;++step)
{
const double rayRadius=rayStart+step*RayStepMetres;
const VoxelForgeCore::Vec3d point{
(axisX+rayRadius*std::cos(angle))/coreMetres,
(axisY+rayRadius*std::sin(angle))/coreMetres,
z/coreMetres};
if(Field.densityAt(point)<0.0f)
{enteredColumn=true;lastSolidRadius=rayRadius;}
else if(enteredColumn)break;
}
if(!enteredColumn)continue;
heightMeanRadius+=lastSolidRadius;
++heightRayCount;
crossingMinimumSurfaceRadius=std::min(crossingMinimumSurfaceRadius,
lastSolidRadius);
crossingMaximumSurfaceRadius=std::max(crossingMaximumSurfaceRadius,
lastSolidRadius);
}
if(heightRayCount==0)continue;
meanRadiusByHeight[heightSamples++]=heightMeanRadius/heightRayCount;
}
const double crossingSurfaceRelief=heightSamples>=2
?*std::max_element(meanRadiusByHeight.begin(),
meanRadiusByHeight.begin()+heightSamples)
-*std::min_element(meanRadiusByHeight.begin(),
meanRadiusByHeight.begin()+heightSamples):0.0;
audit.minimumSurfaceRadiusMetres=std::min(audit.minimumSurfaceRadiusMetres,
crossingMinimumSurfaceRadius);
audit.maximumSurfaceRadiusMetres=std::max(audit.maximumSurfaceRadiusMetres,
crossingMaximumSurfaceRadius);
audit.surfaceRadiusReliefMetres=std::max(audit.surfaceRadiusReliefMetres,
crossingSurfaceRelief);
const double measuredWall=crossingMinimumSurfaceRadius
-crossing.maximumRouteOffsetMetres-crossing.maximumBoreRadiusMetres;
const bool columnPass=topCapConnected&&bottomCapConnected
&&minimumWall>=1.50&&crossingRouteFailures==0
&&crossingWallFailures==0&&std::isfinite(measuredWall)
&&measuredWall>=1.50&&crossingSurfaceRelief>=0.20;
audit.passed&=columnPass;
std::printf("[PassageRockColumnAudit] id=%s segments=%zu..%zu span_m=%.3f axis_m=(%.3f,%.3f) connected=%d/2 route_support=%llu/%llu wall_failures=%llu wall_margin_m=%.3f threshold_m=1.500 radii_m=%.3f..%.3f relief_p2p_m=%.3f nominal_radius_m=%.3f status=%s\n",
passage.stableId.c_str(),crossing.firstSegment,crossing.lastSegment,
crossing.unsupportedLengthMetres,axisX,axisY,
static_cast<int>(topCapConnected)+static_cast<int>(bottomCapConnected),
static_cast<unsigned long long>(probeCount-crossingRouteFailures),
static_cast<unsigned long long>(probeCount),
static_cast<unsigned long long>(crossingWallFailures),measuredWall,
crossingMinimumSurfaceRadius,crossingMaximumSurfaceRadius,
crossingSurfaceRelief,qToMetres(crossing.columnNominalRadiusSubvoxels),
columnPass?"PASS":"FAIL");
}
audit.disconnectedEndControlApplicable|=disconnectedEndControlApplicable;
audit.disconnectedEndControlDetected|=disconnectedEndControlDetected;
if(disconnectedEndControlApplicable&&!disconnectedEndControlDetected)
audit.passed=false;
return audit;
};
if(Assembly)
for(const auto& stratum:ResolvedLayout->strates)
{
if(stratum.generatorKind!="FloatingIslands")continue;
const auto anchor=std::find_if(stratum.anchors.begin(),stratum.anchors.end(),
[](const auto& value){return value.kind=="passage_anchor"&&value.values.size()>=7;});
const auto islandPlan=std::find_if(Assembly->floatingIslands.begin(),
Assembly->floatingIslands.end(),[&](const auto& value)
{return value.strateIndex==stratum.strateIndex;});
if(anchor==stratum.anchors.end()||islandPlan==Assembly->floatingIslands.end())continue;
if(islandPlan->manifest.recipe.geometryVersion>=8)continue;
const auto ordinal=islandPlan->manifest.recipe.anchorIslandOrdinal;
if(ordinal>=islandPlan->manifest.plan.islands.size())continue;
const auto& anchorIsland=islandPlan->manifest.plan.islands[ordinal];
const double axisX=qToMetres(anchor->values[0]);
const double axisY=qToMetres(anchor->values[1]);
const double rootBottom=qToMetres(anchor->values[5]);
const auto& islandRecipe=islandPlan->manifest.recipe;
const std::int64_t crustRatioQ16=islandRecipe.thicknessRatioQ16
+islandRecipe.crustDepthBonusQ16;
const std::int64_t crustDepthQ=(anchorIsland.radiusSubvoxels*crustRatioQ16
+32768)/65536;
const double rootTop=qToMetres(anchorIsland.topZSubvoxels-crustDepthQ);
const double nominalRootRadius=qToMetres(anchor->values[2]);
double helixMinimumRadius=std::numeric_limits<double>::infinity();
double helixMaximumRadius=0.0;
for(const auto& passage:ResolvedLayout->passages)
if(passage.upperStrateIndex==stratum.strateIndex)
for(const auto& point:passage.controlPoints)
{
const double z=qToMetres(point.positionSubvoxels[2]);
if(z<rootBottom||z>rootTop)continue;
const double radial=std::hypot(
qToMetres(point.positionSubvoxels[0]-anchor->values[0]),
qToMetres(point.positionSubvoxels[1]-anchor->values[1]));
helixMinimumRadius=std::min(helixMinimumRadius,radial);
helixMaximumRadius=std::max(helixMaximumRadius,radial);
}
if(!std::isfinite(helixMinimumRadius))continue;
double minimumMeasuredRootRadius=std::numeric_limits<double>::infinity();
std::uint64_t rootRaySamples=0;
constexpr std::array<double,5> RootHeightFractions{{0.01,0.25,0.5,0.75,0.99}};
for(const double fraction:RootHeightFractions)
{
const double z=rootTop+(rootBottom-rootTop)*fraction;
double minimumRadius=std::numeric_limits<double>::infinity();
double maximumRadius=0.0,meanRadius=0.0;
constexpr std::size_t DirectionCount=32;
constexpr double RayStepMetres=0.125;
const std::size_t raySteps=static_cast<std::size_t>(std::ceil(
(nominalRootRadius+2.0)/RayStepMetres));
for(std::size_t direction=0;direction<DirectionCount;++direction)
{
const double angle=2.0*3.14159265358979323846*direction/DirectionCount;
double radius=0.0;
for(std::size_t step=0;step<=raySteps;++step)
{
const double probeRadius=step*RayStepMetres;
const VoxelForgeCore::Vec3d probe{
(axisX+probeRadius*std::cos(angle))/coreMetres,
(axisY+probeRadius*std::sin(angle))/coreMetres,z/coreMetres};
if(blockedWorld.densityAt(probe)>=0.0f)break;
radius=probeRadius;
}
minimumRadius=std::min(minimumRadius,radius);
maximumRadius=std::max(maximumRadius,radius);
meanRadius+=radius;
++rootRaySamples;
}
meanRadius/=DirectionCount;
minimumMeasuredRootRadius=std::min(minimumMeasuredRootRadius,minimumRadius);
std::printf("[PassageRootRadiusMeasure] strate=%d z_m=%.3f solid_radius_min_m=%.3f mean_m=%.3f max_m=%.3f nominal_root_m=%.3f rays=%zu\n",
stratum.strateIndex,z,minimumRadius,meanRadius,maximumRadius,
nominalRootRadius,DirectionCount);
}
const auto firstRootPassage=std::find_if(ResolvedLayout->passages.begin(),
ResolvedLayout->passages.end(),[&](const auto& passage)
{return passage.upperStrateIndex==stratum.strateIndex;});
const double mouthBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0
:qToMetres(firstRootPassage->mouthRadiusSubvoxels);
const double midBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0
:qToMetres(firstRootPassage->midRadiusSubvoxels);
const double maximumBoreRadius=std::max(mouthBoreRadius,midBoreRadius);
std::printf("[PassageRootMeasure] strate=%d axis_m=(%.3f,%.3f) helix_centerline_radius_min_m=%.3f max_m=%.3f mouth_bore_radius_m=%.3f mid_bore_radius_m=%.3f nominal_root_m=%.3f measured_min_root_m=%.3f minimum_wall_m=%.3f samples=%llu\n",
stratum.strateIndex,axisX,axisY,helixMinimumRadius,helixMaximumRadius,
mouthBoreRadius,midBoreRadius,nominalRootRadius,minimumMeasuredRootRadius,
minimumMeasuredRootRadius-helixMaximumRadius-maximumBoreRadius,
static_cast<unsigned long long>(rootRaySamples));
}
const auto mouthInContent=[&](std::int32_t index,const std::array<std::int64_t,3>& mouth)
{
const auto* stratum=findStratum(index);if(!stratum)return false;
const std::int64_t zUm=static_cast<std::int64_t>(std::llround(
static_cast<double>(mouth[2])*World.CoreVoxelSizeMicrons
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
return zUm>=stratum->content.bottomMicrometres&&zUm<stratum->content.topMicrometres;
};
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
std::uint64_t mouthProfilePasses=0,ripplePasses=0,rippleControlsDetected=0;
std::uint64_t floorRippleControlsDetected=0;
std::uint64_t openAirViolations=0,openAirLegacyViolations=0,openAirSamples=0;
std::uint64_t openAirAudits=0,openAirColumnSamples=0,openAirShortSpanSamples=0;
std::uint64_t columnCrossings=0,shortGroundedSpans=0,columnConnectedEnds=0;
std::uint64_t columnRouteFailures=0,columnWallFailures=0;
double longestUncolumnedSpanMetres=0.0,longestShortSpanMetres=0.0;
double l26LegacyBridgeSpanMetres=0.0;
bool columnAuditsPassed=true,noLongBridgeAuditPassed=true;
bool columnDisconnectedEndControlApplicable=false;
bool columnDisconnectedEndControlDetected=false;
bool l26NegativeControlApplicable=false;
const auto plannedVoidCrossings=Shape.passageVoidCrossings();
for(const auto& crossing:plannedVoidCrossings)
{
if(crossing.needsColumn)continue;
longestUncolumnedSpanMetres=std::max(longestUncolumnedSpanMetres,
crossing.unsupportedLengthMetres);
}
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
++passageIndex)
{
const auto& passage=ResolvedLayout->passages[passageIndex];
const auto* upper=findStratum(passage.upperStrateIndex);
const auto* lower=findStratum(passage.lowerStrateIndex);
if(!upper||!lower||lower->generatorKind!="SurfaceWorld"
||upper->generatorKind=="FloatingIslands")continue;
l26NegativeControlApplicable=true;
for(const auto& crossing:plannedVoidCrossings)
if(crossing.passageIndex==passageIndex)
l26LegacyBridgeSpanMetres=std::max(l26LegacyBridgeSpanMetres,
crossing.unsupportedLengthMetres);
}
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();++passageIndex)
{
const auto& passage=ResolvedLayout->passages[passageIndex];
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
{
const double playerZ=static_cast<double>(point.positionSubvoxels[2]
-point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*1000000.0/World.CoreVoxelSizeMicrons;
path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres,
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
std::vector<FPassageSegmentSupportAudit> segmentSupport;
const FWalkAudit passageAudit=auditPlayerPath(Shape,path,0.125,0.125,0.25,3,0.45,
&blockedWorld,&segmentSupport);
const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage);
const FPassageMouthProfileAudit mouthProfileAudit=
auditPassageMouthProfiles(Shape,passage);
const FPassageRippleAudit rippleAudit=auditPassageRipples(Shape,passage);
const FPassageOpenAirAudit openAirAudit=auditPassageOpenAir(Shape,blockedWorld,
passage,passageIndex);
const FPassageColumnAudit columnAudit=auditPassageColumns(Shape,blockedWorld,
passage,passageIndex);
openAirSamples+=openAirAudit.supportSamples;
openAirViolations+=openAirAudit.violations;
openAirLegacyViolations+=openAirAudit.legacyViolations;
openAirColumnSamples+=openAirAudit.columnSamples;
openAirShortSpanSamples+=openAirAudit.shortSpanSamples;
columnCrossings+=columnAudit.columns;
shortGroundedSpans+=columnAudit.shortSpans;
columnConnectedEnds+=columnAudit.connectedEnds;
columnRouteFailures+=columnAudit.routeSectionFailures;
columnWallFailures+=columnAudit.wallFailures;
longestShortSpanMetres=std::max(longestShortSpanMetres,
columnAudit.longestShortSpanMetres);
columnAuditsPassed&=columnAudit.passed;
columnDisconnectedEndControlApplicable|=columnAudit.disconnectedEndControlApplicable;
columnDisconnectedEndControlDetected|=columnAudit.disconnectedEndControlDetected;
++openAirAudits;
const auto radialSquared=[](const std::array<std::int64_t,3>& p)
{return p[0]*p[0]+p[1]*p[1];};
const bool mouthsInRadius=radialSquared(passage.upperMouthSubvoxels)
<=passage.placementRadiusSubvoxels*passage.placementRadiusSubvoxels
&&radialSquared(passage.lowerMouthSubvoxels)
<=passage.placementRadiusSubvoxels*passage.placementRadiusSubvoxels;
const bool mouthsInContent=mouthInContent(passage.upperStrateIndex,passage.upperMouthSubvoxels)
&&mouthInContent(passage.lowerStrateIndex,passage.lowerMouthSubvoxels);
++passageCount;naturalPasses+=naturalAudit.passed;
mouthProfilePasses+=mouthProfileAudit.passed;
ripplePasses+=rippleAudit.passed;
rippleControlsDetected+=rippleAudit.controlDetected;
floorRippleControlsDetected+=rippleAudit.floorControlDetected;
passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent
&&naturalAudit.passed&&mouthProfileAudit.passed&&rippleAudit.passed;
std::printf("[ResolvedPassageAudit] id=%s interface=%d-%d control_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_content=%d/2 mouth_radius=%d/2 walkability=%s\n",
passage.stableId.c_str(),passage.upperStrateIndex,passage.lowerStrateIndex,
passage.controlPoints.size(),static_cast<unsigned long long>(passageAudit.centers),
static_cast<unsigned long long>(passageAudit.capsuleSamples),
static_cast<unsigned long long>(passageAudit.blocked),
static_cast<unsigned long long>(passageAudit.supportSamples),
static_cast<unsigned long long>(passageAudit.unsupported),
static_cast<unsigned long long>(passageAudit.gradeFailures),mouthsInContent?2:0,
mouthsInRadius?2:0,passageAudit.passed?"PASS":"FAIL");
std::printf("[PassageNaturalnessAudit] id=%s flat_run_max_m=%.3f limit_m=%.3f wall_relief_p2p_m=%.3f minimum_m=%.3f samples=%llu missing=%llu status=%s\n",
passage.stableId.c_str(),naturalAudit.maximumFlatRunMetres,MaximumFlatRunMetres,
naturalAudit.wallReliefPeakToPeakMetres,MinimumWallReliefMetres,
static_cast<unsigned long long>(naturalAudit.wallSamples),
static_cast<unsigned long long>(naturalAudit.missingWallSamples),
naturalAudit.passed?"PASS":"FAIL");
std::printf("[PassageMouthProfileAudit] id=%s floor_samples=%llu floor_missing=%llu wall_samples=%llu wall_missing=%llu floor_step_scan=centerline floor_flat_step_run_m=%.3f floor_step_m=%.3f wall_flat_step_run_m=%.3f wall_step_m=%.3f spacing_m=%.3f plateau=(%.3f,%.3f) status=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(mouthProfileAudit.floorSamples),
static_cast<unsigned long long>(mouthProfileAudit.missingFloorSamples),
static_cast<unsigned long long>(mouthProfileAudit.wallSamples),
static_cast<unsigned long long>(mouthProfileAudit.missingWallSamples),
mouthProfileAudit.floorFlatStepRunMetres,mouthProfileAudit.floorStepMetres,
mouthProfileAudit.wallFlatStepRunMetres,mouthProfileAudit.wallStepMetres,
PassageProfileSpacingMetres,PassageProfilePlateauMinimumMetres,
PassageProfileStepThresholdMetres,mouthProfileAudit.passed?"PASS":"FAIL");
std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s floor_period_m=%.3f floor_amplitude_m=%.4f floor_amplitude_cm=%.2f floor_coherent_period_m=%.3f floor_coherent_amplitude_m=%.4f floor_coverage=%llu/%llu floor_threshold_m=0.015 floor_beaded_control_amplitude_m=%.4f floor_beaded_control_detected=%s status=%s\n",
passage.stableId.c_str(),rippleAudit.periodMetres,
rippleAudit.amplitudeMetres,rippleAudit.amplitudeMetres*100.0,
rippleAudit.coherentPeriodMetres,rippleAudit.coherentAmplitudeMetres,
rippleAudit.coherentAmplitudeMetres*100.0,
rippleAudit.localPeakAmplitudeMetres,
static_cast<unsigned long long>(rippleAudit.samples),
static_cast<unsigned long long>(rippleAudit.expectedSamples),
rippleAudit.controlAmplitudeMetres,rippleAudit.controlDetected?"true":"false",
rippleAudit.floorPeriodMetres,rippleAudit.floorAmplitudeMetres,
rippleAudit.floorAmplitudeMetres*100.0,
rippleAudit.floorCoherentPeriodMetres,rippleAudit.floorCoherentAmplitudeMetres,
static_cast<unsigned long long>(rippleAudit.floorSamples),
static_cast<unsigned long long>(rippleAudit.floorExpectedSamples),
rippleAudit.floorControlAmplitudeMetres,
rippleAudit.floorControlDetected?"true":"false",
rippleAudit.passed?"PASS":"FAIL");
for(std::size_t sample=0;sample<rippleAudit.floorPeakProfile.size();sample+=4)
{
const auto& value=rippleAudit.floorPeakProfile[sample];
std::printf("[PassageFloorRippleSample] id=%s distance_m=%.3f "
"expected_floor_m=%.4f sampled_floor_m=%.4f residual_m=%.4f "
"route_xyz_m=(%.3f,%.3f,%.3f)\n",
passage.stableId.c_str(),value[0],value[1],value[2],value[2]-value[1],
value[3],value[4],value[5]);
}
std::printf("[PassageOpenAirAudit] id=%s support_samples=%llu violations=%llu column_samples=%llu short_span_samples=%llu l24_ungated_violations=%llu route_support_samples=%llu route_support_violations=%llu spacing_m=%.3f status=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(openAirAudit.supportSamples),
static_cast<unsigned long long>(openAirAudit.violations),
static_cast<unsigned long long>(openAirAudit.columnSamples),
static_cast<unsigned long long>(openAirAudit.shortSpanSamples),
static_cast<unsigned long long>(openAirAudit.legacyViolations),
static_cast<unsigned long long>(openAirAudit.routeSupportSamples),
static_cast<unsigned long long>(openAirAudit.routeSupportViolations),
PassageSupportAuditSpacingMetres,
openAirAudit.violations==0?"PASS":"FAIL");
for(std::size_t i=0;i<openAirAudit.firstViolationCount;++i)
std::printf("[PassageOpenAirAuditSample] id=%s kind=unsupported_support xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),openAirAudit.firstViolations[i][0],
openAirAudit.firstViolations[i][1],openAirAudit.firstViolations[i][2],
openAirAudit.firstViolations[i][3]);
for(std::size_t i=0;i<passageAudit.firstBlockedCount;++i)
{
const auto& sample=passageAudit.firstBlocked[i];
double nearestDistanceSquared=std::numeric_limits<double>::infinity();
std::size_t nearestSegment=0;
double nearestT=0.0;
double nearestPassageSdf=std::numeric_limits<double>::infinity();
std::size_t nearestPassageSegment=0;
for(std::size_t segment=0;segment+1<path.size();++segment)
{
const auto& a=path[segment];const auto& b=path[segment+1];
const double dx=b[0]-a[0],dy=b[1]-a[1],dz=b[2]-a[2];
const double lengthSquared=dx*dx+dy*dy+dz*dz;
const double t=lengthSquared>0.0?std::clamp(
((sample[0]/coreMetres-a[0])*dx+(sample[1]/coreMetres-a[1])*dy
+(sample[2]/coreMetres-a[2])*dz)/lengthSquared,0.0,1.0):0.0;
const double ex=sample[0]/coreMetres-(a[0]+t*dx);
const double ey=sample[1]/coreMetres-(a[1]+t*dy);
const double ez=sample[2]/coreMetres-(a[2]+t*dz);
const double distanceSquared=ex*ex+ey*ey+ez*ez;
if(distanceSquared<nearestDistanceSquared)
{nearestDistanceSquared=distanceSquared;nearestSegment=segment;nearestT=t;}
}
for(std::size_t segment=0;segment+1<passage.controlPoints.size();++segment)
{
const auto& a=passage.controlPoints[segment];
const auto& b=passage.controlPoints[segment+1];
const double ax=qToMetres(a.positionSubvoxels[0]);
const double ay=qToMetres(a.positionSubvoxels[1]);
const double az=qToMetres(a.positionSubvoxels[2]);
const double dx=qToMetres(b.positionSubvoxels[0]-a.positionSubvoxels[0]);
const double dy=qToMetres(b.positionSubvoxels[1]-a.positionSubvoxels[1]);
const double dz=qToMetres(b.positionSubvoxels[2]-a.positionSubvoxels[2]);
const double lengthSquared=dx*dx+dy*dy+dz*dz;
const double t=lengthSquared>0.0?std::clamp(
((sample[0]-ax)*dx+(sample[1]-ay)*dy+(sample[2]-az)*dz)
/lengthSquared,0.0,1.0):0.0;
const double ex=sample[0]-(ax+t*dx),ey=sample[1]-(ay+t*dy),
ez=sample[2]-(az+t*dz);
const double radius=qToMetres(a.radiusSubvoxels)
+(qToMetres(b.radiusSubvoxels)-qToMetres(a.radiusSubvoxels))*t;
const double signedDistance=std::sqrt(ex*ex+ey*ey+ez*ez)-radius;
if(signedDistance<nearestPassageSdf)
{nearestPassageSdf=signedDistance;nearestPassageSegment=segment;}
}
const VoxelForgeCore::Vec3d nativePosition{sample[0]/coreMetres,
sample[1]/coreMetres,sample[2]/coreMetres};
const float nativeDensity=blockedWorld.densityAt(nativePosition);
const bool passageColumn=Shape.isPassageColumnSample(passageIndex,
nearestSegment,nativePosition);
std::printf("[ResolvedPassageAuditSample] id=%s kind=blocked xyz_m=(%.3f,%.3f,%.3f) density=%.6f native_density=%.6f segment=%zu t=%.3f passage_segment=%zu passage_sdf_m=%.3f passage_column=%d native_path=%s\n",
passage.stableId.c_str(),sample[0],sample[1],sample[2],sample[3],
nativeDensity,nearestSegment,nearestT,nearestPassageSegment,
nearestPassageSdf,passageColumn?1:0,
blockedWorld.densityDispatchPathAt(nativePosition).c_str());
}
for(std::size_t i=0;i<passageAudit.firstUnsupportedCount;++i)
{
std::printf("[ResolvedPassageAuditSample] id=%s kind=unsupported xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),passageAudit.firstUnsupported[i][0],
passageAudit.firstUnsupported[i][1],passageAudit.firstUnsupported[i][2],
passageAudit.firstUnsupported[i][3]);
}
for(std::size_t segment=0;segment<segmentSupport.size();++segment)
{
const auto& item=segmentSupport[segment];
if(!item.hasUnsupported)continue;
const auto& a=path[segment];const auto& b=path[segment+1];
const auto& sample=item.firstUnsupported;
const double firstX=sample[0]/coreMetres;
const double firstY=sample[1]/coreMetres;
const double firstZ=(sample[2]-0.125)/coreMetres;
const VoxelForgeCore::Vec3d bridgeProbe{sample[0]/coreMetres,
sample[1]/coreMetres,(sample[2]-0.25)/coreMetres};
const bool columnAtSupport=Shape.isPassageColumnSample(passageIndex,
segment,bridgeProbe);
std::printf("[ResolvedPassageSupportSegment] id=%s segment=%zu route_z_m=%.3f..%.3f centers=%llu unsupported=%llu native_unsupported=%llu first_foot_m=(%.3f,%.3f,%.3f) column_at_d025=%d native_support_probes=%u/5 native_density_d0125_d1_d2_d4=(%.6f,%.6f,%.6f,%.6f) native_path=%s\n",
passage.stableId.c_str(),segment,
std::min(a[2],b[2])*coreMetres,std::max(a[2],b[2])*coreMetres,
static_cast<unsigned long long>(item.centers),
static_cast<unsigned long long>(item.unsupported),
static_cast<unsigned long long>(item.nativeUnsupported),
sample[0],sample[1],sample[2],columnAtSupport?1:0,
item.firstNativeSupportedProbes,item.firstNativeDensities[0],item.firstNativeDensities[1],
item.firstNativeDensities[2],item.firstNativeDensities[3],
blockedWorld.densityDispatchPathAt({firstX,firstY,firstZ}).c_str());
}
}
std::uint64_t routePoints=0,routePasses=0,routeWalkPasses=0,routeBindings=0,routeBindingFailures=0;
struct FRouteAuditInput
{
std::int32_t strateIndex=0;
std::vector<std::array<double,3>> path;
double supportStart=0.125,supportStep=0.125,supportMaximum=0.25,
supportProbeRadius=0.45;
std::uint32_t minimumSupportProbes=3;
};
std::vector<FRouteAuditInput> routeAuditInputs;
for(const auto& stratum:ResolvedLayout->strates)
{
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> anchors;
for(const auto& anchor:stratum.anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)anchors.push_back(&anchor);
if(anchors.size()<2)continue;
std::vector<std::array<double,3>> route;route.reserve(anchors.size());
for(const auto* anchor:anchors)
{
route.push_back({qToMetres(anchor->values[0])/coreMetres,
qToMetres(anchor->values[1])/coreMetres,
qToMetres(anchor->values[2])/coreMetres});
++routePoints;
}
double supportStartMetres=0.125,supportStepMetres=0.125,
supportMaximumMetres=0.25,supportProbeRadiusMetres=0.45;
std::uint32_t minimumSupportProbes=3;
const VoxelForgeCore::WorldAssemblyRouteConstraintsV1* routeConstraints=nullptr;
if(Assembly)
{
const auto worldRoute=std::find_if(Assembly->plan.strates.begin(),
Assembly->plan.strates.end(),[&](const auto& candidate)
{return candidate.strateIndex==stratum.strateIndex;});
if(worldRoute!=Assembly->plan.strates.end()
&&worldRoute->routeConstraints.version==1)
routeConstraints=&worldRoute->routeConstraints;
const auto islandRoute=std::find_if(Assembly->floatingIslands.begin(),
Assembly->floatingIslands.end(),[&](const auto& candidate)
{return candidate.strateIndex==stratum.strateIndex;});
if(islandRoute!=Assembly->floatingIslands.end()
&&islandRoute->manifest.recipe.routeConstraints.version==1)
routeConstraints=&islandRoute->manifest.recipe.routeConstraints;
}
if(routeConstraints)
{
const double qMetres=coreMetres
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
minimumSupportProbes=std::clamp<std::uint32_t>(
routeConstraints->minimumSupportProbes,1,5);
supportProbeRadiusMetres=routeConstraints->supportProbeRadiusSubvoxels*qMetres;
if(stratum.generatorKind=="FloatingIslands")
{
supportStartMetres=(routeConstraints->minimumClearanceSubvoxels
+VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/2)*qMetres;
supportStepMetres=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*0.5*qMetres;
supportMaximumMetres=(routeConstraints->minimumClearanceSubvoxels
+routeConstraints->supportSearchDepthSubvoxels)*qMetres;
}
else
{
const std::int64_t spacing=std::min<std::int64_t>(
routeConstraints->sweepSpacingSubvoxels,
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/4);
supportStepMetres=std::max<std::int64_t>(1,spacing)*qMetres;
supportStartMetres=supportStepMetres;
supportMaximumMetres=routeConstraints->supportSearchDepthSubvoxels*qMetres;
}
}
const FWalkAudit routeAudit=auditPlayerPath(Shape,route,supportStartMetres,
supportStepMetres,supportMaximumMetres,minimumSupportProbes,
supportProbeRadiusMetres,nullptr,nullptr);
routeAuditInputs.push_back({stratum.strateIndex,route,supportStartMetres,
supportStepMetres,supportMaximumMetres,supportProbeRadiusMetres,
minimumSupportProbes});
bool binding=true;
for(const auto& passage:ResolvedLayout->passages)
{
const auto equalPosition=[](const auto& a,const auto& b)
{return a[0]==b[0]&&a[1]==b[1]&&a[2]==b[2];};
if(passage.upperStrateIndex==stratum.strateIndex)
{
const auto rootedMouth=std::find_if(stratum.anchors.begin(),
stratum.anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_anchor"&&anchor.values.size()>=10;});
const std::array<std::int64_t,3> departure=
rootedMouth!=stratum.anchors.end()
?std::array<std::int64_t,3>{{rootedMouth->values[7],
rootedMouth->values[8],rootedMouth->values[9]}}
:std::array<std::int64_t,3>{{anchors.back()->values[0],
anchors.back()->values[1],anchors.back()->values[2]}};
binding&=equalPosition(passage.upperMouthSubvoxels,
departure);
}
if(passage.lowerStrateIndex==stratum.strateIndex)
{
const auto passageArrival=std::find_if(stratum.anchors.begin(),
stratum.anchors.end(),[](const auto& anchor)
{return anchor.kind=="passage_arrival"&&anchor.values.size()>=3;});
const std::array<std::int64_t,3> arrival=passageArrival!=stratum.anchors.end()
?std::array<std::int64_t,3>{{passageArrival->values[0],
passageArrival->values[1],passageArrival->values[2]}}
:std::array<std::int64_t,3>{{anchors.front()->values[0],
anchors.front()->values[1],anchors.front()->values[2]}};
binding&=equalPosition(passage.lowerMouthSubvoxels,
arrival);
}
}
++routePasses;routeWalkPasses+=routeAudit.passed;
routeBindings+=binding;routeBindingFailures+=!binding;
std::printf("[ResolvedStrateRouteAudit] strate=%d route_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_binding=%s status=%s\n",
stratum.strateIndex,anchors.size(),static_cast<unsigned long long>(routeAudit.centers),
static_cast<unsigned long long>(routeAudit.capsuleSamples),
static_cast<unsigned long long>(routeAudit.blocked),
static_cast<unsigned long long>(routeAudit.supportSamples),
static_cast<unsigned long long>(routeAudit.unsupported),
static_cast<unsigned long long>(routeAudit.gradeFailures),binding?"PASS":"FAIL",
routeAudit.passed&&binding?"PASS":"FAIL");
for(std::size_t i=0;i<routeAudit.firstBlockedCount;++i)
std::printf("[ResolvedStrateRouteAuditSample] strate=%d kind=blocked xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
stratum.strateIndex,routeAudit.firstBlocked[i][0],routeAudit.firstBlocked[i][1],
routeAudit.firstBlocked[i][2],routeAudit.firstBlocked[i][3]);
for(std::size_t i=0;i<routeAudit.firstUnsupportedCount;++i)
std::printf("[ResolvedStrateRouteAuditSample] strate=%d kind=unsupported xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
stratum.strateIndex,routeAudit.firstUnsupported[i][0],
routeAudit.firstUnsupported[i][1],routeAudit.firstUnsupported[i][2],
routeAudit.firstUnsupported[i][3]);
}
for(const auto& passage:ResolvedLayout->passages)
{
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
for(const auto& point:passage.controlPoints)
{
const double playerZ=static_cast<double>(point.positionSubvoxels[2]
-point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
*1000000.0/World.CoreVoxelSizeMicrons;
path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres,
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
const FWalkAudit blockedAudit=auditPlayerPath(blockedWorld,path,
0.125,0.125,0.25,3,0.45,nullptr,nullptr);
blockedControls+=blockedAudit.blocked>0&&!blockedAudit.passed;
std::printf("[ResolvedPassageBlockedControl] id=%s blocked_capsule_samples=%llu detected=%s\n",
passage.stableId.c_str(),static_cast<unsigned long long>(blockedAudit.blocked),
blockedAudit.blocked>0&&!blockedAudit.passed?"true":"false");
}
for(const auto& input:routeAuditInputs)
{
const FWalkAudit controlRoute=auditPlayerPath(blockedWorld,input.path,
input.supportStart,input.supportStep,input.supportMaximum,
input.minimumSupportProbes,input.supportProbeRadius,nullptr,nullptr);
std::printf("[ResolvedStrateRouteBlockedControl] strate=%d blocked=%llu unsupported=%llu status=%s\n",
input.strateIndex,static_cast<unsigned long long>(controlRoute.blocked),
static_cast<unsigned long long>(controlRoute.unsupported),
controlRoute.passed?"PASS":"FAIL");
}
const bool l24OpenAirControlDetected=openAirLegacyViolations>0;
std::printf("[PassageOpenAirNegativeControl] source=L24_ungated_support unsupported_samples=%llu detected=%s\n",
static_cast<unsigned long long>(openAirLegacyViolations),
l24OpenAirControlDetected?"true":"false");
std::printf("[PassageOpenAirAuditSummary] interfaces=%llu samples=%llu violations=%llu column_samples=%llu short_span_samples=%llu l24_negative_control=%s status=%s\n",
static_cast<unsigned long long>(openAirAudits),
static_cast<unsigned long long>(openAirSamples),
static_cast<unsigned long long>(openAirViolations),
static_cast<unsigned long long>(openAirColumnSamples),
static_cast<unsigned long long>(openAirShortSpanSamples),
l24OpenAirControlDetected?"DETECTED":"MISSED",
openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
?"PASS":"FAIL");
const bool l26NoLongBridgeControlDetected=l26NegativeControlApplicable
&&l26LegacyBridgeSpanMetres>12.5;
const bool l26NoLongBridgeControlPass=!l26NegativeControlApplicable
||l26NoLongBridgeControlDetected;
noLongBridgeAuditPassed=longestUncolumnedSpanMetres<=12.5
&&l26NoLongBridgeControlPass;
std::printf("[PassageNoLongBridgeNegativeControl] source=L26_SurfaceWorld_bridge applicable=%s longest_uncolumned_m=%.3f threshold_m=12.500 detected=%s\n",
l26NegativeControlApplicable?"true":"false",l26LegacyBridgeSpanMetres,
l26NoLongBridgeControlDetected?"true":"false");
std::printf("[PassageNoLongBridgeAudit] columns=%llu short_grounded_spans=%llu longest_uncolumned_m=%.3f threshold_m=12.500 longest_short_span_m=%.3f l26_negative_control=%s status=%s\n",
static_cast<unsigned long long>(columnCrossings),
static_cast<unsigned long long>(shortGroundedSpans),longestUncolumnedSpanMetres,
longestShortSpanMetres,l26NegativeControlApplicable
?(l26NoLongBridgeControlDetected?"DETECTED":"MISSED"):"NOT_APPLICABLE",
noLongBridgeAuditPassed?"PASS":"FAIL");
std::printf("[PassageRockColumnAuditSummary] columns=%llu connected_ends=%llu/%llu short_spans=%llu wall_or_support_failures=%llu disconnected_end_control=%s status=%s\n",
static_cast<unsigned long long>(columnCrossings),
static_cast<unsigned long long>(columnConnectedEnds),
static_cast<unsigned long long>(columnCrossings*2),
static_cast<unsigned long long>(shortGroundedSpans),
static_cast<unsigned long long>(columnRouteFailures+columnWallFailures),
columnDisconnectedEndControlApplicable
?(columnDisconnectedEndControlDetected?"DETECTED":"MISSED")
:"NOT_APPLICABLE",
columnAuditsPassed?"PASS":"FAIL");
const bool l23SmoothWallDetected=!looksNatural(0.0,0.0);
std::printf("[PassageNaturalnessNegativeControl] source=L23_smooth_unrelieved_wall relief_p2p_m=0.000 threshold_m=%.3f detected=%s\n",
MinimumWallReliefMetres,l23SmoothWallDetected?"true":"false");
std::printf("[PassageMouthProfileNegativeControl] source=L23_terraced_geometry flat_run_m=%.3f following_step_m=%.3f thresholds=(%.3f,%.3f) detected=%s\n",
l23TerraceControlResult.first,l23TerraceControlResult.second,
PassageProfilePlateauMinimumMetres,PassageProfileStepThresholdMetres,
l23TerraceControlDetected?"true":"false");
std::printf("[PassageNaturalnessSummary] passed=%llu/%llu l23_negative_control=%s flat_run_limit_m=%.3f wall_relief_min_m=%.3f status=%s\n",
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
l23SmoothWallDetected?"DETECTED":"MISSED",MaximumFlatRunMetres,
MinimumWallReliefMetres,naturalPasses==passageCount&&l23SmoothWallDetected?"PASS":"FAIL");
std::printf("[PassageMouthProfileSummary] passed=%llu/%llu spacing_m=%.3f plateau_min_m=%.3f following_step_min_m=%.3f l23_terrace_negative_control=%s status=%s\n",
static_cast<unsigned long long>(mouthProfilePasses),
static_cast<unsigned long long>(passageCount),PassageProfileSpacingMetres,
PassageProfilePlateauMinimumMetres,PassageProfileStepThresholdMetres,
l23TerraceControlDetected?"DETECTED":"MISSED",
mouthProfilePasses==passageCount&&l23TerraceControlDetected?"PASS":"FAIL");
std::printf("[PassageRippleAuditSummary] passed=%llu/%llu synthetic_spheres_negative_control=%s max_amplitude_m=0.035 floor_beaded_negative_control=%s max_floor_amplitude_m=0.015 status=%s\n",
static_cast<unsigned long long>(ripplePasses),
static_cast<unsigned long long>(passageCount),
rippleControlsDetected==passageCount?"DETECTED":"MISSED",
floorRippleControlsDetected==passageCount?"DETECTED":"MISSED",
ripplePasses==passageCount?"PASS":"FAIL");
const bool auditPassed=passageCount>0&&passagePasses==passageCount
&&naturalPasses==passageCount&&l23SmoothWallDetected
&&mouthProfilePasses==passageCount&&l23TerraceControlDetected
&&ripplePasses==passageCount
&&openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected
&&columnAuditsPassed&&noLongBridgeAuditPassed
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings
&&routeBindingFailures==0
&&blockedCompiled&&blockedControls==passageCount;
std::printf("[ResolvedPassageAuditSummary] interfaces=%llu passed=%llu natural=%llu/%llu strate_routes=%llu route_walkable=%llu route_points=%llu route_bindings=%llu route_binding_failures=%llu blocked_controls=%llu/%llu status=%s\n",
static_cast<unsigned long long>(passageCount),static_cast<unsigned long long>(passagePasses),
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
static_cast<unsigned long long>(routePasses),static_cast<unsigned long long>(routeWalkPasses),
static_cast<unsigned long long>(routePoints),
static_cast<unsigned long long>(routeBindings),static_cast<unsigned long long>(routeBindingFailures),
static_cast<unsigned long long>(blockedControls),static_cast<unsigned long long>(passageCount),
auditPassed?"PASS":"FAIL");
if(!auditPassed)
{Streamer.Stop();return 10;}
}
if(bAuditResolvedLayoutBoundaries)
{
if(ResolvedLayout==nullptr)
{Streamer.Stop();std::fprintf(stderr,"[ResolvedLayoutProbe] missing plan-time snapshot\n");return 2;}
std::vector<std::int64_t> endpoints;
for(const auto& Stratum:ResolvedLayout->strates)
{
endpoints.push_back(Stratum.interiorBottomMicrometres);
endpoints.push_back(Stratum.interiorTopMicrometres);
endpoints.push_back(Stratum.ceiling.bottomMicrometres);
endpoints.push_back(Stratum.ceiling.topMicrometres);
endpoints.push_back(Stratum.bedrock.bottomMicrometres);
endpoints.push_back(Stratum.bedrock.topMicrometres);
}
for(std::size_t StratumIndex=0;StratumIndex+1<ResolvedLayout->strates.size();++StratumIndex)
{
const auto& Upper=ResolvedLayout->strates[StratumIndex];
if(Upper.transitionMode=="Hard"||Upper.transitionWidthMicrometres<=0)continue;
endpoints.push_back(Upper.interiorBottomMicrometres-Upper.transitionWidthMicrometres);
endpoints.push_back(Upper.interiorBottomMicrometres+Upper.transitionWidthMicrometres);
}
std::sort(endpoints.begin(),endpoints.end());
endpoints.erase(std::unique(endpoints.begin(),endpoints.end()),endpoints.end());
std::uint64_t probes=0,disagreements=0;
const double CoreVoxelMicrometres=std::max<std::uint32_t>(1,World.CoreVoxelSizeMicrons);
const auto expectedAt=[&](std::int64_t zMicrometres)
{
std::vector<std::string> candidates;
for(const auto& Stratum:ResolvedLayout->strates)
{
const auto contains=[zMicrometres](const VoxelForgeCore::ResolvedLayoutBandV2& Band)
{return Band.presentInCurrentField&&zMicrometres>=Band.bottomMicrometres
&&zMicrometres<Band.topMicrometres;};
if(contains(Stratum.ceiling))candidates.push_back(Stratum.generatorKind+"/ceiling");
if(contains(Stratum.content))candidates.push_back(Stratum.generatorKind+"/content");
if(contains(Stratum.bedrock))candidates.push_back(Stratum.generatorKind+"/bedrock");
}
return candidates;
};
const std::array<std::int64_t,3> offsets{{
-static_cast<std::int64_t>(World.CoreVoxelSizeMicrons),0,
static_cast<std::int64_t>(World.CoreVoxelSizeMicrons)}};
const std::int64_t stackMinimum=std::min_element(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[](const auto& A,const auto& B)
{return A.bedrock.bottomMicrometres<B.bedrock.bottomMicrometres;})
->bedrock.bottomMicrometres;
const std::int64_t stackMaximum=std::max_element(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[](const auto& A,const auto& B)
{return A.ceiling.topMicrometres<B.ceiling.topMicrometres;})
->ceiling.topMicrometres;
for(const std::int64_t Endpoint:endpoints)
for(const std::int64_t Offset:offsets)
{
const std::int64_t zMicrometres=Endpoint+Offset;
const double zVoxel=static_cast<double>(zMicrometres)/CoreVoxelMicrometres;
const VoxelForgeCore::Vec3d position{0.0,0.0,zVoxel};
const std::string actual=Shape.densityDispatchPathAt(position);
const auto expected=expectedAt(zMicrometres);
std::string expectedLabel;
std::vector<std::string> expectedGenerators;
for(const auto& Candidate:expected)
{
if(!expectedLabel.empty())expectedLabel+=',';
expectedLabel+=Candidate;
const auto Separator=Candidate.find('/');
const std::string Kind=Candidate.substr(0,Separator);
if(std::find(expectedGenerators.begin(),expectedGenerators.end(),Kind)==expectedGenerators.end())
expectedGenerators.push_back(Kind);
}
const float density=Shape.densityAt(position);
const bool solid=density<0.0f;
const bool outsideStack=zMicrometres<stackMinimum||zMicrometres>=stackMaximum;
if(expected.empty())expectedLabel=outsideStack?"outside-stack/air":"uncovered";
std::string actualGenerator;
if(actual=="SurfaceWorld-native"||actual=="SurfaceWorld-legacy")actualGenerator="SurfaceWorld";
else if(actual=="FloatingIslands-native")actualGenerator="FloatingIslands";
else if(actual.rfind("compiled-analytic/",0)==0)actualGenerator=actual.substr(18);
const bool mismatch=expected.empty()
?(!outsideStack||solid)
:std::find(expectedGenerators.begin(),expectedGenerators.end(),actualGenerator)==expectedGenerators.end();
++probes;disagreements+=mismatch?1u:0u;
std::printf("[ResolvedLayoutProbe] endpoint_um=%lld offset_um=%lld z_m=%.3f expected=%s actual=%s density=%.7g occupancy=%s disagreement=%s\n",
static_cast<long long>(Endpoint),static_cast<long long>(Offset),
static_cast<double>(zMicrometres)/1000000.0,expectedLabel.c_str(),actual.c_str(),density,
solid?"solid":"air",mismatch?"YES":"no");
}
std::printf("[ResolvedLayoutProbeSummary] probes=%llu disagreements=%llu status=%s\n",
static_cast<unsigned long long>(probes),static_cast<unsigned long long>(disagreements),
disagreements==0?"PASS":"DEVIATIONS_RECORDED");
Streamer.Stop();
return 0;
}
const auto ShapeReady=Clock::now();
const double ShapeSeconds=std::chrono::duration<double>(ShapeReady-ShapeBuildStart).count();
if(bAuditTileShapeReadiness)
{
VoxelForgeCore::TileGenerationOptions CompiledOptions;
VoxelForgeCore::TileGenerationOptions NativeOnlyOptions;
CompiledOptions.hashDensity=true;
NativeOnlyOptions.hashDensity=true;
NativeOnlyOptions.diagnosticForceNativeOnly=true;
int32 Compared=0,Mismatched=0;
for(const FVoxelTileKey& Tile:ShapeFreeTiles)
{
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey CoreKey{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string CompiledError,NativeOnlyError;
const auto Compiled=Shape.generateTile(CoreKey,CompiledOptions,CompiledError);
const auto NativeOnly=Shape.generateTile(CoreKey,NativeOnlyOptions,NativeOnlyError);
++Compared;
const bool bSame=Compiled&&NativeOnly
&&Compiled->densityHash==NativeOnly->densityHash
&&Compiled->meshHash==NativeOnly->meshHash
&&Compiled->payloadHash==NativeOnly->payloadHash
&&Compiled->topologyHash==NativeOnly->topologyHash;
if(!bSame)
{
++Mismatched;
std::printf("[ShapeReadinessEquivalence] key=(%d,%d,%d,lod%d) match=0 compiled=%s native_only=%s density=%s mesh=%s\n",
Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z,Tile.Level,
Compiled?"ok":CompiledError.c_str(),NativeOnly?"ok":NativeOnlyError.c_str(),
Compiled&&NativeOnly&&Compiled->densityHash==NativeOnly->densityHash?"same":"different",
Compiled&&NativeOnly&&Compiled->meshHash==NativeOnly->meshHash?"same":"different");
}
}
std::printf("[ShapeReadinessEquivalence] compared_near_ring=%d mismatches=%d status=%s\n",
Compared,Mismatched,Mismatched==0?"PASS":"FAIL");
if(Mismatched!=0)
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] native-only tile generation differs from compiled generation.\n");
return 9;
}
}
if(bAuditBasePageEquivalence)
{
std::vector<VoxelForgeCore::TileKey> AuditKeys;
AuditKeys.reserve(48);
const auto AddAuditCandidates=[&](int32 PreferredLOD)
{
const std::size_t ExistingCount=AuditKeys.size();
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(Tile.Level!=PreferredLOD)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},
Tile.Level};
if(Shape.isTileShapeFree(Key)||Shape.needsTileRegion(Key))continue;
if(std::find(AuditKeys.begin(),AuditKeys.end(),Key)==AuditKeys.end())
AuditKeys.push_back(Key);
if(AuditKeys.size()>=48||AuditKeys.size()-ExistingCount>=4)return;
}
};
for(int32 PreferredLOD:{1,0,2,3,4,5,6,7,8})
{
AddAuditCandidates(PreferredLOD);
if(AuditKeys.size()>=48)break;
}
if(AuditKeys.empty())
{
std::printf("[BasePageTileEquivalence] status=UNAVAILABLE reason=no_tile_reachable_through_both_routes\n");
Streamer.Stop();
return 9;
}
VoxelForgeCore::TileGenerationOptions HashOptions;
HashOptions.hashDensity=true;
HashOptions.profileMesherStages=true;
bool bFoundEquivalentTile=false;
std::size_t CandidatesTried=0;
VoxelForgeCore::TileKey EquivalentKey{};
for(const VoxelForgeCore::TileKey& AuditKey:AuditKeys)
{
++CandidatesTried;
std::string BaseError,PageError,CompileError;
const auto BaseGenerationStart=Clock::now();
const auto BaseTile=Shape.generateTile(AuditKey,HashOptions,BaseError);
const double BaseGenerationSeconds=std::chrono::duration<double>(
Clock::now()-BaseGenerationStart).count();
if(!BaseTile)
{
std::printf("[BasePageTileEquivalenceCandidate] key=(%d,%d,%d,lod%d) base=FAIL reason=%s\n",
AuditKey.coordinate.x,AuditKey.coordinate.y,AuditKey.coordinate.z,
AuditKey.lod,BaseError.c_str());
continue;
}
const std::array<VoxelForgeCore::TileKey,1> AuditTiles={AuditKey};
VoxelForgeCore::TileRegionCompileStats PageBuildStats;
std::size_t PageTileCount=0;
const auto PageCompileStart=Clock::now();
const bool bPageBuilt=Shape.compileTileRegion(AuditTiles,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
CompileError,&PageTileCount,&PageBuildStats,true,true);
const double PageCompileSeconds=std::chrono::duration<double>(
Clock::now()-PageCompileStart).count();
const auto PageGenerationStart=Clock::now();
const auto PageTile=bPageBuilt?Shape.generateTile(AuditKey,HashOptions,PageError)
:std::optional<VoxelForgeCore::TileMesh>{};
const double PageGenerationSeconds=std::chrono::duration<double>(
Clock::now()-PageGenerationStart).count();
const bool bDensitySame=PageTile&&BaseTile->densityHash==PageTile->densityHash;
const bool bMeshSame=PageTile&&BaseTile->meshHash==PageTile->meshHash;
const bool bPayloadSame=PageTile&&BaseTile->payloadHash==PageTile->payloadHash;
const bool bTopologySame=PageTile&&BaseTile->topologyHash==PageTile->topologyHash;
const bool bActualPage=PageTile&&PageTile->diagnostics.analyticRegionPageRoute;
const int32 Matches=static_cast<int32>(bDensitySame)+static_cast<int32>(bMeshSame)
+static_cast<int32>(bPayloadSame)+static_cast<int32>(bTopologySame);
const bool bSame=bActualPage&&Matches==4;
std::printf("[BasePageTileEquivalenceCandidate] key=(%d,%d,%d,lod%d) page_built=%d page_route_verified=%d page_keys=%zu page_nodes=%llu base_route=base-shape page_route=analytic-page base_generation_ms=%.3f page_compile_ms=%.3f page_generation_ms=%.3f density=%s mesh=%s payload=%s topology=%s base_density=0x%016llx page_density=0x%016llx status=%s error=%s\n",
AuditKey.coordinate.x,AuditKey.coordinate.y,AuditKey.coordinate.z,AuditKey.lod,
bPageBuilt?1:0,bActualPage?1:0,PageTileCount,
static_cast<unsigned long long>(PageBuildStats.latticeNodes),
BaseGenerationSeconds*1000.0,PageCompileSeconds*1000.0,
PageGenerationSeconds*1000.0,
bDensitySame?"same":"DIFF",bMeshSame?"same":"DIFF",
bPayloadSame?"same":"DIFF",bTopologySame?"same":"DIFF",
static_cast<unsigned long long>(BaseTile->densityHash),
static_cast<unsigned long long>(PageTile?PageTile->densityHash:0),
bSame?"PASS":"DIFF",bPageBuilt?PageError.c_str():CompileError.c_str());
if(bSame)
{
bFoundEquivalentTile=true;
EquivalentKey=AuditKey;
break;
}
}
std::printf("[BasePageTileEquivalence] candidates=%zu tried=%zu matching_key=(%d,%d,%d,lod%d) status=%s\n",
AuditKeys.size(),CandidatesTried,EquivalentKey.coordinate.x,
EquivalentKey.coordinate.y,EquivalentKey.coordinate.z,EquivalentKey.lod,
bFoundEquivalentTile?"PASS":"FAIL");
if(!bFoundEquivalentTile)
{
Streamer.Stop();
return 9;
}
}
if(bAuditRouteParity)
{
struct FRouteAuditCandidate
{
VoxelForgeCore::TileKey Key;
bool bWouldRequestPage=false;
};
struct FRouteAuditRow
{
FRouteAuditCandidate Candidate;
std::optional<VoxelForgeCore::TileMesh> Base;
};
VoxelForgeCore::TileGenerationOptions CaptureOptions;
CaptureOptions.hashDensity=true;
CaptureOptions.captureDensitySamples=true;
CaptureOptions.forceFullDensityCapture=true;
CaptureOptions.profileMesherStages=true;
std::vector<FRouteAuditRow> Rows;
Rows.reserve(static_cast<std::size_t>(World.FullResClipLevels)*8);
std::vector<VoxelForgeCore::TileKey> PageKeys;
PageKeys.reserve(Rows.capacity());
const int32 AuditPageLODs=std::min(World.FullResClipLevels,3);
std::vector<const FStandaloneDesiredTileSet*> CandidateSets{&Desired};
if(bHasCameraStep)CandidateSets.push_back(&MovedDesired);
for(int32 LOD=0;LOD<AuditPageLODs;++LOD)
{
for(const bool bPageRequested:{true,false})
{
int32 SurfaceCandidates=0;
bool bHaveFlatCandidate=false;
int32 Inspected=0;
for(const FStandaloneDesiredTileSet* CandidateSet:CandidateSets)
{
for(const FVoxelTileKey& Tile:CandidateSet->Tiles)
{
if(Tile.Level!=LOD)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
if(Shape.isTileShapeFree(Key)
||Shape.needsTileRegion(Key)!=bPageRequested)continue;
if(Inspected++>=256)break;
std::string BaseError;
auto Base=Shape.generateTile(Key,CaptureOptions,BaseError);
if(!Base)
{
std::printf("[RouteParityCandidate] route=%s key=(%d,%d,%d,lod%d) base=FAIL error=%s\n",
bPageRequested?"actual-page":"base-covered-page",Key.coordinate.x,
Key.coordinate.y,Key.coordinate.z,Key.lod,BaseError.c_str());
continue;
}
const bool bHasSurface=!Base->vertices.empty()&&!Base->indices.empty();
if(bHasSurface&&SurfaceCandidates<3)
{
Rows.push_back({{Key,bPageRequested},std::move(Base)});
PageKeys.push_back(Key);
++SurfaceCandidates;
}
else if(!bHasSurface&&!bHaveFlatCandidate)
{
Rows.push_back({{Key,bPageRequested},std::move(Base)});
PageKeys.push_back(Key);
bHaveFlatCandidate=true;
}
if(SurfaceCandidates>=3&&bHaveFlatCandidate)break;
}
if(SurfaceCandidates>=3&&bHaveFlatCandidate)break;
}
}
}
if(Rows.empty())
{
std::printf("[RouteParityAudit] status=UNAVAILABLE reason=no_page_route_candidates\n");
Streamer.Stop();
return 9;
}
VoxelForgeCore::TileGenerationOptions PageOptions=CaptureOptions;
PageOptions.auditUniformBlockProofs=true;
int32 BasePageMismatches=0,PageRoutesVerified=0;
std::uint64_t PageProofBlocks=0,PageProofSamples=0,PageProofFallbacks=0,
PageProofUnknown=0,PageProofViolations=0;
std::uint64_t PageExactSamples=0,PageExactMismatches=0;
double MaxDensityDelta=0.0,SumDensityDelta=0.0;
std::uint64_t ComparedDensitySamples=0,SignMismatches=0,
CrossingEdgeMismatches=0,SharedCrossingEdges=0;
double MaxSurfaceDisplacement=0.0,SumSurfaceDisplacement=0.0;
for(const FRouteAuditRow& Row:Rows)
if(Row.Base)
{
const FRouteDensityComparison Query=CompareRouteDensities(
*Row.Base,*Row.Base,Shape);
PageExactSamples+=Query.exactQuerySamples;
PageExactMismatches+=Query.exactQueryMismatches;
}
else ++BasePageMismatches;
VoxelForgeCore::TileRegionCompileStats PageStats;
std::size_t CoveredPageKeys=0;
std::string PageCompileError;
const bool bPagesCompiled=Shape.compileTileRegion(PageKeys,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
PageCompileError,&CoveredPageKeys,&PageStats,true,true);
if(!bPagesCompiled)
{
std::printf("[RouteParityAudit] page_compile=FAIL error=%s\n",PageCompileError.c_str());
Streamer.Stop();
return 9;
}
for(FRouteAuditRow& Row:Rows)
{
std::string Error;
const auto Page=Shape.generateTile(Row.Candidate.Key,PageOptions,Error);
const bool bVerifiedPage=Page&&Page->diagnostics.analyticRegionPageRoute;
PageRoutesVerified+=bVerifiedPage?1:0;
const bool bSame=Row.Base&&bVerifiedPage&&SameTileOutput(*Row.Base,*Page);
const FRouteDensityComparison Comparison=Page&&Row.Base
?CompareRouteDensities(*Page,*Row.Base,Shape):FRouteDensityComparison{};
if(!bSame||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++BasePageMismatches;
PageExactSamples+=Comparison.exactQuerySamples;
PageExactMismatches+=Comparison.exactQueryMismatches;
MaxDensityDelta=std::max(MaxDensityDelta,Comparison.maxAbsoluteDelta);
SumDensityDelta+=Comparison.sumAbsoluteDelta;
ComparedDensitySamples+=Comparison.samples;
SignMismatches+=Comparison.signMismatches;
CrossingEdgeMismatches+=Comparison.crossingEdgeMismatches;
SharedCrossingEdges+=Comparison.sharedCrossingEdges;
MaxSurfaceDisplacement=std::max(MaxSurfaceDisplacement,
Comparison.maxSurfaceDisplacementVoxels);
SumSurfaceDisplacement+=Comparison.sumSurfaceDisplacementVoxels;
if(Page)
{
PageProofBlocks+=Page->diagnostics.uniformBlockProofsChecked;
PageProofSamples+=Page->diagnostics.uniformBlockProofSamplesChecked;
PageProofFallbacks+=Page->diagnostics.uniformBlockProofFallbackBlocks;
PageProofUnknown+=Page->diagnostics.uniformBlockProofUnknownBlocks;
PageProofViolations+=Page->diagnostics.uniformBlockProofViolations;
}
std::printf("[RouteParityPair] route=base/page key=(%d,%d,%d,lod%d) page_requested=%d page_verified=%d same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu max_abs_density_delta=%.9g sign_mismatches=%llu edge_crossing_mismatches=%llu shared_surface_edges=%llu max_surface_delta_vox=%.9g exact_query_mismatches=%llu base_native_float=%llu page_native_float=%llu first_density=(%.9g,%.9g) status=%s error=%s\n",
Row.Candidate.Key.coordinate.x,Row.Candidate.Key.coordinate.y,
Row.Candidate.Key.coordinate.z,Row.Candidate.Key.lod,
Row.Candidate.bWouldRequestPage?1:0,bVerifiedPage?1:0,
Row.Base&&Page&&Row.Base->densityHash==Page->densityHash?1:0,
Row.Base&&Page&&Row.Base->meshHash==Page->meshHash?1:0,
Row.Base&&Page&&Row.Base->payloadHash==Page->payloadHash?1:0,
Row.Base&&Page&&Row.Base->topologyHash==Page->topologyHash?1:0,
static_cast<unsigned long long>(Comparison.samples),
Comparison.maxAbsoluteDelta,
static_cast<unsigned long long>(Comparison.signMismatches),
static_cast<unsigned long long>(Comparison.crossingEdgeMismatches),
static_cast<unsigned long long>(Comparison.sharedCrossingEdges),
Comparison.maxSurfaceDisplacementVoxels,
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
static_cast<unsigned long long>(Row.Base?Row.Base->diagnostics.floatFieldCalls:0),
static_cast<unsigned long long>(Page?Page->diagnostics.floatFieldCalls:0),
Row.Base&&!Row.Base->debugDensitySamples.empty()
?Row.Base->debugDensitySamples.front():0.0f,
Page&&!Page->debugDensitySamples.empty()?Page->debugDensitySamples.front():0.0f,
bSame&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Page?Error.c_str():Error.c_str());
}
int32 NativeMismatches=0,NativeRoutesVerified=0;
std::uint64_t NativeExactSamples=0,NativeExactMismatches=0;
int32 NativePairs=0;
VoxelForgeCore::TileGenerationOptions NativeOptions=CaptureOptions;
NativeOptions.diagnosticForceNativeOnly=true;
for(const FVoxelTileKey& Tile:ShapeFreeTiles)
{
if(NativePairs>=9)break;
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string BaseError,NativeError;
const auto Base=Shape.generateTile(Key,CaptureOptions,BaseError);
const auto Native=Shape.generateTile(Key,NativeOptions,NativeError);
++NativePairs;
const bool bVerifiedNative=Native&&Native->diagnostics.nativeOnlyRoute;
NativeRoutesVerified+=bVerifiedNative?1:0;
const bool bSame=Base&&bVerifiedNative&&SameTileOutput(*Base,*Native);
const FRouteDensityComparison Comparison=Base&&Native
?CompareRouteDensities(*Native,*Base,Shape):FRouteDensityComparison{};
NativeExactSamples+=Comparison.exactQuerySamples;
NativeExactMismatches+=Comparison.exactQueryMismatches;
if(!bSame||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++NativeMismatches;
std::printf("[RouteParityPair] route=compiled/native-only key=(%d,%d,%d,lod%d) native_verified=%d same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
bVerifiedNative?1:0,Base&&Native&&Base->densityHash==Native->densityHash?1:0,
Base&&Native&&Base->meshHash==Native->meshHash?1:0,
Base&&Native&&Base->payloadHash==Native->payloadHash?1:0,
Base&&Native&&Base->topologyHash==Native->topologyHash?1:0,
static_cast<unsigned long long>(Comparison.samples),
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
bSame&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Native?NativeError.c_str():NativeError.c_str());
}
int32 ExactQueryPairs=0,ExactQueryMismatches=0;
std::uint64_t ExactQuerySamples=0;
for(int32 LOD=World.FullResClipLevels;LOD<=World.MaxClipLevel&&LOD<9;++LOD)
{
int32 Added=0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(Tile.Level!=LOD||Added>=2)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string Error;
const auto Mesh=Shape.generateTile(Key,CaptureOptions,Error);
const FRouteDensityComparison Comparison=Mesh
?CompareRouteDensities(*Mesh,*Mesh,Shape):FRouteDensityComparison{};
++ExactQueryPairs;++Added;
ExactQuerySamples+=Comparison.exactQuerySamples;
if(!Mesh||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++ExactQueryMismatches;
std::printf("[RouteParityPair] route=tile/exact-query key=(%d,%d,%d,lod%d) samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
static_cast<unsigned long long>(Comparison.exactQuerySamples),
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
Mesh&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Error.c_str());
}
}
int32 EditPairs=0,EditMismatches=0;
const auto EditRow=std::find_if(Rows.begin(),Rows.end(),[](const FRouteAuditRow& Row)
{
return Row.Base&&!Row.Candidate.bWouldRequestPage&&Row.Candidate.Key.lod<=1
&&!Row.Base->vertices.empty()&&!Row.Base->indices.empty();
});
if(EditRow!=Rows.end())
{
VoxelForgeCore::World EditWorld(CoreSnapshot);
std::string EditCompileError;
if(!EditWorld.compile(ShapeRequest,Scheduler,EditCompileError))
{
++EditMismatches;
std::printf("[RouteParityEdit] status=FAIL stage=compile error=%s\n",
EditCompileError.c_str());
}
else
{
const VoxelForgeCore::TileKey Key=EditRow->Candidate.Key;
const std::int32_t Extent=CHUNK_SIZE<<Key.lod;
const std::array<VoxelForgeCore::TileKey,1> EditKeys={Key};
VoxelForgeCore::TileGenerationOptions EditOptions=CaptureOptions;
EditOptions.auditUniformBlockProofs=true;
std::string BeforeError,ApplyError,BaseError,PageCompileError,PageError;
const auto Before=EditWorld.generateTile(Key,EditOptions,BeforeError);
VoxelForgeCore::EditTransaction Transaction;
Transaction.sequence=1;
VoxelForgeCore::EditBrush Brush;
Brush.shape=VoxelForgeCore::EditBrush::Shape::sphere;
Brush.operation=VoxelForgeCore::EditBrush::Operation::densityOffset;
bool bSurfaceCenterFound=false;
if(Before&&!Before->debugDensitySamples.empty())
{
const std::int32_t Dim=static_cast<std::int32_t>(std::llround(
std::cbrt(static_cast<double>(Before->debugDensitySamples.size()))));
const std::int32_t GridDim=Dim-3;
if(Dim>=4&&static_cast<std::size_t>(Dim)*Dim*Dim
==Before->debugDensitySamples.size()&&GridDim>0&&Extent%GridDim==0)
{
const std::int32_t Step=Extent/GridDim;
const std::int32_t OriginX=Key.coordinate.x*Extent;
const std::int32_t OriginY=Key.coordinate.y*Extent;
const std::int32_t OriginZ=Key.coordinate.z*Extent;
const auto Index=[Dim](std::int32_t X,std::int32_t Y,std::int32_t Z)
{return (static_cast<std::size_t>(Z)*Dim+Y)*Dim+X;};
for(std::int32_t Z=0;Z<Dim&&!bSurfaceCenterFound;++Z)
for(std::int32_t Y=0;Y<Dim&&!bSurfaceCenterFound;++Y)
for(std::int32_t X=0;X<Dim&&!bSurfaceCenterFound;++X)
{
for(const std::array<std::int32_t,3>& Delta:
{std::array<std::int32_t,3>{1,0,0},
std::array<std::int32_t,3>{0,1,0},
std::array<std::int32_t,3>{0,0,1}})
{
const std::int32_t NX=X+Delta[0],NY=Y+Delta[1],NZ=Z+Delta[2];
if(NX>=Dim||NY>=Dim||NZ>=Dim)continue;
const float D0=Before->debugDensitySamples[Index(X,Y,Z)];
const float D1=Before->debugDensitySamples[Index(NX,NY,NZ)];
if((D0<0.0f)==(D1<0.0f))continue;
const double T=static_cast<double>(D0)
/(static_cast<double>(D0)-D1);
Brush.a={OriginX+(X-1+T*Delta[0])*Step,
OriginY+(Y-1+T*Delta[1])*Step,
OriginZ+(Z-1+T*Delta[2])*Step};
bSurfaceCenterFound=true;
break;
}
}
}
}
if(!bSurfaceCenterFound)
Brush.a={static_cast<double>(Key.coordinate.x*Extent)+Extent*0.5,
static_cast<double>(Key.coordinate.y*Extent)+Extent*0.5,
static_cast<double>(Key.coordinate.z*Extent)+Extent*0.5};
Brush.radius=10.0;
Brush.strength=-48.0f;
Transaction.brushes.push_back(Brush);
const auto Applied=Before?EditWorld.applyEditTransaction(Transaction,
EditKeys,ApplyError):std::optional<VoxelForgeCore::EditResult>{};
const auto EditedBase=Applied
?EditWorld.generateTile(Key,EditOptions,BaseError)
:std::optional<VoxelForgeCore::TileMesh>{};
VoxelForgeCore::TileRegionCompileStats EditPageStats;
std::size_t EditPageKeys=0;
const bool bEditPageBuilt=EditedBase&&EditWorld.compileTileRegion(EditKeys,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
PageCompileError,&EditPageKeys,&EditPageStats,true,true);
const auto EditedPage=bEditPageBuilt
?EditWorld.generateTile(Key,EditOptions,PageError)
:std::optional<VoxelForgeCore::TileMesh>{};
const FRouteDensityComparison EditComparison=EditedBase&&EditedPage
?CompareRouteDensities(*EditedPage,*EditedBase,EditWorld)
:FRouteDensityComparison{};
const bool bEditChanged=Before&&EditedBase
&&Before->densityHash!=EditedBase->densityHash;
const bool bEditPageVerified=EditedPage
&&EditedPage->diagnostics.analyticRegionPageRoute;
const bool bEditSame=EditedBase&&EditedPage&&bEditPageVerified
&&SameTileOutput(*EditedBase,*EditedPage);
const bool bEditPass=Before&&Applied&&EditedBase&&bEditPageBuilt
&&bEditPageVerified&&bEditChanged&&bEditSame&&EditComparison.valid
&&EditComparison.exactQueryMismatches==0;
++EditPairs;
if(!bEditPass)++EditMismatches;
if(EditedPage)
{
PageProofBlocks+=EditedPage->diagnostics.uniformBlockProofsChecked;
PageProofSamples+=EditedPage->diagnostics.uniformBlockProofSamplesChecked;
PageProofFallbacks+=EditedPage->diagnostics.uniformBlockProofFallbackBlocks;
PageProofUnknown+=EditedPage->diagnostics.uniformBlockProofUnknownBlocks;
PageProofViolations+=EditedPage->diagnostics.uniformBlockProofViolations;
}
std::printf("[RouteParityEdit] key=(%d,%d,%d,lod%d) sequence=%llu before_hash=0x%016llx edited_base_hash=0x%016llx edited_page_hash=0x%016llx edit_changed=%d page_verified=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
static_cast<unsigned long long>(Transaction.sequence),
static_cast<unsigned long long>(Before?Before->densityHash:0),
static_cast<unsigned long long>(EditedBase?EditedBase->densityHash:0),
static_cast<unsigned long long>(EditedPage?EditedPage->densityHash:0),
bEditChanged?1:0,bEditPageVerified?1:0,
EditedBase&&EditedPage&&EditedBase->meshHash==EditedPage->meshHash?1:0,
EditedBase&&EditedPage&&EditedBase->payloadHash==EditedPage->payloadHash?1:0,
EditedBase&&EditedPage&&EditedBase->topologyHash==EditedPage->topologyHash?1:0,
static_cast<unsigned long long>(EditComparison.samples),
static_cast<unsigned long long>(EditComparison.exactQueryMismatches),
bEditPass?"PASS":"FAIL",
!Before?BeforeError.c_str():!Applied?ApplyError.c_str():
!EditedBase?BaseError.c_str():!bEditPageBuilt?PageCompileError.c_str():
PageError.c_str());
}
}
int32 HistoryPairs=0,HistoryMismatches=0;
if(bHasCameraStep&&bRegionCrossing)
{
const auto MovedAnchor=std::find_if(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[](const FVoxelTileKey& Tile){return Tile.Level==0;});
const auto HistoryRow=std::find_if(Rows.begin(),Rows.end(),
[&](const FRouteAuditRow& Row)
{
if(!Row.Base||Row.Candidate.bWouldRequestPage)return false;
return std::none_of(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[&](const FVoxelTileKey& Tile)
{
return Tile.Level==Row.Candidate.Key.lod
&&Tile.Coord.X==Row.Candidate.Key.coordinate.x
&&Tile.Coord.Y==Row.Candidate.Key.coordinate.y
&&Tile.Coord.Z==Row.Candidate.Key.coordinate.z;
});
});
if(HistoryRow!=Rows.end()&&MovedAnchor!=MovedDesired.Tiles.end())
{
VoxelForgeCore::ShapeBuildRequest MovedShapeRequest=ShapeRequest;
const FIntVector MovedOrigin=MovedAnchor->OriginVoxels();
const std::int32_t MovedExtent=MovedAnchor->ExtentVoxels();
MovedShapeRequest.minVoxel={MovedOrigin.X,MovedOrigin.Y,MovedOrigin.Z};
MovedShapeRequest.maxVoxel={MovedOrigin.X+MovedExtent,
MovedOrigin.Y+MovedExtent,MovedOrigin.Z+MovedExtent};
MovedShapeRequest.clipMinVoxel=MovedShapeRequest.minVoxel;
MovedShapeRequest.clipMaxVoxel=MovedShapeRequest.maxVoxel;
VoxelForgeCore::World MovedWorld(CoreSnapshot);
std::string MovedShapeError,MovedTileError;
const bool bMovedCompiled=MovedWorld.compile(MovedShapeRequest,Scheduler,
MovedShapeError);
const auto MovedTile=bMovedCompiled
?MovedWorld.generateTile(HistoryRow->Candidate.Key,CaptureOptions,MovedTileError)
:std::optional<VoxelForgeCore::TileMesh>{};
const FRouteDensityComparison HistoryComparison=MovedTile
?CompareRouteDensities(*MovedTile,*HistoryRow->Base,MovedWorld)
:FRouteDensityComparison{};
const bool bHistorySame=MovedTile
&&SameTileOutput(*MovedTile,*HistoryRow->Base)
&&HistoryComparison.valid&&HistoryComparison.exactQueryMismatches==0;
++HistoryPairs;
if(!bHistorySame)++HistoryMismatches;
std::printf("[RouteParityHistory] from=initial_base to=moved_world key=(%d,%d,%d,lod%d) same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu max_abs_density_delta=%.9g exact_query_mismatches=%llu status=%s error=%s\n",
HistoryRow->Candidate.Key.coordinate.x,HistoryRow->Candidate.Key.coordinate.y,
HistoryRow->Candidate.Key.coordinate.z,HistoryRow->Candidate.Key.lod,
MovedTile&&MovedTile->densityHash==HistoryRow->Base->densityHash?1:0,
MovedTile&&MovedTile->meshHash==HistoryRow->Base->meshHash?1:0,
MovedTile&&MovedTile->payloadHash==HistoryRow->Base->payloadHash?1:0,
MovedTile&&MovedTile->topologyHash==HistoryRow->Base->topologyHash?1:0,
static_cast<unsigned long long>(HistoryComparison.samples),
HistoryComparison.maxAbsoluteDelta,
static_cast<unsigned long long>(HistoryComparison.exactQueryMismatches),
bHistorySame?"PASS":"FAIL",
!bMovedCompiled?MovedShapeError.c_str():MovedTileError.c_str());
}
}
const double MeanDensityDelta=ComparedDensitySamples
?SumDensityDelta/static_cast<double>(ComparedDensitySamples):0.0;
const double MeanSurfaceDisplacement=SharedCrossingEdges
?SumSurfaceDisplacement/static_cast<double>(SharedCrossingEdges):0.0;
const bool bRouteParityPassing=BasePageMismatches==0&&NativeMismatches==0
&&ExactQueryMismatches==0&&EditPairs==1&&EditMismatches==0
&&HistoryPairs==(bHasCameraStep&&bRegionCrossing?1:0)&&HistoryMismatches==0
&&PageRoutesVerified==static_cast<int32>(Rows.size())
&&NativeRoutesVerified==NativePairs&&PageProofViolations==0
&&PageExactMismatches==0&&NativeExactMismatches==0;
std::printf("[RouteParityAudit] seed=%d page_pairs=%zu page_verified=%d page_mismatches=%d native_only_pairs=%d native_verified=%d native_mismatches=%d higher_lod_exact_pairs=%d higher_lod_exact_mismatches=%d edit_pairs=%d edit_mismatches=%d history_pairs=%d history_mismatches=%d exact_query_samples=%llu exact_query_mismatches=%llu page_density_samples=%llu max_abs_density_delta=%.9g mean_abs_density_delta=%.9g sign_mismatches=%llu edge_crossing_mismatches=%llu shared_surface_edges=%llu max_surface_delta_vox=%.9g mean_surface_delta_vox=%.9g page_proof_blocks=%llu page_proof_samples=%llu page_proof_fallbacks=%llu page_proof_unknown=%llu page_proof_violations=%llu status=%s\n",
World.Seed,Rows.size(),PageRoutesVerified,BasePageMismatches,
NativePairs,NativeRoutesVerified,NativeMismatches,ExactQueryPairs,
ExactQueryMismatches,EditPairs,EditMismatches,HistoryPairs,HistoryMismatches,
static_cast<unsigned long long>(PageExactSamples
+NativeExactSamples+ExactQuerySamples),
static_cast<unsigned long long>(PageExactMismatches
+NativeExactMismatches+ExactQueryMismatches),
static_cast<unsigned long long>(ComparedDensitySamples),MaxDensityDelta,
MeanDensityDelta,static_cast<unsigned long long>(SignMismatches),
static_cast<unsigned long long>(CrossingEdgeMismatches),
static_cast<unsigned long long>(SharedCrossingEdges),MaxSurfaceDisplacement,
MeanSurfaceDisplacement,static_cast<unsigned long long>(PageProofBlocks),
static_cast<unsigned long long>(PageProofSamples),
static_cast<unsigned long long>(PageProofFallbacks),
static_cast<unsigned long long>(PageProofUnknown),
static_cast<unsigned long long>(PageProofViolations),
bRouteParityPassing?"PASS":"FAIL");
if(!bRouteParityPassing)
{
Streamer.Stop();
return 9;
}
}
const FStandaloneStreamingUpdate Update=Streamer.UpdateDesiredWithSet(Desired,{},0);
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles after shape publication but queued %d.\n",
Desired.Tiles.size(),Update.DesiredTiles);return 7;
}
FSceneExportWriter SceneExport;
const bool bExportRequested=!MeshExportPath.empty();
bool bSceneExportPassing=true;
if(bExportRequested)
{
bSceneExportPassing=SceneExport.Open(MeshExportPath,World.CoreVoxelSizeMicrons,
CameraPositionVoxels,CameraYawDegrees,CameraPitchDegrees,
static_cast<std::uint32_t>(Update.DesiredTiles));
if(!bSceneExportPassing)
{
Streamer.Stop();
std::fprintf(stderr,"[MeshSceneExport] FAIL: could not open %s\n",
MeshExportPath.string().c_str());
return 8;
}
}
std::vector<FHashedTile> DensityRows,MeshRows,PayloadRows,TopologyRows;
int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0;
int32 FullDetailExpected=0;
uint64 WholeNonEmptyMeshTiles=0,WholeTriangleCount=0;
struct FColumnXY
{
std::int64_t X=0,Y=0;
bool operator==(const FColumnXY&)const=default;
};
struct FColumnXYHash
{
std::size_t operator()(const FColumnXY& Value)const noexcept
{
const std::size_t X=std::hash<std::int64_t>{}(Value.X);
const std::size_t Y=std::hash<std::int64_t>{}(Value.Y);
return X^(Y+static_cast<std::size_t>(0x9E3779B9u)+(X<<6)+(X>>2));
}
};
struct FColumnEvaluationEvent
{
FColumnXY XY;
FVoxelTileKey Tile;
std::uint64_t WorkerHash=0;
std::uint64_t Sequence=0;
bool bOutsideTileFootprint=false;
};
std::array<std::vector<FColumnEvaluationEvent>,9> ColumnEventsByLOD;
std::array<std::uint64_t,9> ColumnEvaluationEventsByLOD{},UniqueColumnCoordinatesByLOD{};
std::array<std::uint64_t,9> ColumnDuplicateEventsByLOD{},SameWorkerEvictedRepeatsByLOD{};
std::array<std::uint64_t,9> DifferentWorkerRepeatsByLOD{},HaloNormalRepeatsByLOD{};
std::array<std::uint64_t,9> HaloNormalEvaluationsByLOD{},NeighbourDuplicateEventsByLOD{};
std::array<std::uint64_t,9> CrossWorkerNeighbourDuplicateEventsByLOD{};
std::array<std::uint64_t,9> ColumnCaptureTilesByLOD{},ExpectedTilesByLOD{};
std::array<bool,9> ColumnCaptureCompleteByLOD{};
ColumnCaptureCompleteByLOD.fill(true);
std::array<double,9> WorkerSecondsByLOD{};
std::array<double,9> BaseRouteWorkerSecondsByLOD{},PageRouteWorkerSecondsByLOD{};
std::array<double,9> ColumnEvalMsByLOD{},MarchingExclusiveMsByLOD{};
std::array<double,9> GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{};
std::array<double,9> MeshAssemblyMsByLOD{};
std::array<double,9> SkirtMsByLOD{};
struct FFarLODProfile
{
std::array<std::uint64_t,9> ColumnCalls{},ColumnHits{},ColumnMisses{};
std::array<std::uint64_t,9> ColumnConflictMisses{},SharedColumnHits{},ColumnEvaluations{};
std::array<double,9> McColumnMs{},GroundColumnMs{},CapColumnMs{};
std::array<double,9> McGridMs{},McCellClassMs{},McGradientMs{};
std::array<double,9> McInterpolationMs{},McDedupMs{},McOtherMs{};
std::array<double,9> StratumShellMs{},ConnectorShellMs{};
std::array<std::uint64_t,9> StratumFieldCalls{},ConnectorFieldCalls{},FarShellTriangles{};
std::array<std::uint64_t,9> StratumColumnPointCalls{},StratumColumnHits{};
std::array<std::uint64_t,9> StratumColumnMisses{},StratumSharedColumnHits{},StratumColumnEvaluations{};
std::array<std::uint64_t,9> ConnectorColumnPointCalls{},ConnectorColumnHits{};
std::array<std::uint64_t,9> ConnectorColumnMisses{},ConnectorSharedColumnHits{},ConnectorColumnEvaluations{};
std::array<double,9> StratumColumnComputeMs{},ConnectorColumnComputeMs{};
};
std::unique_ptr<FFarLODProfile> FarLODProfile;
if(bReportLodWorkProfile)FarLODProfile=std::make_unique<FFarLODProfile>();
std::array<std::uint64_t,9> DensitySamplesByLOD{};
std::array<std::uint64_t,9> SkirtTrianglesByLOD{};
std::array<std::uint64_t,9> TileCountByLOD{};
std::array<std::uint64_t,9> BaseRouteTilesByLOD{},PageRouteTilesByLOD{};
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level>=0&&Tile.Level<static_cast<int32>(ExpectedTilesByLOD.size()))
++ExpectedTilesByLOD[static_cast<std::size_t>(Tile.Level)];
const auto AreSameLODNeighbours=[](const FVoxelTileKey& A,const FVoxelTileKey& B)
{
if(A.Level!=B.Level)return false;
const std::int64_t DX=std::abs(static_cast<std::int64_t>(A.Coord.X)-B.Coord.X);
const std::int64_t DY=std::abs(static_cast<std::int64_t>(A.Coord.Y)-B.Coord.Y);
const std::int64_t DZ=std::abs(static_cast<std::int64_t>(A.Coord.Z)-B.Coord.Z);
return std::max({DX,DY,DZ})<=1&&(DX+DY+DZ)>0;
};
uint64 NativeSolidBoxes=0,NativeAirBoxes=0,NativeMixedBoxes=0,NativeUnknownBoxes=0;
uint64 NativeFieldCalls=0,NativeColumnHits=0,NativeColumnMisses=0,NativeMeshingSkips=0;
double NativeClassificationMilliseconds=0.0,NativeColumnComputeMilliseconds=0.0;
double NativeMeshingMilliseconds=0.0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level<World.FullResClipLevels)++FullDetailExpected;
std::array<std::optional<FStandaloneCpuTile>,9> GateSampleTiles{};
std::array<double,9> GateSampleDistances{};
GateSampleDistances.fill(std::numeric_limits<double>::infinity());
Clock::time_point FirstTileReady{},NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
bool bFirstTileReported=false,bNeighborhoodReported=false,bFullDetailReported=false;
uint64 BlockProofBlocksChecked=0,BlockProofSamplesChecked=0;
uint64 BlockProofFallbackBlocks=0,BlockProofUnknownBlocks=0,BlockProofViolations=0;
while(Finished<Update.DesiredTiles)
{
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
for(const FStandaloneCpuTile& Tile:Ready)
{
if(Tile.bGenerationFailed)
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] a tile failed generation; refusing a partial result.\n");
return 9;
}
if(bExportRequested)SceneExport.Add(Tile);
++Finished;
if(bReportMeshCoverage)
{
const uint64 TileTriangleCount=static_cast<uint64>(Tile.Indices.size()/3);
WholeTriangleCount+=TileTriangleCount;
if(TileTriangleCount>0)++WholeNonEmptyMeshTiles;
}
if(Tile.Key.Level>=0&&Tile.Key.Level<static_cast<int32>(TileCountByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++TileCountByLOD[LOD];
WorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
if(bReportLodWorkProfile)
{
if(Tile.CoreDiagnostics.analyticRegionPageRoute)
{
++PageRouteTilesByLOD[LOD];
PageRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
}
else
{
++BaseRouteTilesByLOD[LOD];
BaseRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
}
}
ColumnEvalMsByLOD[LOD]+=Tile.CoreDiagnostics.columnEvaluationExclusiveMilliseconds;
MarchingExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesExclusiveMilliseconds;
GroundRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.groundRefinementExclusiveMilliseconds;
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
SkirtMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesSkirtMilliseconds;
SkirtTrianglesByLOD[LOD]+=Tile.SkirtTriangleCount;
if(bReportLodWorkProfile)
{
DensitySamplesByLOD[LOD]+=Tile.DensitySamples;
const auto& D=Tile.CoreDiagnostics;
FarLODProfile->ColumnCalls[LOD]+=D.fieldCalls;
FarLODProfile->ColumnHits[LOD]+=D.columnCacheHits;
FarLODProfile->ColumnMisses[LOD]+=D.columnCacheMisses;
FarLODProfile->ColumnConflictMisses[LOD]+=D.columnCacheConflictMisses;
FarLODProfile->SharedColumnHits[LOD]+=D.sharedColumnCacheHits;
FarLODProfile->ColumnEvaluations[LOD]+=D.columnEvaluations;
FarLODProfile->McColumnMs[LOD]+=D.marchingCubesColumnComputeMilliseconds;
FarLODProfile->GroundColumnMs[LOD]+=D.groundRefinementColumnComputeMilliseconds;
FarLODProfile->CapColumnMs[LOD]+=D.capRefinementColumnComputeMilliseconds;
FarLODProfile->McGridMs[LOD]+=D.marchingCubesDensityGridMilliseconds;
FarLODProfile->McCellClassMs[LOD]+=D.marchingCubesCellClassificationMilliseconds;
FarLODProfile->McGradientMs[LOD]+=D.marchingCubesGradientNormalsMilliseconds;
FarLODProfile->McInterpolationMs[LOD]+=D.marchingCubesEdgeInterpolationMilliseconds;
FarLODProfile->McDedupMs[LOD]+=D.marchingCubesVertexDedupStreamMilliseconds;
FarLODProfile->McOtherMs[LOD]+=D.marchingCubesOtherMilliseconds;
FarLODProfile->StratumShellMs[LOD]+=D.farStratumShellMilliseconds;
FarLODProfile->ConnectorShellMs[LOD]+=D.farConnectorShellMilliseconds;
FarLODProfile->StratumFieldCalls[LOD]+=D.farStratumFieldCalls;
FarLODProfile->ConnectorFieldCalls[LOD]+=D.farConnectorFieldCalls;
FarLODProfile->FarShellTriangles[LOD]+=D.farShellTrianglesAdded;
FarLODProfile->StratumColumnPointCalls[LOD]+=D.farStratumColumnPointCalls;
FarLODProfile->StratumColumnHits[LOD]+=D.farStratumColumnCacheHits;
FarLODProfile->StratumColumnMisses[LOD]+=D.farStratumColumnCacheMisses;
FarLODProfile->StratumSharedColumnHits[LOD]+=D.farStratumSharedColumnCacheHits;
FarLODProfile->StratumColumnEvaluations[LOD]+=D.farStratumColumnEvaluations;
FarLODProfile->ConnectorColumnPointCalls[LOD]+=D.farConnectorColumnPointCalls;
FarLODProfile->ConnectorColumnHits[LOD]+=D.farConnectorColumnCacheHits;
FarLODProfile->ConnectorColumnMisses[LOD]+=D.farConnectorColumnCacheMisses;
FarLODProfile->ConnectorSharedColumnHits[LOD]+=D.farConnectorSharedColumnCacheHits;
FarLODProfile->ConnectorColumnEvaluations[LOD]+=D.farConnectorColumnEvaluations;
FarLODProfile->StratumColumnComputeMs[LOD]+=D.farStratumColumnComputeMilliseconds;
FarLODProfile->ConnectorColumnComputeMs[LOD]+=D.farConnectorColumnComputeMilliseconds;
}
if(bAuditUniformBlockProofs)
{
BlockProofBlocksChecked+=Tile.CoreDiagnostics.uniformBlockProofsChecked;
BlockProofSamplesChecked+=Tile.CoreDiagnostics.uniformBlockProofSamplesChecked;
BlockProofFallbackBlocks+=Tile.CoreDiagnostics.uniformBlockProofFallbackBlocks;
BlockProofUnknownBlocks+=Tile.CoreDiagnostics.uniformBlockProofUnknownBlocks;
BlockProofViolations+=Tile.CoreDiagnostics.uniformBlockProofViolations;
}
if(bScreenSpaceGate&&Assembly&&Tile.Key.Level>=3&&Tile.Key.Level<9
&&!Tile.Vertices.empty()
&&StandaloneScreenSpaceGate::TileHasNativeSurface(Tile.Key,*Assembly,
static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0))
{
const double Distance=StandaloneScreenSpaceGate::TileAabbDistanceMeters(
Tile.Key,CameraPositionVoxels,
static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0);
const bool bCloser=Distance<GateSampleDistances[LOD]-1e-9;
const bool bTied=std::abs(Distance-GateSampleDistances[LOD])<=1e-9;
const bool bKeyLess=!GateSampleTiles[LOD]
||TileKeyLessForHash(Tile.Key,GateSampleTiles[LOD]->Key);
if(bCloser||(bTied&&bKeyLess))
{GateSampleDistances[LOD]=Distance;GateSampleTiles[LOD]=Tile;}
}
}
if(bProfileColumnOverlap&&Tile.Key.Level>=0
&&Tile.Key.Level<static_cast<int32>(ColumnCaptureTilesByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++ColumnCaptureTilesByLOD[LOD];
ColumnCaptureCompleteByLOD[LOD]=ColumnCaptureCompleteByLOD[LOD]
&&Tile.CoreDiagnostics.columnCoordinateCaptureComplete;
auto& Events=ColumnEventsByLOD[LOD];
for(const auto& Coordinate:Tile.CoreDiagnostics.evaluatedColumnCoordinates)
{
Events.push_back({{Coordinate.x,Coordinate.y},Tile.Key,
Tile.CoreDiagnostics.columnEvaluationWorkerHash,Coordinate.sequence,
Coordinate.outsideTileFootprint});
}
}
WholeViewReady=std::max(WholeViewReady,Tile.CompletedAt);
if(FirstTileReady.time_since_epoch().count()==0||Tile.CompletedAt<FirstTileReady)
FirstTileReady=Tile.CompletedAt;
if(Neighborhood.contains(Tile.Key))
{
++NeighborhoodFinished;
NeighborhoodReady=std::max(NeighborhoodReady,Tile.CompletedAt);
}
if(Tile.Key.Level<World.FullResClipLevels)
{
++FullDetailFinished;
FullDetailReady=std::max(FullDetailReady,Tile.CompletedAt);
NativeSolidBoxes+=Tile.CoreDiagnostics.solidBoxes;
NativeAirBoxes+=Tile.CoreDiagnostics.airBoxes;
NativeMixedBoxes+=Tile.CoreDiagnostics.mixedBoxes;
NativeUnknownBoxes+=Tile.CoreDiagnostics.unknownBoxes;
NativeFieldCalls+=Tile.CoreDiagnostics.fieldCalls;
NativeColumnHits+=Tile.CoreDiagnostics.columnCacheHits;
NativeColumnMisses+=Tile.CoreDiagnostics.columnCacheMisses;
NativeMeshingSkips+=Tile.CoreDiagnostics.meshingSkipped?1u:0u;
NativeClassificationMilliseconds+=Tile.CoreDiagnostics.classificationMilliseconds;
NativeColumnComputeMilliseconds+=Tile.CoreDiagnostics.columnComputeMilliseconds;
NativeMeshingMilliseconds+=Tile.CoreDiagnostics.meshingMilliseconds;
}
if(bHashDensity)
{
if(Tile.bHasDensityHash)DensityRows.push_back({Tile.Key,Tile.DensityHash});
if(Tile.bHasMeshHash)MeshRows.push_back({Tile.Key,Tile.MeshHash});
if(Tile.bHasPayloadHash)PayloadRows.push_back({Tile.Key,Tile.PayloadHash});
if(Tile.bHasTopologyHash)TopologyRows.push_back({Tile.Key,Tile.TopologyHash});
}
}
if(!bFirstTileReported&&FirstTileReady.time_since_epoch().count()!=0)
{
std::printf("[PipelineMilestone] first_tile_ready=%.3fs\n",
std::chrono::duration<double>(FirstTileReady-ColdStart).count());
bFirstTileReported=true;
}
if(!bNeighborhoodReported&&NeighborhoodFinished==static_cast<int32>(Neighborhood.size()))
{
std::printf("[PipelineMilestone] neighborhood_ready=%.3fs generated=%d/27\n",
std::chrono::duration<double>(NeighborhoodReady-ColdStart).count(),NeighborhoodFinished);
bNeighborhoodReported=true;
}
if(!bFullDetailReported&&FullDetailFinished==FullDetailExpected)
{
std::printf("[PipelineMilestone] full_detail_ready=%.3fs generated=%d/%d\n",
std::chrono::duration<double>(FullDetailReady-ColdStart).count(),
FullDetailFinished,FullDetailExpected);
bFullDetailReported=true;
}
}
if(bHasCameraStep)
{
const auto MovingStart=Clock::now();
double RegionCompileWallSeconds=0.0;
double RegionCompileCpuSeconds=0.0;
std::size_t RegionCompileRequested=0,RegionCompileCovered=0;
VoxelForgeCore::TileRegionCompileStats RegionCompileStats;
if(bRegionCrossing)
{
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> InitialKeys;
InitialKeys.reserve(Desired.Tiles.size()*2+1);
for(const FVoxelTileKey& Key:Desired.Tiles)InitialKeys.insert(Key);
std::vector<VoxelForgeCore::TileKey> EnteringCoreTiles;
EnteringCoreTiles.reserve(MovedDesired.Tiles.size());
for(const FVoxelTileKey& Key:MovedDesired.Tiles)
{
if(InitialKeys.contains(Key))continue;
EnteringCoreTiles.push_back({{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level});
}
RegionCompileRequested=EnteringCoreTiles.size();
const auto RegionCompileStart=Clock::now();
const std::clock_t RegionCompileCpuStart=std::clock();
std::string RegionCompileError;
if(!Shape.compileTileRegion(EnteringCoreTiles,
static_cast<uint32>(std::clamp(WorkerCount,1,16)),Scheduler,
RegionCompileError,&RegionCompileCovered,&RegionCompileStats,true))
{
Streamer.Stop();
std::fprintf(stderr,"[MovingRegionCompile] failed: %s\n",RegionCompileError.c_str());
return 2;
}
RegionCompileWallSeconds=std::chrono::duration<double>(
Clock::now()-RegionCompileStart).count();
RegionCompileCpuSeconds=static_cast<double>(std::clock()-RegionCompileCpuStart)
/CLOCKS_PER_SEC;
const std::size_t ParallelWorkers=RegionCompileStats.regionsBuilt>1
?std::min<std::size_t>(8,RegionCompileStats.regionsBuilt):0;
std::printf("[MovingRegionCompile] distance_m=%.3f entering_tiles=%zu covered_tiles=%zu regions=%zu lattice_nodes=%llu wall_s=%.6f cpu_s=%.6f worker_threads=%zu mode=analytic-shape-pages\n",
std::sqrt(static_cast<double>(CameraStepVoxels.X)*CameraStepVoxels.X
+static_cast<double>(CameraStepVoxels.Y)*CameraStepVoxels.Y
+static_cast<double>(CameraStepVoxels.Z)*CameraStepVoxels.Z)
*static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0,
RegionCompileRequested,RegionCompileCovered,RegionCompileStats.regionsBuilt,
static_cast<unsigned long long>(RegionCompileStats.latticeNodes),
RegionCompileWallSeconds,RegionCompileCpuSeconds,ParallelWorkers);
}
const auto MovingTileStart=Clock::now();
const auto MovingUpdate=Streamer.UpdateDesiredWithSet(MovedDesired,Desired.Tiles,1);
std::array<std::uint64_t,9> MovingTilesByLOD{};
std::array<double,9> MovingWorkerSecondsByLOD{};
std::array<std::uint64_t,9> MovingSamplesByLOD{},MovingNativeFloatCallsByLOD{},
MovingNativeLatticeCallsByLOD{},MovingNativeOnlyTilesByLOD{},
MovingAnalyticPageTilesByLOD{},MovingNativeSurfaceTilesByLOD{};
std::array<std::uint64_t,9> MovingBaseRouteTilesByLOD{};
std::array<double,9> MovingBaseRouteWorkerSecondsByLOD{},
MovingPageRouteWorkerSecondsByLOD{};
std::array<double,9> MovingColumnComputeMsByLOD{},MovingClassificationMsByLOD{},
MovingMcExclusiveMsByLOD{},MovingMcDensityGridMsByLOD{},
MovingMcCellClassMsByLOD{},MovingMcGradientMsByLOD{},
MovingMcInterpolationMsByLOD{},MovingMcDedupMsByLOD{},MovingMcOtherMsByLOD{};
std::vector<FHashedTile> MovingDensityRows,MovingMeshRows,
MovingPayloadRows,MovingTopologyRows;
int32 MovingFinished=0;
while(MovingFinished<MovingUpdate.NewJobs)
{
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
if(Ready.empty())
{std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
for(const FStandaloneCpuTile& Tile:Ready)
{
++MovingFinished;
if(Tile.Key.Level>=0&&Tile.Key.Level<static_cast<int32>(MovingTilesByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++MovingTilesByLOD[LOD];
MovingWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
if(bReportLodWorkProfile)
{
const auto& D=Tile.CoreDiagnostics;
MovingSamplesByLOD[LOD]+=Tile.DensitySamples;
MovingNativeFloatCallsByLOD[LOD]+=D.floatFieldCalls;
MovingNativeLatticeCallsByLOD[LOD]+=D.latticeFieldCalls;
MovingNativeOnlyTilesByLOD[LOD]+=D.nativeOnlyRoute?1u:0u;
MovingAnalyticPageTilesByLOD[LOD]+=D.analyticRegionPageRoute?1u:0u;
MovingNativeSurfaceTilesByLOD[LOD]+=D.nativeSurfaceTile?1u:0u;
if(D.analyticRegionPageRoute)
MovingPageRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
else
{
++MovingBaseRouteTilesByLOD[LOD];
MovingBaseRouteWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
}
MovingColumnComputeMsByLOD[LOD]+=D.columnEvaluationExclusiveMilliseconds;
MovingClassificationMsByLOD[LOD]+=D.classificationExclusiveMilliseconds;
MovingMcExclusiveMsByLOD[LOD]+=D.marchingCubesExclusiveMilliseconds;
MovingMcDensityGridMsByLOD[LOD]+=D.marchingCubesDensityGridMilliseconds;
MovingMcCellClassMsByLOD[LOD]+=D.marchingCubesCellClassificationMilliseconds;
MovingMcGradientMsByLOD[LOD]+=D.marchingCubesGradientNormalsMilliseconds;
MovingMcInterpolationMsByLOD[LOD]+=D.marchingCubesEdgeInterpolationMilliseconds;
MovingMcDedupMsByLOD[LOD]+=D.marchingCubesVertexDedupStreamMilliseconds;
MovingMcOtherMsByLOD[LOD]+=D.marchingCubesOtherMilliseconds;
}
}
if(bHashDensity)
{
if(Tile.bHasDensityHash)MovingDensityRows.push_back({Tile.Key,Tile.DensityHash});
if(Tile.bHasMeshHash)MovingMeshRows.push_back({Tile.Key,Tile.MeshHash});
if(Tile.bHasPayloadHash)MovingPayloadRows.push_back({Tile.Key,Tile.PayloadHash});
if(Tile.bHasTopologyHash)MovingTopologyRows.push_back({Tile.Key,Tile.TopologyHash});
}
}
}
const double MovingTileWallSeconds=std::chrono::duration<double>(
Clock::now()-MovingTileStart).count();
const double MovingWallSeconds=std::chrono::duration<double>(Clock::now()-MovingStart).count();
const double StepDistanceMeters=std::sqrt(
static_cast<double>(CameraStepVoxels.X)*CameraStepVoxels.X
+static_cast<double>(CameraStepVoxels.Y)*CameraStepVoxels.Y
+static_cast<double>(CameraStepVoxels.Z)*CameraStepVoxels.Z)
*static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
std::printf("[MovingCameraStep] step_voxels=(%.3f,%.3f,%.3f) distance_m=%.3f desired_tiles=%zu new_tiles=%d completed=%d wall_s=%.6f shared_column_cache=%s\n",
CameraStepVoxels.X,CameraStepVoxels.Y,CameraStepVoxels.Z,StepDistanceMeters,
MovedDesired.Tiles.size(),MovingUpdate.NewJobs,MovingFinished,MovingWallSeconds,
bUseSharedColumnCache?"on":"off");
std::printf("[MovingTileWork] tiles=%d wall_s=%.6f worker_sum_s=%.6f region_compile_wall_s=%.6f crossing_total_s=%.6f\n",
MovingFinished,MovingTileWallSeconds,
std::accumulate(MovingWorkerSecondsByLOD.begin(),MovingWorkerSecondsByLOD.end(),0.0),
RegionCompileWallSeconds,MovingWallSeconds);
if(bHashDensity)
std::printf("[MovingTileHash] tiles=%d rows=(%zu,%zu,%zu,%zu) density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx status=%s\n",
MovingFinished,MovingDensityRows.size(),MovingMeshRows.size(),
MovingPayloadRows.size(),MovingTopologyRows.size(),
static_cast<unsigned long long>(HashTileRows(MovingDensityRows)),
static_cast<unsigned long long>(HashTileRows(MovingMeshRows)),
static_cast<unsigned long long>(HashTileRows(MovingPayloadRows)),
static_cast<unsigned long long>(HashTileRows(MovingTopologyRows)),
MovingDensityRows.size()==static_cast<std::size_t>(MovingFinished)
&&MovingMeshRows.size()==static_cast<std::size_t>(MovingFinished)
&&MovingPayloadRows.size()==static_cast<std::size_t>(MovingFinished)
&&MovingTopologyRows.size()==static_cast<std::size_t>(MovingFinished)
?"PASS":"FAIL");
for(std::size_t LOD=0;LOD<MovingTilesByLOD.size();++LOD)
if(MovingTilesByLOD[LOD]!=0)
{
std::printf("[MovingCameraStepLOD] lod=%zu tiles=%llu worker_sum_s=%.6f\n",
LOD,static_cast<unsigned long long>(MovingTilesByLOD[LOD]),
MovingWorkerSecondsByLOD[LOD]);
if(bReportLodWorkProfile)
std::printf("[MovingCameraStepLODProfile] lod=%zu density_samples=%llu samples_per_tile=%.1f native_float_calls=%llu native_lattice_calls=%llu native_surface_tiles=%llu native_only_tiles=%llu analytic_page_tiles=%llu base_route_tiles=%llu base_route_avg_ms=%.3f page_route_avg_ms=%.3f column_compute_ms=%.3f classification_ms=%.3f mc_exclusive_ms=%.3f mc_density_grid_ms=%.3f mc_cell_class_ms=%.3f mc_gradient_ms=%.3f mc_interpolation_ms=%.3f mc_dedup_ms=%.3f mc_other_ms=%.3f\n",
LOD,static_cast<unsigned long long>(MovingSamplesByLOD[LOD]),
static_cast<double>(MovingSamplesByLOD[LOD])/MovingTilesByLOD[LOD],
static_cast<unsigned long long>(MovingNativeFloatCallsByLOD[LOD]),
static_cast<unsigned long long>(MovingNativeLatticeCallsByLOD[LOD]),
static_cast<unsigned long long>(MovingNativeSurfaceTilesByLOD[LOD]),
static_cast<unsigned long long>(MovingNativeOnlyTilesByLOD[LOD]),
static_cast<unsigned long long>(MovingAnalyticPageTilesByLOD[LOD]),
static_cast<unsigned long long>(MovingBaseRouteTilesByLOD[LOD]),
MovingBaseRouteTilesByLOD[LOD]
?MovingBaseRouteWorkerSecondsByLOD[LOD]*1000.0
/MovingBaseRouteTilesByLOD[LOD]:0.0,
MovingAnalyticPageTilesByLOD[LOD]
?MovingPageRouteWorkerSecondsByLOD[LOD]*1000.0
/MovingAnalyticPageTilesByLOD[LOD]:0.0,
MovingColumnComputeMsByLOD[LOD],MovingClassificationMsByLOD[LOD],
MovingMcExclusiveMsByLOD[LOD],MovingMcDensityGridMsByLOD[LOD],
MovingMcCellClassMsByLOD[LOD],MovingMcGradientMsByLOD[LOD],
MovingMcInterpolationMsByLOD[LOD],MovingMcDedupMsByLOD[LOD],
MovingMcOtherMsByLOD[LOD]);
}
}
Streamer.Stop();
bool bScreenSpaceGatePassing=true;
if(bScreenSpaceGate)
{
if(Assembly)
bScreenSpaceGatePassing=StandaloneScreenSpaceGate::Run(GateSampleTiles,
Streamer,*Assembly,ClosestDisplayDistances,World.CoreVoxelSizeMicrons,
World.MaxClipLevel,PixelBudgetsSubvoxels,CameraYawDegrees,
CameraPitchDegrees);
else
{std::fprintf(stderr,"[ScreenSpaceGateResult] no-world-assembly status=REJECT\n");bScreenSpaceGatePassing=false;}
}
if(bExportRequested)
{
bSceneExportPassing=SceneExport.Close(static_cast<std::uint32_t>(Update.DesiredTiles));
std::error_code FileSizeError;
const std::uintmax_t ExportBytes=std::filesystem::file_size(MeshExportPath,FileSizeError);
std::printf("[MeshSceneExport] tiles=%u expected=%d bytes=%llu status=%s path=%s\n",
SceneExport.TileCount,Update.DesiredTiles,
static_cast<unsigned long long>(FileSizeError?0:ExportBytes),
bSceneExportPassing?"PASS":"FAIL",MeshExportPath.string().c_str());
bSceneExportPassing=bSceneExportPassing&&!FileSizeError;
}
if(bProfileColumnOverlap)
{
struct FColumnPriorUse
{
FVoxelTileKey Tile;
std::uint64_t WorkerHash=0;
};
for(std::size_t LOD=0;LOD<ColumnEventsByLOD.size();++LOD)
{
auto& Events=ColumnEventsByLOD[LOD];
std::sort(Events.begin(),Events.end(),[](const FColumnEvaluationEvent& A,
const FColumnEvaluationEvent& B){return A.Sequence<B.Sequence;});
std::unordered_map<FColumnXY,std::vector<FColumnPriorUse>,FColumnXYHash> UsesByXY;
UsesByXY.reserve(Events.size());
for(const FColumnEvaluationEvent& Event:Events)
{
++ColumnEvaluationEventsByLOD[LOD];
if(Event.bOutsideTileFootprint)++HaloNormalEvaluationsByLOD[LOD];
auto [Found,Inserted]=UsesByXY.try_emplace(Event.XY);
auto& PriorUses=Found->second;
if(Inserted)
{
++UniqueColumnCoordinatesByLOD[LOD];
PriorUses.push_back({Event.Tile,Event.WorkerHash});
continue;
}
++ColumnDuplicateEventsByLOD[LOD];
if(Event.bOutsideTileFootprint)
++HaloNormalRepeatsByLOD[LOD];
else
{
const bool bSameWorkerSeen=std::any_of(PriorUses.begin(),PriorUses.end(),
[&](const FColumnPriorUse& Prior)
{return Prior.WorkerHash==Event.WorkerHash;});
if(bSameWorkerSeen)++SameWorkerEvictedRepeatsByLOD[LOD];
else ++DifferentWorkerRepeatsByLOD[LOD];
}
bool bHasNeighbourDuplicate=false,bHasCrossWorkerNeighbourDuplicate=false;
for(const FColumnPriorUse& Prior:PriorUses)
{
if(!AreSameLODNeighbours(Prior.Tile,Event.Tile))continue;
bHasNeighbourDuplicate=true;
bHasCrossWorkerNeighbourDuplicate=bHasCrossWorkerNeighbourDuplicate
||Prior.WorkerHash!=Event.WorkerHash;
}
if(bHasNeighbourDuplicate)++NeighbourDuplicateEventsByLOD[LOD];
if(bHasCrossWorkerNeighbourDuplicate)
++CrossWorkerNeighbourDuplicateEventsByLOD[LOD];
PriorUses.push_back({Event.Tile,Event.WorkerHash});
}
}
}
bool bColumnOverlapCapturePassing=true;
if(bProfileColumnOverlap)
{
for(std::size_t LOD=0;LOD<ColumnCaptureTilesByLOD.size();++LOD)
{
const bool bLODComplete=ColumnCaptureCompleteByLOD[LOD]
&&ColumnCaptureTilesByLOD[LOD]==ExpectedTilesByLOD[LOD];
bColumnOverlapCapturePassing=bColumnOverlapCapturePassing&&bLODComplete;
std::printf("[WorldAssemblerLODColumnOverlap] lod=%zu tiles=%llu expected_tiles=%llu total_column_evaluations=%llu unique_xy_columns=%llu repeated_column_evaluations=%llu same_worker_evicted_repeats=%llu different_worker_repeats=%llu halo_normal_repeats=%llu halo_normal_evaluations=%llu neighbouring_duplicate_evaluations=%llu cross_worker_neighbouring_duplicates=%llu capture_complete=%d\n",
LOD,static_cast<unsigned long long>(ColumnCaptureTilesByLOD[LOD]),
static_cast<unsigned long long>(ExpectedTilesByLOD[LOD]),
static_cast<unsigned long long>(ColumnEvaluationEventsByLOD[LOD]),
static_cast<unsigned long long>(UniqueColumnCoordinatesByLOD[LOD]),
static_cast<unsigned long long>(ColumnDuplicateEventsByLOD[LOD]),
static_cast<unsigned long long>(SameWorkerEvictedRepeatsByLOD[LOD]),
static_cast<unsigned long long>(DifferentWorkerRepeatsByLOD[LOD]),
static_cast<unsigned long long>(HaloNormalRepeatsByLOD[LOD]),
static_cast<unsigned long long>(HaloNormalEvaluationsByLOD[LOD]),
static_cast<unsigned long long>(NeighbourDuplicateEventsByLOD[LOD]),
static_cast<unsigned long long>(CrossWorkerNeighbourDuplicateEventsByLOD[LOD]),
bLODComplete?1:0);
}
}
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
{
std::printf("[WorldAssemblerLODWorker] lod=%zu tiles=%llu worker_sum_s=%.6f column_eval_exclusive_ms=%.3f mc_exclusive_ms=%.3f ground_refine_exclusive_ms=%.3f cap_refine_exclusive_ms=%.3f skirt_ms=%.3f skirt_triangles=%llu mesh_assembly_ms=%.3f\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),WorkerSecondsByLOD[LOD],
ColumnEvalMsByLOD[LOD],MarchingExclusiveMsByLOD[LOD],
GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD],
SkirtMsByLOD[LOD],static_cast<unsigned long long>(SkirtTrianglesByLOD[LOD]),
MeshAssemblyMsByLOD[LOD]);
if(bReportLodWorkProfile)
{
const auto& Detail=*FarLODProfile;
const double SamplesPerTile=TileCountByLOD[LOD]
?static_cast<double>(DensitySamplesByLOD[LOD])/TileCountByLOD[LOD]:0.0;
std::printf("[WorldAssemblerLODSamples] lod=%zu samples=%llu samples_per_tile=%.1f\n",
LOD,static_cast<unsigned long long>(DensitySamplesByLOD[LOD]),SamplesPerTile);
std::printf("[WorldAssemblerLODRouteProfile] lod=%zu base_shape_tiles=%llu base_shape_avg_ms=%.3f analytic_page_tiles=%llu analytic_page_avg_ms=%.3f\n",
LOD,static_cast<unsigned long long>(BaseRouteTilesByLOD[LOD]),
BaseRouteTilesByLOD[LOD]
?BaseRouteWorkerSecondsByLOD[LOD]*1000.0/BaseRouteTilesByLOD[LOD]:0.0,
static_cast<unsigned long long>(PageRouteTilesByLOD[LOD]),
PageRouteTilesByLOD[LOD]
?PageRouteWorkerSecondsByLOD[LOD]*1000.0/PageRouteTilesByLOD[LOD]:0.0);
const double TileDivisor=TileCountByLOD[LOD]
?static_cast<double>(TileCountByLOD[LOD]):1.0;
std::printf("[WorldAssemblerLODCostDetail] lod=%zu tiles=%llu density_samples=%llu column_point_calls=%llu column_local_hits=%llu column_local_misses=%llu column_conflict_misses=%llu column_shared_hits=%llu column_formula_evaluations=%llu column_compute_ms=%.3f mc_column_ms=%.3f mc_exclusive_ms=%.3f mc_grid_ms=%.3f mc_cell_class_ms=%.3f mc_gradient_ms=%.3f mc_interpolation_ms=%.3f mc_dedup_stream_ms=%.3f mc_other_ms=%.3f ground_column_ms=%.3f ground_exclusive_ms=%.3f cap_column_ms=%.3f cap_exclusive_ms=%.3f stratum_shell_ms=%.3f stratum_field_calls=%llu stratum_column_calls=%llu stratum_column_hits=%llu stratum_column_misses=%llu stratum_shared_hits=%llu stratum_column_evaluations=%llu stratum_column_compute_ms=%.3f connector_shell_ms=%.3f connector_field_calls=%llu connector_column_calls=%llu connector_column_hits=%llu connector_column_misses=%llu connector_shared_hits=%llu connector_column_evaluations=%llu connector_column_compute_ms=%.3f far_shell_triangles=%llu skirt_ms=%.3f mesh_assembly_ms=%.3f worker_ms_per_tile=%.3f column_formula_evals_per_tile=%.1f connector_calls_per_tile=%.1f\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),
static_cast<unsigned long long>(DensitySamplesByLOD[LOD]),
static_cast<unsigned long long>(Detail.ColumnCalls[LOD]),
static_cast<unsigned long long>(Detail.ColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ColumnMisses[LOD]),
static_cast<unsigned long long>(Detail.ColumnConflictMisses[LOD]),
static_cast<unsigned long long>(Detail.SharedColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ColumnEvaluations[LOD]),
ColumnEvalMsByLOD[LOD],Detail.McColumnMs[LOD],MarchingExclusiveMsByLOD[LOD],
Detail.McGridMs[LOD],Detail.McCellClassMs[LOD],Detail.McGradientMs[LOD],
Detail.McInterpolationMs[LOD],Detail.McDedupMs[LOD],Detail.McOtherMs[LOD],
Detail.GroundColumnMs[LOD],GroundRefineExclusiveMsByLOD[LOD],
Detail.CapColumnMs[LOD],CapRefineExclusiveMsByLOD[LOD],
Detail.StratumShellMs[LOD],
static_cast<unsigned long long>(Detail.StratumFieldCalls[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnPointCalls[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnHits[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnMisses[LOD]),
static_cast<unsigned long long>(Detail.StratumSharedColumnHits[LOD]),
static_cast<unsigned long long>(Detail.StratumColumnEvaluations[LOD]),
Detail.StratumColumnComputeMs[LOD],
Detail.ConnectorShellMs[LOD],
static_cast<unsigned long long>(Detail.ConnectorFieldCalls[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnPointCalls[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnMisses[LOD]),
static_cast<unsigned long long>(Detail.ConnectorSharedColumnHits[LOD]),
static_cast<unsigned long long>(Detail.ConnectorColumnEvaluations[LOD]),
Detail.ConnectorColumnComputeMs[LOD],
static_cast<unsigned long long>(Detail.FarShellTriangles[LOD]),
SkirtMsByLOD[LOD],MeshAssemblyMsByLOD[LOD],
WorkerSecondsByLOD[LOD]*1000.0/TileDivisor,
static_cast<double>(Detail.ColumnEvaluations[LOD])/TileDivisor,
static_cast<double>(Detail.ConnectorFieldCalls[LOD])/TileDivisor);
}
}
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
const double NeighborhoodMeshSeconds=std::max(0.0,
std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count());
const double FullDetailSeconds=std::chrono::duration<double>(FullDetailReady-ColdStart).count();
const double WholeViewSeconds=std::chrono::duration<double>(WholeViewReady-ColdStart).count();
const double StreamSeconds=std::chrono::duration<double>(WholeViewReady-StreamStart).count();
const double FirstTileSeconds=std::chrono::duration<double>(FirstTileReady-ColdStart).count();
std::printf("[StreamPipeline] workers=%d shape=%.3fs first_tile_ready=%.3fs neighborhood_mesh=%.3fs neighborhood_ready=%.3fs full_detail_ready=%.3fs whole_view_ready=%.3fs neighborhood_tiles=%d/27 full_detail_tiles=%d/%d whole_tiles=%d/%zu stream_wall=%.3fs cache_hits=0 full_payload=1\n",
WorkerCount,ShapeSeconds,FirstTileSeconds,NeighborhoodMeshSeconds,NeighborhoodSeconds,
FullDetailSeconds,WholeViewSeconds,NeighborhoodFinished,
FullDetailFinished,FullDetailExpected,Finished,Desired.Tiles.size(),StreamSeconds);
if(bReportMeshCoverage)
std::printf("[PipelineMeshCoverage] tiles=%d nonempty_mesh_tiles=%llu indexed_triangles=%llu\n",
Finished,static_cast<unsigned long long>(WholeNonEmptyMeshTiles),
static_cast<unsigned long long>(WholeTriangleCount));
std::printf("[WorldAssemblerTilePipeline] full_detail_tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n",
FullDetailExpected,static_cast<unsigned long long>(NativeSolidBoxes),
static_cast<unsigned long long>(NativeAirBoxes),
static_cast<unsigned long long>(NativeMixedBoxes),
static_cast<unsigned long long>(NativeUnknownBoxes),
static_cast<unsigned long long>(NativeMeshingSkips),
static_cast<unsigned long long>(NativeFieldCalls),
static_cast<unsigned long long>(NativeColumnHits),
static_cast<unsigned long long>(NativeColumnMisses),
NativeColumnComputeMilliseconds,NativeClassificationMilliseconds,
NativeMeshingMilliseconds);
if(bAuditUniformBlockProofs)
std::printf("[UniformBlockProofAudit] checked_blocks=%llu checked_samples=%llu fallback_blocks=%llu unknown_blocks=%llu violations=%llu\n",
static_cast<unsigned long long>(BlockProofBlocksChecked),
static_cast<unsigned long long>(BlockProofSamplesChecked),
static_cast<unsigned long long>(BlockProofFallbackBlocks),
static_cast<unsigned long long>(BlockProofUnknownBlocks),
static_cast<unsigned long long>(BlockProofViolations));
bool bHashesPassing=true;
if(bHashDensity)
{
bHashesPassing=DensityRows.size()==Desired.Tiles.size()
&&MeshRows.size()==Desired.Tiles.size()
&&PayloadRows.size()==Desired.Tiles.size()
&&TopologyRows.size()==Desired.Tiles.size();
if(bPrintTileHashes)
{
const auto makeHashIndex=[](const std::vector<FHashedTile>& rows)
{
std::unordered_map<FVoxelTileKey,uint64,FStandaloneTileKeyHash> index;
index.reserve(rows.size());
for(const FHashedTile& row:rows)index.emplace(row.Key,row.Hash);
return index;
};
const auto MeshIndex=makeHashIndex(MeshRows);
const auto PayloadIndex=makeHashIndex(PayloadRows);
const auto TopologyIndex=makeHashIndex(TopologyRows);
const auto findHash=[](const auto& index,const FVoxelTileKey& key)
{
const auto found=index.find(key);
return found==index.end()?uint64{0}:found->second;
};
for(const FHashedTile& row:DensityRows)
std::printf("[PipelineTileHash] lod=%d x=%d y=%d z=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
row.Key.Level,row.Key.Coord.X,row.Key.Coord.Y,row.Key.Coord.Z,
static_cast<unsigned long long>(row.Hash),
static_cast<unsigned long long>(findHash(MeshIndex,row.Key)),
static_cast<unsigned long long>(findHash(PayloadIndex,row.Key)),
static_cast<unsigned long long>(findHash(TopologyIndex,row.Key)));
}
std::vector<FHashedTile> FullDensity,FullMesh,FullPayload,FullTopology;
for(const FHashedTile& Row:DensityRows)if(Row.Key.Level<World.FullResClipLevels)FullDensity.push_back(Row);
for(const FHashedTile& Row:MeshRows)if(Row.Key.Level<World.FullResClipLevels)FullMesh.push_back(Row);
for(const FHashedTile& Row:PayloadRows)if(Row.Key.Level<World.FullResClipLevels)FullPayload.push_back(Row);
for(const FHashedTile& Row:TopologyRows)if(Row.Key.Level<World.FullResClipLevels)FullTopology.push_back(Row);
std::printf("[PipelineFullDetailHash] tiles=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
FullDetailExpected,static_cast<unsigned long long>(HashTileRows(FullDensity)),
static_cast<unsigned long long>(HashTileRows(FullMesh)),
static_cast<unsigned long long>(HashTileRows(FullPayload)),
static_cast<unsigned long long>(HashTileRows(FullTopology)));
std::printf("[PipelineWholeViewHash] tiles=%zu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
Desired.Tiles.size(),static_cast<unsigned long long>(HashTileRows(DensityRows)),
static_cast<unsigned long long>(HashTileRows(MeshRows)),
static_cast<unsigned long long>(HashTileRows(PayloadRows)),
static_cast<unsigned long long>(HashTileRows(TopologyRows)));
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
{
const auto FilterLOD=[LOD](const std::vector<FHashedTile>& Rows)
{
std::vector<FHashedTile> Selected;
for(const FHashedTile& Row:Rows)
if(Row.Key.Level==static_cast<int32>(LOD))Selected.push_back(Row);
return Selected;
};
auto LodDensity=FilterLOD(DensityRows),LodMesh=FilterLOD(MeshRows);
auto LodPayload=FilterLOD(PayloadRows),LodTopology=FilterLOD(TopologyRows);
std::printf("[PipelineLODHash] lod=%zu tiles=%llu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),
static_cast<unsigned long long>(HashTileRows(LodDensity)),
static_cast<unsigned long long>(HashTileRows(LodMesh)),
static_cast<unsigned long long>(HashTileRows(LodPayload)),
static_cast<unsigned long long>(HashTileRows(LodTopology)));
}
const std::array<VoxelForgeCore::Vec3d,9> QueryPoints={{
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X+8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X-8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y+8.0,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y-8.0,CameraPositionVoxels.Z},
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z+8.0},
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z-8.0},
{CameraPositionVoxels.X+64.0,CameraPositionVoxels.Y-32.0,CameraPositionVoxels.Z+16.0},
{CameraPositionVoxels.X-128.0,CameraPositionVoxels.Y+96.0,CameraPositionVoxels.Z-64.0}}};
uint64 ExactDensityHash=14695981039346656037ull;
uint64 ExactUnclampedHash=14695981039346656037ull;
uint64 ExactDetailHash=14695981039346656037ull;
uint64 ExactCollisionHash=14695981039346656037ull;
for(const auto& Point:QueryPoints)
{
const float Density=Shape.densityAt(Point);
const float Unclamped=Shape.unclampedDensityAt(Point);
const auto Detail=Shape.detailSampleAt(Point);
HashWord(ExactDensityHash,std::bit_cast<uint32>(Density),4);
HashWord(ExactUnclampedHash,std::bit_cast<uint32>(Unclamped),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.displacement),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.caveInfluence),4);
HashWord(ExactDetailHash,std::bit_cast<uint32>(Detail.floorInfluence),4);
HashWord(ExactCollisionHash,Shape.isSolidAt(Point)?1u:0u,1);
}
std::printf("[PipelineExactQueryHash] probes=%zu density=0x%016llx unclamped=0x%016llx detail=0x%016llx collision=0x%016llx path=direct-Core-queries\n",
QueryPoints.size(),static_cast<unsigned long long>(ExactDensityHash),
static_cast<unsigned long long>(ExactUnclampedHash),
static_cast<unsigned long long>(ExactDetailHash),
static_cast<unsigned long long>(ExactCollisionHash));
}
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)
&&(!bExportRequested||bSceneExportPassing)&&bScreenSpaceGatePassing
&&(!bAuditUniformBlockProofs||BlockProofViolations==0)?0:6;
}
} // namespace StandaloneStreamBenchmark