Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
044cd6d9c5 |
No files matched your search
@@ -494,7 +494,10 @@ namespace VoxelForgeCore
|
|||||||
// Version 223 projects the floor onto one continuous arc-length profile and groups
|
// Version 223 projects the floor onto one continuous arc-length profile and groups
|
||||||
// dense passage samples into coarse tile candidates. Version 224 keeps the same
|
// dense passage samples into coarse tile candidates. Version 224 keeps the same
|
||||||
// continuous floor while relaxing the spline chord tolerance and bounding shell work.
|
// continuous floor while relaxing the spline chord tolerance and bounding shell work.
|
||||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 225;
|
// Version 226 unifies the passage influence reach in metres and converts it to core
|
||||||
|
// voxels for every broadphase and proof bound. Version 227 uses the exact smooth-max
|
||||||
|
// support width/6 when deriving that reach.
|
||||||
|
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 227;
|
||||||
|
|
||||||
enum class FieldChannel : std::uint32_t
|
enum class FieldChannel : std::uint32_t
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,11 +72,28 @@ static bool VF_IsL98PassagePrepareTraceEnabled()
|
|||||||
return bEnabled;
|
return bEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double VF_L93PassageCarveReachMetres()
|
static bool VF_IsL130PassageReachProofAuditEnabled()
|
||||||
{
|
{
|
||||||
// The generated world uses a fixed bounded tube influence. An explicit diagnostic
|
static const bool bEnabled=VF_IsL88DiagnosticSwitchEnabled(
|
||||||
// option can still select the legacy point-evaluation path for comparisons.
|
"VOXELFORGE_L130_PASSAGE_REACH_PROOF_AUDIT");
|
||||||
return 4.0;
|
return bEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr double VF_PassageShellThicknessMetres=0.75;
|
||||||
|
static constexpr double VF_PassageWallReliefMetres=0.21;
|
||||||
|
static constexpr double VF_PassageCornerBlendMetres=0.50;
|
||||||
|
static constexpr double VF_PassageReachMarginMetres=0.01;
|
||||||
|
// Radial support in metres: shell + maximum relief + the smooth-max support
|
||||||
|
// (corner-blend width / 6) + a 1 cm guard for float and bound rounding.
|
||||||
|
static constexpr double VF_PassageInfluenceReachMetres=
|
||||||
|
VF_PassageShellThicknessMetres+VF_PassageWallReliefMetres
|
||||||
|
+VF_PassageCornerBlendMetres/6.0+VF_PassageReachMarginMetres;
|
||||||
|
|
||||||
|
static double VF_PassageInfluenceReachCoreVoxels(
|
||||||
|
std::uint32_t coreVoxelSizeMicrometres)
|
||||||
|
{
|
||||||
|
return VF_PassageInfluenceReachMetres*1000000.0
|
||||||
|
/std::max<std::uint32_t>(1,coreVoxelSizeMicrometres);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class EPassageDensityQueryCaller : std::size_t
|
enum class EPassageDensityQueryCaller : std::size_t
|
||||||
@@ -306,7 +323,7 @@ public:
|
|||||||
profileStats_(profileStats),profileLod_(profileLod),
|
profileStats_(profileStats),profileLod_(profileLod),
|
||||||
passageCarveReachMetres_(std::isfinite(passageCarveReachMetres)
|
passageCarveReachMetres_(std::isfinite(passageCarveReachMetres)
|
||||||
&&passageCarveReachMetres>=0.0?passageCarveReachMetres
|
&&passageCarveReachMetres>=0.0?passageCarveReachMetres
|
||||||
:VF_L93PassageCarveReachMetres())
|
:VF_PassageInfluenceReachMetres)
|
||||||
{
|
{
|
||||||
mayContainResolvedBoundaryBand_=shape.ResolvedBoundaryBandsIntersectSubvoxelRange(
|
mayContainResolvedBoundaryBand_=shape.ResolvedBoundaryBandsIntersectSubvoxelRange(
|
||||||
minimumSubvoxels_[2],maximumSubvoxels_[2]);
|
minimumSubvoxels_[2],maximumSubvoxels_[2]);
|
||||||
@@ -1204,8 +1221,8 @@ public:
|
|||||||
if(!ResolvedLayout||ResolvedLayout->passages.empty()||!std::isfinite(X)
|
if(!ResolvedLayout||ResolvedLayout->passages.empty()||!std::isfinite(X)
|
||||||
||!std::isfinite(Y)||!std::isfinite(Z))return density;
|
||!std::isfinite(Y)||!std::isfinite(Z))return density;
|
||||||
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||||
constexpr double FloorShellThicknessMetres=0.75;
|
constexpr double FloorShellThicknessMetres=VF_PassageShellThicknessMetres;
|
||||||
constexpr double WallReliefMetres=0.21;
|
constexpr double WallReliefMetres=VF_PassageWallReliefMetres;
|
||||||
constexpr double OpenAirSideWallHeightMetres=1.0;
|
constexpr double OpenAirSideWallHeightMetres=1.0;
|
||||||
constexpr double MouthShellBlendMetres=5.0;
|
constexpr double MouthShellBlendMetres=5.0;
|
||||||
const double qPerMetre=Q*1000000.0/
|
const double qPerMetre=Q*1000000.0/
|
||||||
@@ -1630,8 +1647,8 @@ public:
|
|||||||
{
|
{
|
||||||
constexpr double Q=static_cast<double>(
|
constexpr double Q=static_cast<double>(
|
||||||
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||||
const double qPerMetre=Q*1000000.0/
|
const double reachCoreVoxels=VF_PassageInfluenceReachCoreVoxels(
|
||||||
std::max<std::uint32_t>(1,ResolvedLayout->coreVoxelSizeMicrometres);
|
ResolvedLayout->coreVoxelSizeMicrometres);
|
||||||
const auto overlaps=[&](const double low[3],const double high[3])
|
const auto overlaps=[&](const double low[3],const double high[3])
|
||||||
{
|
{
|
||||||
for(int axis=0;axis<3;++axis)
|
for(int axis=0;axis<3;++axis)
|
||||||
@@ -1648,7 +1665,8 @@ public:
|
|||||||
const auto& p3=passage.controlPoints[
|
const auto& p3=passage.controlPoints[
|
||||||
std::min(segment+2,passage.controlPoints.size()-1)];
|
std::min(segment+2,passage.controlPoints.size()-1)];
|
||||||
const double radius=std::max(static_cast<double>(a.radiusSubvoxels),
|
const double radius=std::max(static_cast<double>(a.radiusSubvoxels),
|
||||||
static_cast<double>(b.radiusSubvoxels))/Q+1.0;
|
static_cast<double>(b.radiusSubvoxels))/Q
|
||||||
|
+reachCoreVoxels+0.01;
|
||||||
double low[3]{},high[3]{};
|
double low[3]{},high[3]{};
|
||||||
for(int axis=0;axis<3;++axis)
|
for(int axis=0;axis<3;++axis)
|
||||||
{
|
{
|
||||||
@@ -3499,7 +3517,7 @@ private:
|
|||||||
double centerZSubvoxels,double queryZSubvoxels,double floorDepthSubvoxels,
|
double centerZSubvoxels,double queryZSubvoxels,double floorDepthSubvoxels,
|
||||||
double qPerMetre)
|
double qPerMetre)
|
||||||
{
|
{
|
||||||
constexpr double CornerBlendMetres=0.50;
|
constexpr double CornerBlendMetres=VF_PassageCornerBlendMetres;
|
||||||
const float floorDistance=static_cast<float>(centerZSubvoxels
|
const float floorDistance=static_cast<float>(centerZSubvoxels
|
||||||
-floorDepthSubvoxels-queryZSubvoxels);
|
-floorDepthSubvoxels-queryZSubvoxels);
|
||||||
return SmoothMaxDistance(roundDistanceSubvoxels,floorDistance,
|
return SmoothMaxDistance(roundDistanceSubvoxels,floorDistance,
|
||||||
@@ -4811,13 +4829,9 @@ private:
|
|||||||
PassageNearestNodes.resize(ResolvedLayout?ResolvedLayout->passages.size():0);
|
PassageNearestNodes.resize(ResolvedLayout?ResolvedLayout->passages.size():0);
|
||||||
if(!ResolvedLayout||ResolvedLayout->passages.empty())return;
|
if(!ResolvedLayout||ResolvedLayout->passages.empty())return;
|
||||||
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||||
constexpr double PassageShellMetres=0.75;
|
|
||||||
constexpr double ReliefMetres=0.21;
|
|
||||||
constexpr double SweepReachMetres=4.0;
|
|
||||||
constexpr double CornerBlendMetres=0.50;
|
|
||||||
constexpr std::size_t CandidateFineSamplesPerSpan=5;
|
constexpr std::size_t CandidateFineSamplesPerSpan=5;
|
||||||
const double requiredReach=std::max(SweepReachMetres+ReliefMetres
|
const double requiredReachCoreVoxels=VF_PassageInfluenceReachCoreVoxels(
|
||||||
+CornerBlendMetres*0.25,PassageShellMetres+ReliefMetres);
|
ResolvedLayout->coreVoxelSizeMicrometres);
|
||||||
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
|
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
|
||||||
++passageIndex)
|
++passageIndex)
|
||||||
{
|
{
|
||||||
@@ -4854,7 +4868,7 @@ private:
|
|||||||
routeMinimum[axis]=std::min(routeMinimum[axis],localMinimum[axis]);
|
routeMinimum[axis]=std::min(routeMinimum[axis],localMinimum[axis]);
|
||||||
routeMaximum[axis]=std::max(routeMaximum[axis],localMaximum[axis]);
|
routeMaximum[axis]=std::max(routeMaximum[axis],localMaximum[axis]);
|
||||||
}
|
}
|
||||||
const double localExtent=requiredReach
|
const double localExtent=requiredReachCoreVoxels
|
||||||
+std::max(prepared.radiusA,prepared.radiusB)/Q+0.01;
|
+std::max(prepared.radiusA,prepared.radiusB)/Q+0.01;
|
||||||
FPassageProofBound proof;
|
FPassageProofBound proof;
|
||||||
for(std::size_t axis=0;axis<3;++axis)
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
@@ -4872,7 +4886,8 @@ private:
|
|||||||
std::ceil((localMaximum[axis]+localExtent)*Q));
|
std::ceil((localMaximum[axis]+localExtent)*Q));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const double routeExtent=maximumRadiusSubvoxels/Q+requiredReach+0.01;
|
const double routeExtent=maximumRadiusSubvoxels/Q
|
||||||
|
+requiredReachCoreVoxels+0.01;
|
||||||
const double tileExtent=routeExtent;
|
const double tileExtent=routeExtent;
|
||||||
std::array<std::int64_t,3> featureMinimum{},featureMaximum{};
|
std::array<std::int64_t,3> featureMinimum{},featureMaximum{};
|
||||||
for(std::size_t axis=0;axis<3;++axis)
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
@@ -4899,6 +4914,113 @@ private:
|
|||||||
BuildPassageFeatureNode(0,PassageFeatureOrder.size());
|
BuildPassageFeatureNode(0,PassageFeatureOrder.size());
|
||||||
if(!PassageProofBounds.empty())
|
if(!PassageProofBounds.empty())
|
||||||
BuildPassageProofNode(0,PassageProofBounds.size());
|
BuildPassageProofNode(0,PassageProofBounds.size());
|
||||||
|
|
||||||
|
if(VF_IsL130PassageReachProofAuditEnabled())
|
||||||
|
{
|
||||||
|
constexpr double Q=static_cast<double>(
|
||||||
|
VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||||
|
constexpr std::array<std::array<double,2>,8> RadialDirections={{
|
||||||
|
{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}}};
|
||||||
|
constexpr std::array<double,2> CrestHeightsMetres={0.625,0.875};
|
||||||
|
const double qPerMetre=Q*1000000.0/
|
||||||
|
std::max<std::uint32_t>(1,ResolvedLayout->coreVoxelSizeMicrometres);
|
||||||
|
const std::array<double,6> shellOffsetsMetres={0.70,0.78,0.86,0.94,
|
||||||
|
VF_PassageInfluenceReachMetres-0.005,
|
||||||
|
VF_PassageInfluenceReachMetres+0.005};
|
||||||
|
std::uint64_t sampled=0,signRelevant=0,proofMisses=0,featureMisses=0;
|
||||||
|
for(std::size_t passageIndex=0;
|
||||||
|
passageIndex<PassageSegmentData.size();++passageIndex)
|
||||||
|
{
|
||||||
|
const auto& segments=PassageSegmentData[passageIndex];
|
||||||
|
if(segments.empty())continue;
|
||||||
|
const auto& constants=PassageComposerConstants[passageIndex];
|
||||||
|
const std::size_t stride=std::max<std::size_t>(1,
|
||||||
|
(segments.size()+127)/128);
|
||||||
|
for(std::size_t segmentIndex=0;segmentIndex<segments.size();
|
||||||
|
segmentIndex+=stride)
|
||||||
|
{
|
||||||
|
const auto& segment=segments[segmentIndex];
|
||||||
|
if(segment.lengthSq<=1.0e-12)continue;
|
||||||
|
constexpr double T=0.5;
|
||||||
|
const double centerX=segment.a[0]+T*segment.delta[0];
|
||||||
|
const double centerY=segment.a[1]+T*segment.delta[1];
|
||||||
|
const double centerZ=segment.a[2]+T*segment.delta[2];
|
||||||
|
const double radius=segment.radiusA+T*segment.radiusDelta;
|
||||||
|
const double floorDepth=PassageFlatFloorDepthSubvoxels(
|
||||||
|
constants,segmentIndex,T,radius,qPerMetre);
|
||||||
|
const double floorCenterZ=PassageFlatFloorCenterZSubvoxels(
|
||||||
|
constants,segments,segmentIndex,T,segment,centerX,centerY,
|
||||||
|
floorDepth,qPerMetre);
|
||||||
|
for(const double crestHeightMetres:CrestHeightsMetres)
|
||||||
|
{
|
||||||
|
const double sampleZ=floorCenterZ-floorDepth
|
||||||
|
+crestHeightMetres*qPerMetre;
|
||||||
|
const double verticalDelta=sampleZ-centerZ;
|
||||||
|
for(const double shellOffsetMetres:shellOffsetsMetres)
|
||||||
|
{
|
||||||
|
const double radialDistance=radius
|
||||||
|
+shellOffsetMetres*qPerMetre;
|
||||||
|
if(radialDistance*radialDistance
|
||||||
|
<=verticalDelta*verticalDelta)continue;
|
||||||
|
const double horizontalDistance=std::sqrt(
|
||||||
|
radialDistance*radialDistance
|
||||||
|
-verticalDelta*verticalDelta);
|
||||||
|
for(const auto& direction:RadialDirections)
|
||||||
|
{
|
||||||
|
const double sampleQ[3]={
|
||||||
|
centerX+direction[0]*horizontalDistance,
|
||||||
|
centerY+direction[1]*horizontalDistance,sampleZ};
|
||||||
|
const double sampleVoxel[3]={sampleQ[0]/Q,
|
||||||
|
sampleQ[1]/Q,sampleQ[2]/Q};
|
||||||
|
const float contribution=ApplyResolvedStratePassageCarves(
|
||||||
|
0.0f,static_cast<float>(sampleVoxel[0]),
|
||||||
|
static_cast<float>(sampleVoxel[1]),
|
||||||
|
static_cast<float>(sampleVoxel[2]));
|
||||||
|
++sampled;
|
||||||
|
if(std::abs(contribution)<=1.0e-6f)continue;
|
||||||
|
++signRelevant;
|
||||||
|
if(PassageProofNodes.empty()
|
||||||
|
||!PassageProofBoundsOverlapNode(0,sampleVoxel,
|
||||||
|
sampleVoxel))
|
||||||
|
++proofMisses;
|
||||||
|
std::array<std::int64_t,3> sampleMinimum{},sampleMaximum{};
|
||||||
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
|
{
|
||||||
|
sampleMinimum[axis]=static_cast<std::int64_t>(
|
||||||
|
std::floor(sampleQ[axis]));
|
||||||
|
sampleMaximum[axis]=static_cast<std::int64_t>(
|
||||||
|
std::ceil(sampleQ[axis]));
|
||||||
|
}
|
||||||
|
const auto candidates=BuildPassageFeatureTileList(
|
||||||
|
sampleMinimum,sampleMaximum);
|
||||||
|
const bool featureContainsSample=std::any_of(
|
||||||
|
candidates.begin(),candidates.end(),
|
||||||
|
[&](std::uint32_t featureIndex)
|
||||||
|
{
|
||||||
|
return featureIndex<PassageTileFeatures.size()
|
||||||
|
&&PassageTileFeatures[featureIndex].passageIndex
|
||||||
|
==passageIndex;
|
||||||
|
});
|
||||||
|
if(!featureContainsSample)++featureMisses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bool auditPassed=sampled>0&&signRelevant>0
|
||||||
|
&&proofMisses==0&&featureMisses==0;
|
||||||
|
std::printf("[L130PassageReachProofAudit] reach_m=%.3f sampled=%llu sign_relevant=%llu proof_misses=%llu feature_misses=%llu status=%s\n",
|
||||||
|
VF_PassageInfluenceReachMetres,
|
||||||
|
static_cast<unsigned long long>(sampled),
|
||||||
|
static_cast<unsigned long long>(signRelevant),
|
||||||
|
static_cast<unsigned long long>(proofMisses),
|
||||||
|
static_cast<unsigned long long>(featureMisses),
|
||||||
|
auditPassed?"PASS":"FAIL");
|
||||||
|
if(!auditPassed)std::abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PassageProofBoundsOverlapNode(int nodeIndex,const double minimum[3],
|
bool PassageProofBoundsOverlapNode(int nodeIndex,const double minimum[3],
|
||||||
@@ -11442,10 +11564,9 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
|||||||
const FIntVector& origin,std::int32_t step,std::int32_t cells,std::uint32_t seed)
|
const FIntVector& origin,std::int32_t step,std::int32_t cells,std::uint32_t seed)
|
||||||
{
|
{
|
||||||
constexpr std::int64_t Q=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
constexpr std::int64_t Q=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
||||||
constexpr double InfluenceMetres=4.0;
|
|
||||||
constexpr double OpenAirSideWallHeightMetres=1.0;
|
constexpr double OpenAirSideWallHeightMetres=1.0;
|
||||||
if(!shape_||step<=0||cells<=0||!std::isfinite(passageCarveReachMetres_)
|
if(!shape_||step<=0||cells<=0||!std::isfinite(passageCarveReachMetres_)
|
||||||
||std::abs(passageCarveReachMetres_-InfluenceMetres)>1.0e-9)return;
|
||std::abs(passageCarveReachMetres_-VF_PassageInfluenceReachMetres)>1.0e-9)return;
|
||||||
const bool profile=profileStats_!=nullptr;
|
const bool profile=profileStats_!=nullptr;
|
||||||
const auto prepareStart=profile?std::chrono::steady_clock::now()
|
const auto prepareStart=profile?std::chrono::steady_clock::now()
|
||||||
:std::chrono::steady_clock::time_point{};
|
:std::chrono::steady_clock::time_point{};
|
||||||
@@ -11459,7 +11580,7 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
|||||||
sweep->dimension=cells+3;
|
sweep->dimension=cells+3;
|
||||||
const std::size_t gridSampleCount=static_cast<std::size_t>(sweep->dimension)
|
const std::size_t gridSampleCount=static_cast<std::size_t>(sweep->dimension)
|
||||||
*static_cast<std::size_t>(sweep->dimension)*static_cast<std::size_t>(sweep->dimension);
|
*static_cast<std::size_t>(sweep->dimension)*static_cast<std::size_t>(sweep->dimension);
|
||||||
sweep->influenceSubvoxels=InfluenceMetres*static_cast<double>(Q)*1000000.0
|
sweep->influenceSubvoxels=passageCarveReachMetres_*static_cast<double>(Q)*1000000.0
|
||||||
/std::max<std::uint32_t>(1,shape_->ResolvedLayout
|
/std::max<std::uint32_t>(1,shape_->ResolvedLayout
|
||||||
?shape_->ResolvedLayout->coreVoxelSizeMicrometres:250000);
|
?shape_->ResolvedLayout->coreVoxelSizeMicrometres:250000);
|
||||||
sweep->passageToSweep.assign(passageRouteSegments_.size(),-1);
|
sweep->passageToSweep.assign(passageRouteSegments_.size(),-1);
|
||||||
@@ -11473,7 +11594,7 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
|||||||
const double qPerMetre=static_cast<double>(Q)*1000000.0/
|
const double qPerMetre=static_cast<double>(Q)*1000000.0/
|
||||||
std::max<std::uint32_t>(1,shape_->ResolvedLayout
|
std::max<std::uint32_t>(1,shape_->ResolvedLayout
|
||||||
?shape_->ResolvedLayout->coreVoxelSizeMicrometres:250000);
|
?shape_->ResolvedLayout->coreVoxelSizeMicrometres:250000);
|
||||||
const double shellThickness=0.75*qPerMetre;
|
const double shellThickness=VF_PassageShellThicknessMetres*qPerMetre;
|
||||||
const double stampedOutsideDistance=sweep->influenceSubvoxels+1.0;
|
const double stampedOutsideDistance=sweep->influenceSubvoxels+1.0;
|
||||||
constexpr double MouthShellBlendMetres=5.0;
|
constexpr double MouthShellBlendMetres=5.0;
|
||||||
const double wallReliefShell=0.41*qPerMetre;
|
const double wallReliefShell=0.41*qPerMetre;
|
||||||
@@ -11633,7 +11754,7 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
|||||||
// more than cornerWidth/6. Skip its work for pairs outside this exact
|
// more than cornerWidth/6. Skip its work for pairs outside this exact
|
||||||
// support, with a small subvoxel guard for float rounding. The final
|
// support, with a small subvoxel guard for float rounding. The final
|
||||||
// shell union only consumes negative distances.
|
// shell union only consumes negative distances.
|
||||||
constexpr double CornerBlendMetres=0.50;
|
constexpr double CornerBlendMetres=VF_PassageCornerBlendMetres;
|
||||||
const float roundDistanceFloat=static_cast<float>(signedDistance);
|
const float roundDistanceFloat=static_cast<float>(signedDistance);
|
||||||
const float floorDistanceFloat=static_cast<float>(floorCenterZ-floorDepth-qz);
|
const float floorDistanceFloat=static_cast<float>(floorCenterZ-floorDepth-qz);
|
||||||
const double flatDistanceLowerBound=std::max(
|
const double flatDistanceLowerBound=std::max(
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Linux130 — passage reach
|
||||||
|
|
||||||
|
On `wip/l130-reach-units` from `b96dd73`, passage influence is now **1.0533 m**: 0.75 m shell + 0.21 m relief + 0.50 m smooth-max support (`width/6`) + 0.01 m margin. One metres-to-core-voxels conversion feeds proof, feature, fallback and off-grid bounds; the sweep cutoff uses the same metre value. The dead 4 m cutoff is removed. Evaluator version is 227.
|
||||||
|
|
||||||
|
The debug shell/crest audit sampled 25,728 points, including 5 mm inside and outside the reach; 18,993 had sign-relevant passage contribution. Proof and feature bounds missed none. The nine-station floor probe still peaks at **7.884 mm**, matching L125. The 23 L125 views and six L129 mouth close-ups are byte-identical. Fast verification, walkability and shell audits pass; the seam audit found 0 mismatches across 4 pairs / 4,900 shared samples.
|
||||||
|
|
||||||
|
Clang/GCC W1/W8/W12 hashes agree across all 18 runs. Versus v225, hashes changed for owner4 full-detail, whole-view and LOD0–3; owner2 surface-world and floating-islands whole-view and LOD2–3. Exact-query hashes stayed unchanged. The v227 canonical baselines are recorded; changed hashes reflect the shorter density influence halo, while sampled sign-relevant bounds and captured surfaces remain covered.
|
||||||
|
|
||||||
|
L80 timing used 10 interleaved pairs per stratum/worker count. Across the eight case medians, the weighted deltas were +0.33% for LOD0–2 and +0.31% whole-view. Across 80 paired runs, mean deltas were +0.26% (95% interval −0.44% to +0.96%) and +0.47% (−0.06% to +1.00%); both intervals include zero. No measurable timing change; UE movement was skipped. The Linux UE host build succeeded in 76.30 s with `-NoUBA -MaxParallelActions=4`, without `prlimit`. `ARCHITECTURE.md` and `CODEMAP.md` had no note for this optimized influence reach, so they were unchanged.
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run Clang/GCC owner hashes at W1/W8/W12 and compare with b96dd73."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
OUT = ROOT / "Saved/Linux/l130/hashes"
|
||||||
|
BASELINE = json.loads((ROOT / "Saved/Linux/l125/hashes/summary.json").read_text())
|
||||||
|
DATASETS = {
|
||||||
|
"owner4": ROOT / "Standalone/data/owner_world.json",
|
||||||
|
"owner2": ROOT / "Standalone/data/regression/owner_world_2strate_l61.json",
|
||||||
|
}
|
||||||
|
RECIPES = {"owner4": ("surface-world",),
|
||||||
|
"owner2": ("surface-world", "floating-islands")}
|
||||||
|
BINARIES = {
|
||||||
|
"clang": ROOT / "Saved/Linux/l130/bin/VoxelForgeCoreHeadless-l130-clang",
|
||||||
|
"gcc": ROOT / "Saved/Linux/l130/bin/VoxelForgeCoreHeadless-l130-gcc",
|
||||||
|
}
|
||||||
|
HASH_RE = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
|
||||||
|
STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=(\S+)$", re.M)
|
||||||
|
|
||||||
|
|
||||||
|
def run(dataset: str, recipe: str, workers: int, compiler: str) -> dict:
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
label = f"{dataset}-{recipe}-w{workers}-{compiler}"
|
||||||
|
log = OUT / f"{label}.log"
|
||||||
|
layout = OUT / f"{label}.layout.json"
|
||||||
|
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||||
|
"timeout", "1740s", str(BINARIES[compiler]), str(DATASETS[dataset]),
|
||||||
|
f"--workers={workers}", "--world-assembler-prototype", "--stream-benchmark",
|
||||||
|
"--stream-pipeline", "--force-generate", "--clip-radius=3",
|
||||||
|
"--max-clip-level=8", "--max-level=8", f"--recipe={recipe}",
|
||||||
|
"--stream-hash", f"--resolved-layout-output={layout}"]
|
||||||
|
started = time.monotonic()
|
||||||
|
with log.open("w", encoding="utf-8") as stream:
|
||||||
|
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||||
|
output = log.read_text(encoding="utf-8", errors="replace")
|
||||||
|
hashes = HASH_RE.findall(output)
|
||||||
|
if result.returncode or len(hashes) != 12:
|
||||||
|
raise SystemExit(f"hash run failed: {label}; exit={result.returncode} "
|
||||||
|
f"hashes={len(hashes)} log={log}")
|
||||||
|
stamp = STAMP_RE.search(output)
|
||||||
|
row = {"dataset": dataset, "recipe": recipe, "workers": workers,
|
||||||
|
"compiler": compiler, "exit_code": result.returncode, "hashes": hashes,
|
||||||
|
"source_stamp": stamp.group(1) if stamp else None,
|
||||||
|
"elapsed_s": round(time.monotonic() - started, 3),
|
||||||
|
"log": str(log.relative_to(ROOT))}
|
||||||
|
print("[L130HashRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if any(not path.is_file() for path in (*DATASETS.values(), *BINARIES.values())):
|
||||||
|
raise SystemExit("missing L130 hash input")
|
||||||
|
old = {(row["dataset"], row["recipe"], row["workers"], row["compiler"]): row
|
||||||
|
for row in BASELINE["runs"]}
|
||||||
|
rows = []
|
||||||
|
for dataset, recipes in RECIPES.items():
|
||||||
|
for recipe in recipes:
|
||||||
|
for workers in (1, 8, 12):
|
||||||
|
for compiler in ("clang", "gcc"):
|
||||||
|
rows.append(run(dataset, recipe, workers, compiler))
|
||||||
|
(OUT / "runs-partial.json").write_text(
|
||||||
|
json.dumps(rows, indent=2) + "\n", encoding="utf-8")
|
||||||
|
groups = {}
|
||||||
|
for dataset, recipes in RECIPES.items():
|
||||||
|
for recipe in recipes:
|
||||||
|
group = [row for row in rows if row["dataset"] == dataset
|
||||||
|
and row["recipe"] == recipe]
|
||||||
|
key = f"{dataset}/{recipe}"
|
||||||
|
stable = all(row["hashes"] == group[0]["hashes"] for row in group)
|
||||||
|
baseline = old[(dataset, recipe, 12, "clang")]["hashes"]
|
||||||
|
changed = [i for i, (before, after) in enumerate(zip(baseline,
|
||||||
|
group[0]["hashes"])) if before != after]
|
||||||
|
groups[key] = {"all_workers_and_compilers_match": stable,
|
||||||
|
"matches_b96dd73_v225": not changed,
|
||||||
|
"changed_hash_rows_from_v225": changed,
|
||||||
|
"source_stamps": sorted({row["source_stamp"] for row in group})}
|
||||||
|
if not stable:
|
||||||
|
raise SystemExit(f"worker/compiler hash mismatch: {key}")
|
||||||
|
(OUT / "summary.json").write_text(
|
||||||
|
json.dumps({"baseline_source": "b96dd73", "runs": rows,
|
||||||
|
"groups": groups}, indent=2) + "\n", encoding="utf-8")
|
||||||
|
print("[L130HashSummary] " + json.dumps(groups, sort_keys=True), flush=True)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Render the six L129 b96dd73 mouth views against the L130 meshes."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import html
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
SOURCE = ROOT / "Saved/Linux/l129/captures/mouth-closeups/before"
|
||||||
|
SAVED = ROOT / "Saved/Linux/l130/captures/mouth-closeups"
|
||||||
|
CAPTURES = ROOT / "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups"
|
||||||
|
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||||
|
HEADLESS = ROOT / "Saved/Linux/l130/bin/VoxelForgeCoreHeadless-l130-clang"
|
||||||
|
RENDERER = ROOT / "Saved/Linux/l130/bin/VoxelForgeOffscreenCapture-l130-clang"
|
||||||
|
HEADLESS_CONFIG = re.compile(
|
||||||
|
r"^\[HeadlessConfig\].*?camera_m=\(([^)]*)\) camera_rotation_deg=\(([^)]*)\)", re.M)
|
||||||
|
SCENE = re.compile(r"^\[OffscreenScene\].*?height_center_m=(-?[\d.]+)", re.M)
|
||||||
|
DRAWN = re.compile(r"drawn_triangles=(\d+)")
|
||||||
|
|
||||||
|
|
||||||
|
def wrapped(command: list[str]) -> list[str]:
|
||||||
|
return ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||||
|
"timeout", "1740s", *map(str, command)]
|
||||||
|
|
||||||
|
|
||||||
|
def run(label: str, command: list[str], log: Path) -> str:
|
||||||
|
started = time.monotonic()
|
||||||
|
log.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with log.open("w", encoding="utf-8") as output:
|
||||||
|
result = subprocess.run(wrapped(command), cwd=ROOT, stdout=output,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||||
|
content = log.read_text(encoding="utf-8", errors="replace")
|
||||||
|
if result.returncode:
|
||||||
|
raise SystemExit(f"{label} failed exit={result.returncode}: {log}")
|
||||||
|
print(f"[L130MouthProcess] {label} elapsed_s={time.monotonic()-started:.2f}",
|
||||||
|
flush=True)
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def parse_vector(text: str) -> tuple[float, ...]:
|
||||||
|
return tuple(float(value) for value in text.split(","))
|
||||||
|
|
||||||
|
|
||||||
|
def sha256(path: Path) -> str:
|
||||||
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if any(not path.is_file() for path in (DATA, HEADLESS, RENDERER)):
|
||||||
|
raise SystemExit("missing L130 mouth capture input")
|
||||||
|
(CAPTURES / "b96dd73").mkdir(parents=True, exist_ok=True)
|
||||||
|
(CAPTURES / "L130").mkdir(parents=True, exist_ok=True)
|
||||||
|
rows = []
|
||||||
|
for source_log in sorted(SOURCE.glob("*-mouth-mesh.log")):
|
||||||
|
name = source_log.name.removesuffix("-mesh.log")
|
||||||
|
source_render = SOURCE / f"{name}-render.log"
|
||||||
|
baseline_mesh = SOURCE / f"{name}.vfmesh"
|
||||||
|
if not all(path.is_file() for path in (source_render, baseline_mesh)):
|
||||||
|
raise SystemExit(f"missing b96dd73 source artifact for {name}")
|
||||||
|
config = HEADLESS_CONFIG.search(source_log.read_text())
|
||||||
|
scene = SCENE.search(source_render.read_text())
|
||||||
|
if config is None or scene is None:
|
||||||
|
raise SystemExit(f"missing camera metadata for {name}")
|
||||||
|
camera = parse_vector(config.group(1))
|
||||||
|
yaw, pitch = parse_vector(config.group(2))
|
||||||
|
height_center = float(scene.group(1))
|
||||||
|
camera_arg = ",".join(f"{value:.6f}" for value in (*camera, yaw, pitch))
|
||||||
|
candidate_mesh = SAVED / "L130" / f"{name}.vfmesh"
|
||||||
|
candidate_mesh.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
run(f"{name}-mesh", [HEADLESS, DATA, "--world-assembler-prototype",
|
||||||
|
"--stream-benchmark", "--stream-pipeline", "--workers=12",
|
||||||
|
"--clip-radius=3", "--max-clip-level=0", "--max-level=0",
|
||||||
|
"--force-generate", "--recipe=surface-world", f"--camera={camera_arg}",
|
||||||
|
"--render-distance-chunks=1", f"--mesh-export={candidate_mesh}"],
|
||||||
|
SAVED / "L130" / f"{name}-mesh.log")
|
||||||
|
if not candidate_mesh.is_file() or candidate_mesh.stat().st_size == 0:
|
||||||
|
raise SystemExit(f"empty L130 mesh for {name}")
|
||||||
|
|
||||||
|
render_args = ["--size=1920x1080",
|
||||||
|
f"--camera-m={','.join(f'{value:.6f}' for value in camera)}",
|
||||||
|
f"--yaw-deg={yaw:.6f}", f"--pitch-deg={pitch:.6f}",
|
||||||
|
"--shade=readable", "--headlamp=on", "--height-tint=on",
|
||||||
|
f"--height-center-m={height_center:.6f}", "--height-range-m=32"]
|
||||||
|
images = {}
|
||||||
|
draw_counts = {}
|
||||||
|
for variant, mesh in (("b96dd73", baseline_mesh), ("L130", candidate_mesh)):
|
||||||
|
image = CAPTURES / variant / f"{name}.png"
|
||||||
|
render_log = SAVED / variant / f"{name}-render.log"
|
||||||
|
content = run(f"{name}-{variant}-render",
|
||||||
|
[RENDERER, mesh, image, *render_args], render_log)
|
||||||
|
drawn = DRAWN.search(content)
|
||||||
|
if drawn is None or int(drawn.group(1)) <= 0 or not image.is_file():
|
||||||
|
raise SystemExit(f"render has no visible triangles for {name}/{variant}")
|
||||||
|
images[variant] = image
|
||||||
|
draw_counts[variant] = int(drawn.group(1))
|
||||||
|
equal = images["b96dd73"].read_bytes() == images["L130"].read_bytes()
|
||||||
|
row = {"name": name, "camera_m": camera, "yaw_deg": yaw,
|
||||||
|
"pitch_deg": pitch, "height_center_m": height_center,
|
||||||
|
"source_mesh": str(baseline_mesh.relative_to(ROOT)),
|
||||||
|
"candidate_mesh": str(candidate_mesh.relative_to(ROOT)),
|
||||||
|
"baseline_png": str(images["b96dd73"].relative_to(ROOT)),
|
||||||
|
"candidate_png": str(images["L130"].relative_to(ROOT)),
|
||||||
|
"baseline_sha256": sha256(images["b96dd73"]),
|
||||||
|
"candidate_sha256": sha256(images["L130"]),
|
||||||
|
"byte_identical": equal, "drawn_triangles": draw_counts}
|
||||||
|
rows.append(row)
|
||||||
|
print(f"[L130MouthCompare] {name} byte_identical={equal} "
|
||||||
|
f"sha256={row['candidate_sha256']}", flush=True)
|
||||||
|
|
||||||
|
if len(rows) != 6:
|
||||||
|
raise SystemExit(f"expected six L129 mouth views, found {len(rows)}")
|
||||||
|
(CAPTURES / "summary.json").write_text(json.dumps(rows, indent=2) + "\n")
|
||||||
|
sections = []
|
||||||
|
for row in rows:
|
||||||
|
name = html.escape(row["name"])
|
||||||
|
sections.append(f"<section><h2>{name}</h2><p>byte identical: "
|
||||||
|
f"{str(row['byte_identical']).lower()}</p><div>"
|
||||||
|
f"<figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/{name}.png'></figure>"
|
||||||
|
f"<figure><figcaption>L130 reach units</figcaption><img src='L130/{name}.png'></figure>"
|
||||||
|
"</div></section>")
|
||||||
|
page = ("<!doctype html><meta charset='utf-8'><title>L130 mouth closeups</title>"
|
||||||
|
"<style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}"
|
||||||
|
"section{margin:28px 0}div{display:grid;grid-template-columns:1fr 1fr;gap:12px}"
|
||||||
|
"img{width:100%;height:auto}p{color:#bbb}</style>"
|
||||||
|
"<h1>L129 mouth closeups: b96dd73 vs L130</h1>" + "\n".join(sections))
|
||||||
|
(CAPTURES / "COMPARE.html").write_text(page)
|
||||||
|
return 0 if all(row["byte_identical"] for row in rows) else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Render the 23 L125 camera poses with the L130 evaluator and compare them."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import html
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
RESEARCH = Path(__file__).resolve().parent
|
||||||
|
CAPTURES = RESEARCH / "captures"
|
||||||
|
SAVED = ROOT / "Saved/Linux/l130/captures"
|
||||||
|
BASELINE_INDEX = (ROOT / "Standalone/Research/WorldAssemblerM3/Linux119"
|
||||||
|
/ "captures/L119/capture-index.json")
|
||||||
|
REFERENCE = ROOT / "Standalone/Research/WorldAssemblerM3/Linux125/captures/L125"
|
||||||
|
LAYOUT = ROOT / "Saved/Linux/l130/hashes/owner4-surface-world-w12-clang.layout.json"
|
||||||
|
HEADLESS = ROOT / "Saved/Linux/l130/bin/VoxelForgeCoreHeadless-l130-clang"
|
||||||
|
RENDERER = ROOT / "Saved/Linux/l130/bin/VoxelForgeOffscreenCapture-l130-clang"
|
||||||
|
HELPER_PATH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux113/RunL113Captures.py"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if any(not path.is_file() for path in
|
||||||
|
(BASELINE_INDEX, REFERENCE / "passage-0-1-0-rock-floor-station-1.png",
|
||||||
|
LAYOUT, HEADLESS, RENDERER)):
|
||||||
|
raise SystemExit("missing pose, layout, or L130 capture input")
|
||||||
|
spec = importlib.util.spec_from_file_location("l125_capture_runner",
|
||||||
|
ROOT / "Standalone/Research/WorldAssemblerM3/Linux125/RunL125Captures.py")
|
||||||
|
if spec is None or spec.loader is None:
|
||||||
|
raise SystemExit("cannot load the verified L125 pose set")
|
||||||
|
runner = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(runner)
|
||||||
|
runner.RESEARCH = RESEARCH
|
||||||
|
runner.CAPTURES = CAPTURES
|
||||||
|
runner.SAVED = SAVED
|
||||||
|
runner.LAYOUT = LAYOUT
|
||||||
|
runner.CLANG = HEADLESS
|
||||||
|
runner.RENDERER = RENDERER
|
||||||
|
runner.HELPERS.RESEARCH = RESEARCH
|
||||||
|
runner.HELPERS.CAPTURES = CAPTURES
|
||||||
|
runner.HELPERS.SAVED = SAVED
|
||||||
|
runner.HELPERS.BINARIES = {"L125": HEADLESS}
|
||||||
|
runner.HELPERS.RENDERERS = {"L125": RENDERER}
|
||||||
|
if runner.main() != 0:
|
||||||
|
raise SystemExit("L130 pose generation failed")
|
||||||
|
|
||||||
|
new_captures = CAPTURES / "L125"
|
||||||
|
new_saved = SAVED / "L125"
|
||||||
|
index_path = new_captures / "capture-index.json"
|
||||||
|
data = json.loads(index_path.read_text())
|
||||||
|
if len(data["captures"]) != 23:
|
||||||
|
raise SystemExit(f"expected 23 poses, found {len(data['captures'])}")
|
||||||
|
identical = 0
|
||||||
|
sections = []
|
||||||
|
for row in data["captures"]:
|
||||||
|
name = row["name"]
|
||||||
|
old_image = REFERENCE / f"{name}.png"
|
||||||
|
new_image = new_captures / f"{name}.png"
|
||||||
|
if not old_image.is_file() or not new_image.is_file():
|
||||||
|
raise SystemExit(f"missing comparison image for {name}")
|
||||||
|
same = old_image.read_bytes() == new_image.read_bytes()
|
||||||
|
identical += int(same)
|
||||||
|
row["variant"] = "L130-v227"
|
||||||
|
row["capture"] = row["capture"].replace("captures/L125/", "captures/L130/")
|
||||||
|
row["scene"] = row["scene"].replace("captures/L125/", "captures/L130/")
|
||||||
|
row["logs"] = [path.replace("captures/L125/", "captures/L130/")
|
||||||
|
for path in row.get("logs", [])]
|
||||||
|
sections.append(f"<section><h2>{html.escape(row['passage'])} — "
|
||||||
|
f"{html.escape(row.get('station', ''))}</h2><p>{html.escape(row['kind'])} · "
|
||||||
|
f"byte identical: {str(same).lower()}</p><div>"
|
||||||
|
f"<figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/{html.escape(name)}.png'></figure>"
|
||||||
|
f"<figure><figcaption>L130 v227</figcaption><img src='L130/{html.escape(name)}.png'></figure>"
|
||||||
|
"</div></section>")
|
||||||
|
if identical != 23:
|
||||||
|
raise SystemExit(f"only {identical}/23 L125 pose captures are byte-identical")
|
||||||
|
|
||||||
|
index_path.write_text(json.dumps(data, indent=2) + "\n")
|
||||||
|
old_captures, old_saved = CAPTURES / "L130", SAVED / "L130"
|
||||||
|
if old_captures.exists():
|
||||||
|
shutil.rmtree(old_captures)
|
||||||
|
if old_saved.exists():
|
||||||
|
shutil.rmtree(old_saved)
|
||||||
|
new_captures.rename(old_captures)
|
||||||
|
new_saved.rename(old_saved)
|
||||||
|
page = ("<!doctype html><meta charset='utf-8'><title>L130 passage captures</title>"
|
||||||
|
"<style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}"
|
||||||
|
"section{margin:28px 0}div{display:grid;grid-template-columns:1fr 1fr;gap:12px}"
|
||||||
|
"img{width:100%;height:auto}p{color:#bbb}</style>"
|
||||||
|
"<h1>L125 v225 vs L130 v227: passage captures</h1>" + "\n".join(sections))
|
||||||
|
(CAPTURES / "COMPARE.html").write_text(page)
|
||||||
|
print(f"[L130PoseCapture] poses=23 byte_identical={identical}/23", flush=True)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Five interleaved L80 near-ready runs per stratum/worker vs b96dd73."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import statistics
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[4]
|
||||||
|
OUT = ROOT / "Saved/Linux/l130/timing"
|
||||||
|
PASS_ID = int(os.environ.get("VOXELFORGE_L130_TIMING_PASS", "1"))
|
||||||
|
REPLICATE_FIRST = (PASS_ID - 1) * 5 + 1
|
||||||
|
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||||
|
BINARIES = {
|
||||||
|
"b96dd73": ROOT / "Saved/Linux/l125/bin/VoxelForgeCoreHeadless-l125-clang",
|
||||||
|
"L130": ROOT / "Saved/Linux/l130/bin/VoxelForgeCoreHeadless-l130-clang",
|
||||||
|
}
|
||||||
|
CAMERAS = {
|
||||||
|
0: (8.0, 16.0, -372.2626953125),
|
||||||
|
1: (25.8369140625, 3.19921875, -737.0),
|
||||||
|
2: (19.166015625, -14.2001953125, -753.3740234375),
|
||||||
|
3: (-20.0625, -5.068359375, -900.353515625),
|
||||||
|
}
|
||||||
|
PIPELINE_RE = re.compile(r"^\[StreamPipeline\] (.*)$", re.M)
|
||||||
|
FIELDS_RE = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||||
|
NEAR_RE = re.compile(
|
||||||
|
r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$",
|
||||||
|
re.M)
|
||||||
|
|
||||||
|
|
||||||
|
def run(strate: int, workers: int, version: str, phase: str, replicate: int) -> dict:
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
pass_suffix = "" if PASS_ID == 1 else f"-p{PASS_ID}"
|
||||||
|
label = f"s{strate}-w{workers}-{version}-{phase}{replicate}-l130-v227{pass_suffix}"
|
||||||
|
log = OUT / f"{label}.log"
|
||||||
|
camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
|
||||||
|
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||||
|
"timeout", "1740s", str(BINARIES[version]), str(DATA),
|
||||||
|
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||||
|
f"--workers={workers}", "--clip-radius=3", "--max-clip-level=8",
|
||||||
|
"--max-level=8", f"--camera={camera}", "--profile-lod-work",
|
||||||
|
"--stream-scheduler-policy=3"]
|
||||||
|
started = time.monotonic()
|
||||||
|
with log.open("w", encoding="utf-8") as output:
|
||||||
|
result = subprocess.run(command, cwd=ROOT, stdout=output,
|
||||||
|
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||||
|
content = log.read_text(encoding="utf-8", errors="replace")
|
||||||
|
pipeline, near = PIPELINE_RE.search(content), NEAR_RE.search(content)
|
||||||
|
if result.returncode or pipeline is None or near is None:
|
||||||
|
raise SystemExit(f"timing run failed: {log}; exit={result.returncode}")
|
||||||
|
fields = dict(FIELDS_RE.findall(pipeline.group(1)))
|
||||||
|
row = {"strate": strate, "workers": workers, "version": version,
|
||||||
|
"phase": phase, "replicate": replicate, "exit_code": result.returncode,
|
||||||
|
"wall_s": round(time.monotonic() - started, 3),
|
||||||
|
"lod02_ready_s": float(near.group(3)),
|
||||||
|
"whole_view_ready_s": float(fields["whole_view_ready"].removesuffix("s")),
|
||||||
|
"log": str(log.relative_to(ROOT))}
|
||||||
|
print("[L130TimingRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if any(not path.is_file() for path in (DATA, *BINARIES.values())):
|
||||||
|
raise SystemExit("missing L130 timing input")
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
load_1m = __import__("os").getloadavg()[0]
|
||||||
|
def cpu_idle(interval: float = 2.0) -> float:
|
||||||
|
def totals() -> tuple[int, int]:
|
||||||
|
fields = Path("/proc/stat").read_text().splitlines()[0].split()
|
||||||
|
values = [int(value) for value in fields[1:]]
|
||||||
|
return sum(values), values[3] + (values[4] if len(values) > 4 else 0)
|
||||||
|
before = totals()
|
||||||
|
time.sleep(interval)
|
||||||
|
after = totals()
|
||||||
|
return 100.0 * (after[1] - before[1]) / max(1, after[0] - before[0])
|
||||||
|
idle = cpu_idle()
|
||||||
|
pass_suffix = "" if PASS_ID == 1 else f"-p{PASS_ID}"
|
||||||
|
(OUT / f"machine-load-v227{pass_suffix}-before.txt").write_text(
|
||||||
|
f"1-minute load: {load_1m:.2f}\n2-second CPU idle: {idle:.1f}%\n")
|
||||||
|
print(f"[L130TimingGate] load_1m={load_1m:.2f} cpu_idle_2s={idle:.1f}%",
|
||||||
|
flush=True)
|
||||||
|
if load_1m >= 0.9 or idle < 97.0:
|
||||||
|
raise SystemExit("timing refused: machine is above the quiet-load gate")
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for strate in range(4):
|
||||||
|
for workers in (8, 12):
|
||||||
|
for version in BINARIES:
|
||||||
|
run(strate, workers, version, "warmup", 0)
|
||||||
|
for replicate in range(REPLICATE_FIRST, REPLICATE_FIRST + 5):
|
||||||
|
order = tuple(BINARIES) if replicate % 2 else tuple(reversed(BINARIES))
|
||||||
|
for version in order:
|
||||||
|
rows.append(run(strate, workers, version, "measured", replicate))
|
||||||
|
(OUT / f"runs-v227{pass_suffix}-partial.json").write_text(
|
||||||
|
json.dumps(rows, indent=2) + "\n", encoding="utf-8")
|
||||||
|
prior_runs = []
|
||||||
|
if PASS_ID > 1:
|
||||||
|
previous = OUT / ("v227-summary.json" if PASS_ID == 2
|
||||||
|
else "v227-combined-summary.json")
|
||||||
|
if previous.is_file():
|
||||||
|
prior_runs = json.loads(previous.read_text(encoding="utf-8")).get("runs", [])
|
||||||
|
all_rows = prior_runs + rows
|
||||||
|
measured_rows = [row for row in all_rows if row["phase"] == "measured"]
|
||||||
|
summary = []
|
||||||
|
for strate in range(4):
|
||||||
|
for workers in (8, 12):
|
||||||
|
group_size = sum(row["strate"] == strate and row["workers"] == workers
|
||||||
|
for row in measured_rows) // 2
|
||||||
|
item = {"strate": strate, "workers": workers,
|
||||||
|
"replicates_per_version": group_size}
|
||||||
|
medians = {}
|
||||||
|
for version in BINARIES:
|
||||||
|
group = [row for row in measured_rows if row["strate"] == strate
|
||||||
|
and row["workers"] == workers and row["version"] == version]
|
||||||
|
medians[version] = {}
|
||||||
|
for key in ("lod02_ready_s", "whole_view_ready_s"):
|
||||||
|
values = [row[key] for row in group]
|
||||||
|
medians[version][key] = statistics.median(values)
|
||||||
|
item[f"{version}_{key}_values"] = values
|
||||||
|
item[f"{version}_{key}_median"] = medians[version][key]
|
||||||
|
for key in ("lod02_ready_s", "whole_view_ready_s"):
|
||||||
|
item[f"L130_vs_b96dd73_{key}_delta_pct"] = round(
|
||||||
|
100.0*(medians["L130"][key]/medians["b96dd73"][key]-1.0), 2)
|
||||||
|
summary.append(item)
|
||||||
|
summary_path = OUT / ("v227-summary.json" if PASS_ID == 1
|
||||||
|
else f"v227-combined-summary.json")
|
||||||
|
summary_path.write_text(json.dumps(
|
||||||
|
{"runs": all_rows, "summary": summary}, indent=2) + "\n", encoding="utf-8")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!doctype html><meta charset='utf-8'><title>L130 passage captures</title><style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}section{margin:28px 0}div{display:grid;grid-template-columns:1fr 1fr;gap:12px}img{width:100%;height:auto}p{color:#bbb}</style><h1>L125 v225 vs L130 v227: passage captures</h1><section><h2>passage/0-1/0 — rock-floor/401.7m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-rock-floor-station-1.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-rock-floor-station-1.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — rock-floor/792.8m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-rock-floor-station-2.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-rock-floor-station-2.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — rock-floor/1634.5m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-rock-floor-station-3.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-rock-floor-station-3.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — rock-floor/27.0m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-rock-floor-station-1.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-rock-floor-station-1.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — rock-floor/52.9m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-rock-floor-station-2.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-rock-floor-station-2.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — rock-floor/78.9m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-rock-floor-station-3.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-rock-floor-station-3.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — rock-floor/323.4m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-rock-floor-station-1.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-rock-floor-station-1.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — rock-floor/333.4m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-rock-floor-station-2.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-rock-floor-station-2.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — rock-floor/343.4m</h2><p>rock-floor-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-rock-floor-station-3.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-rock-floor-station-3.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — section-1/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-1-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-openair-1-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — section-1/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-1-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-openair-1-4m-interior-wall.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — section-2/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-2-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-openair-2-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — section-2/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-2-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-openair-2-4m-interior-wall.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — section-3/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-3-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-openair-3-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/0-1/0 — section-3/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-0-1-0-openair-3-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-0-1-0-openair-3-4m-interior-wall.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — section-1/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-1-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-openair-1-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — section-1/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-1-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-openair-1-4m-interior-wall.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — section-2/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-2-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-openair-2-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/1-2/0 — section-2/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-1-2-0-openair-2-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-1-2-0-openair-2-4m-interior-wall.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — section-1/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-1-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-openair-1-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — section-1/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-1-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-openair-1-4m-interior-wall.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — section-2/4m-outside</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-2-4m-outside.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-openair-2-4m-outside.png'></figure></div></section>
|
||||||
|
<section><h2>passage/2-3/0 — section-2/4m-interior-wall</h2><p>open-air-close · byte identical: true</p><div><figure><figcaption>L125 v225</figcaption><img src='../../Linux125/captures/L125/passage-2-3-0-openair-2-4m-interior-wall.png'></figure><figure><figcaption>L130 v227</figcaption><img src='L130/passage-2-3-0-openair-2-4m-interior-wall.png'></figure></div></section>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 106 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<!doctype html><meta charset='utf-8'><title>L130 mouth closeups</title><style>body{font:14px system-ui;margin:24px;background:#17191d;color:#eee}section{margin:28px 0}div{display:grid;grid-template-columns:1fr 1fr;gap:12px}img{width:100%;height:auto}p{color:#bbb}</style><h1>L129 mouth closeups: b96dd73 vs L130</h1><section><h2>passage-0-1-0-lower-mouth</h2><p>byte identical: true</p><div><figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/passage-0-1-0-lower-mouth.png'></figure><figure><figcaption>L130 reach units</figcaption><img src='L130/passage-0-1-0-lower-mouth.png'></figure></div></section>
|
||||||
|
<section><h2>passage-0-1-0-upper-mouth</h2><p>byte identical: true</p><div><figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/passage-0-1-0-upper-mouth.png'></figure><figure><figcaption>L130 reach units</figcaption><img src='L130/passage-0-1-0-upper-mouth.png'></figure></div></section>
|
||||||
|
<section><h2>passage-1-2-0-lower-mouth</h2><p>byte identical: true</p><div><figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/passage-1-2-0-lower-mouth.png'></figure><figure><figcaption>L130 reach units</figcaption><img src='L130/passage-1-2-0-lower-mouth.png'></figure></div></section>
|
||||||
|
<section><h2>passage-1-2-0-upper-mouth</h2><p>byte identical: true</p><div><figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/passage-1-2-0-upper-mouth.png'></figure><figure><figcaption>L130 reach units</figcaption><img src='L130/passage-1-2-0-upper-mouth.png'></figure></div></section>
|
||||||
|
<section><h2>passage-2-3-0-lower-mouth</h2><p>byte identical: true</p><div><figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/passage-2-3-0-lower-mouth.png'></figure><figure><figcaption>L130 reach units</figcaption><img src='L130/passage-2-3-0-lower-mouth.png'></figure></div></section>
|
||||||
|
<section><h2>passage-2-3-0-upper-mouth</h2><p>byte identical: true</p><div><figure><figcaption>b96dd73 source mesh</figcaption><img src='b96dd73/passage-2-3-0-upper-mouth.png'></figure><figure><figcaption>L130 reach units</figcaption><img src='L130/passage-2-3-0-upper-mouth.png'></figure></div></section>
|
||||||
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,134 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "passage-0-1-0-lower-mouth",
|
||||||
|
"camera_m": [
|
||||||
|
32.688347,
|
||||||
|
9.553723,
|
||||||
|
-735.48053
|
||||||
|
],
|
||||||
|
"yaw_deg": -132.845,
|
||||||
|
"pitch_deg": -6.052,
|
||||||
|
"height_center_m": -736.267,
|
||||||
|
"source_mesh": "Saved/Linux/l129/captures/mouth-closeups/before/passage-0-1-0-lower-mouth.vfmesh",
|
||||||
|
"candidate_mesh": "Saved/Linux/l130/captures/mouth-closeups/L130/passage-0-1-0-lower-mouth.vfmesh",
|
||||||
|
"baseline_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/b96dd73/passage-0-1-0-lower-mouth.png",
|
||||||
|
"candidate_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/L130/passage-0-1-0-lower-mouth.png",
|
||||||
|
"baseline_sha256": "aff7310b94e1b57e9cd1e42d3294e10964aed4a56e74bec8c1cdc0a5b2bffa98",
|
||||||
|
"candidate_sha256": "aff7310b94e1b57e9cd1e42d3294e10964aed4a56e74bec8c1cdc0a5b2bffa98",
|
||||||
|
"byte_identical": true,
|
||||||
|
"drawn_triangles": {
|
||||||
|
"b96dd73": 549170,
|
||||||
|
"L130": 549170
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "passage-0-1-0-upper-mouth",
|
||||||
|
"camera_m": [
|
||||||
|
8.324777,
|
||||||
|
20.450708,
|
||||||
|
-371.84259
|
||||||
|
],
|
||||||
|
"yaw_deg": -175.826,
|
||||||
|
"pitch_deg": -0.889,
|
||||||
|
"height_center_m": -372.122,
|
||||||
|
"source_mesh": "Saved/Linux/l129/captures/mouth-closeups/before/passage-0-1-0-upper-mouth.vfmesh",
|
||||||
|
"candidate_mesh": "Saved/Linux/l130/captures/mouth-closeups/L130/passage-0-1-0-upper-mouth.vfmesh",
|
||||||
|
"baseline_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/b96dd73/passage-0-1-0-upper-mouth.png",
|
||||||
|
"candidate_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/L130/passage-0-1-0-upper-mouth.png",
|
||||||
|
"baseline_sha256": "76dbb3263eb4f2018d13496f42b6eff7eb875e2029358776e22337aea8893a6d",
|
||||||
|
"candidate_sha256": "76dbb3263eb4f2018d13496f42b6eff7eb875e2029358776e22337aea8893a6d",
|
||||||
|
"byte_identical": true,
|
||||||
|
"drawn_triangles": {
|
||||||
|
"b96dd73": 243380,
|
||||||
|
"L130": 243380
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "passage-1-2-0-lower-mouth",
|
||||||
|
"camera_m": [
|
||||||
|
27.129938,
|
||||||
|
-19.07345,
|
||||||
|
-751.877197
|
||||||
|
],
|
||||||
|
"yaw_deg": -58.537,
|
||||||
|
"pitch_deg": -5.944,
|
||||||
|
"height_center_m": -751.734,
|
||||||
|
"source_mesh": "Saved/Linux/l129/captures/mouth-closeups/before/passage-1-2-0-lower-mouth.vfmesh",
|
||||||
|
"candidate_mesh": "Saved/Linux/l130/captures/mouth-closeups/L130/passage-1-2-0-lower-mouth.vfmesh",
|
||||||
|
"baseline_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/b96dd73/passage-1-2-0-lower-mouth.png",
|
||||||
|
"candidate_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/L130/passage-1-2-0-lower-mouth.png",
|
||||||
|
"baseline_sha256": "1c193b6fcb65b98b1c721704990392dc816486639e047b53bb72b4a17d89ae4c",
|
||||||
|
"candidate_sha256": "1c193b6fcb65b98b1c721704990392dc816486639e047b53bb72b4a17d89ae4c",
|
||||||
|
"byte_identical": true,
|
||||||
|
"drawn_triangles": {
|
||||||
|
"b96dd73": 544808,
|
||||||
|
"L130": 544808
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "passage-1-2-0-upper-mouth",
|
||||||
|
"camera_m": [
|
||||||
|
23.391808,
|
||||||
|
-15.509525,
|
||||||
|
-731.781067
|
||||||
|
],
|
||||||
|
"yaw_deg": -72.785,
|
||||||
|
"pitch_deg": -0.897,
|
||||||
|
"height_center_m": -730.561,
|
||||||
|
"source_mesh": "Saved/Linux/l129/captures/mouth-closeups/before/passage-1-2-0-upper-mouth.vfmesh",
|
||||||
|
"candidate_mesh": "Saved/Linux/l130/captures/mouth-closeups/L130/passage-1-2-0-upper-mouth.vfmesh",
|
||||||
|
"baseline_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/b96dd73/passage-1-2-0-upper-mouth.png",
|
||||||
|
"candidate_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/L130/passage-1-2-0-upper-mouth.png",
|
||||||
|
"baseline_sha256": "28576cefb1b59601d2e68981a7b77fc28a1d667c58ab27292deac0acd9deb338",
|
||||||
|
"candidate_sha256": "28576cefb1b59601d2e68981a7b77fc28a1d667c58ab27292deac0acd9deb338",
|
||||||
|
"byte_identical": true,
|
||||||
|
"drawn_triangles": {
|
||||||
|
"b96dd73": 593026,
|
||||||
|
"L130": 593026
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "passage-2-3-0-lower-mouth",
|
||||||
|
"camera_m": [
|
||||||
|
-28.589163,
|
||||||
|
-1.226313,
|
||||||
|
-898.811707
|
||||||
|
],
|
||||||
|
"yaw_deg": 114.256,
|
||||||
|
"pitch_deg": -6.159,
|
||||||
|
"height_center_m": -898.713,
|
||||||
|
"source_mesh": "Saved/Linux/l129/captures/mouth-closeups/before/passage-2-3-0-lower-mouth.vfmesh",
|
||||||
|
"candidate_mesh": "Saved/Linux/l130/captures/mouth-closeups/L130/passage-2-3-0-lower-mouth.vfmesh",
|
||||||
|
"baseline_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/b96dd73/passage-2-3-0-lower-mouth.png",
|
||||||
|
"candidate_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/L130/passage-2-3-0-lower-mouth.png",
|
||||||
|
"baseline_sha256": "58cd3ea88c754afab20d1cdcaf5f0edf676f0303d9f392d3632a6f2257205766",
|
||||||
|
"candidate_sha256": "58cd3ea88c754afab20d1cdcaf5f0edf676f0303d9f392d3632a6f2257205766",
|
||||||
|
"byte_identical": true,
|
||||||
|
"drawn_triangles": {
|
||||||
|
"b96dd73": 293832,
|
||||||
|
"L130": 293832
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "passage-2-3-0-upper-mouth",
|
||||||
|
"camera_m": [
|
||||||
|
-24.455027,
|
||||||
|
-5.631774,
|
||||||
|
-811.975403
|
||||||
|
],
|
||||||
|
"yaw_deg": 82.691,
|
||||||
|
"pitch_deg": -0.896,
|
||||||
|
"height_center_m": -810.755,
|
||||||
|
"source_mesh": "Saved/Linux/l129/captures/mouth-closeups/before/passage-2-3-0-upper-mouth.vfmesh",
|
||||||
|
"candidate_mesh": "Saved/Linux/l130/captures/mouth-closeups/L130/passage-2-3-0-upper-mouth.vfmesh",
|
||||||
|
"baseline_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/b96dd73/passage-2-3-0-upper-mouth.png",
|
||||||
|
"candidate_png": "Standalone/Research/WorldAssemblerM3/Linux130/captures/mouth-closeups/L130/passage-2-3-0-upper-mouth.png",
|
||||||
|
"baseline_sha256": "6b903c68fac1a20783185afbac8cdad717c6e9374e665e3618e118c5a6aadf51",
|
||||||
|
"candidate_sha256": "6b903c68fac1a20783185afbac8cdad717c6e9374e665e3618e118c5a6aadf51",
|
||||||
|
"byte_identical": true,
|
||||||
|
"drawn_triangles": {
|
||||||
|
"b96dd73": 59554,
|
||||||
|
"L130": 59554
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[PipelineFullDetailHash] tiles=960 density=0x91931a57a067fd92 mesh=0xa818654be89790ac payload=0x370ff80451105a39 topology=0x06e507557aa70173
|
||||||
|
[PipelineWholeViewHash] tiles=2370 density=0xf4d3d09d3f31d9bc mesh=0x520f545165440f40 payload=0x6a45502e6bb7ae01 topology=0x8f7d03ba1e2000f3
|
||||||
|
[PipelineLODHash] lod=0 tiles=512 density=0x2fd4c78685a43cfe mesh=0x50478cff1c1f8ca0 payload=0x54e48e57e0af26de topology=0x860c011cfdb9833a
|
||||||
|
[PipelineLODHash] lod=1 tiles=448 density=0x4b8d9a6dcd2942ad mesh=0x17e89b7087bfe711 payload=0x2389c109eb780db6 topology=0x7eccd4cf560d0630
|
||||||
|
[PipelineLODHash] lod=2 tiles=320 density=0x7640a0646ee5ac17 mesh=0x9b63c5aa29160969 payload=0x91cd7ca9a828149b topology=0xcb558843c345a327
|
||||||
|
[PipelineLODHash] lod=3 tiles=208 density=0xdd07fe8f31ede73a mesh=0xfaa2f90438226625 payload=0x86904d144f5db47c topology=0xcfd10c90d38f3fca
|
||||||
|
[PipelineLODHash] lod=4 tiles=240 density=0xfb11591772a3d18e mesh=0xebf2baee8764591b payload=0xe491d7ac9c0061ad topology=0xd618ac33b95ce494
|
||||||
|
[PipelineLODHash] lod=5 tiles=144 density=0x2f8b7b7fb1e67258 mesh=0x4cd508cbe97344fd payload=0x2b6e96a6050458c9 topology=0x4ff6d0eda8988573
|
||||||
|
[PipelineLODHash] lod=6 tiles=96 density=0x0114a34c8b8d6113 mesh=0xb1fec4d01ae1fa44 payload=0x3e50cfd429b8e950 topology=0x08090c96d15c1618
|
||||||
|
[PipelineLODHash] lod=7 tiles=96 density=0x3836ed8cfce73418 mesh=0x40bc6589c5fc1aac payload=0x677349bcae16790f topology=0x36e3aa53192e6a6b
|
||||||
|
[PipelineLODHash] lod=8 tiles=306 density=0x144f3c1fd722708b mesh=0xef77b28bf7fd9453 payload=0xe3f47b37fcd61489 topology=0x5a3c73e295494e04
|
||||||
|
[PipelineExactQueryHash] probes=9 density=0x7b7c50ac24ccadcc unclamped=0x7b7c50ac24ccadcc detail=0xefcba20c0c70c415 collision=0xe604823a249029bf path=direct-Core-queries
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[PipelineFullDetailHash] tiles=960 density=0x11802e529414a62a mesh=0xee7dab071f572c46 payload=0x824a7c07f3cd3f8f topology=0x14a372c4f0003a9b
|
||||||
|
[PipelineWholeViewHash] tiles=2578 density=0x077534532d13b549 mesh=0x0932314a7475fed4 payload=0x6c2bfa3e4a72f8dc topology=0x7e6b3b76ed31bd0f
|
||||||
|
[PipelineLODHash] lod=0 tiles=512 density=0xf8cbb499fca6f62b mesh=0xf3b8e097407eb9e1 payload=0xeef6bfe266279de5 topology=0x79c5ed3811360d1e
|
||||||
|
[PipelineLODHash] lod=1 tiles=448 density=0x7d95c955a8433cac mesh=0xa803bb427deeba9a payload=0xf4718f1ce85d4f4f topology=0x7b770585aafd8174
|
||||||
|
[PipelineLODHash] lod=2 tiles=320 density=0x1c9445d15cce0de3 mesh=0x4da3bcf40eb6d137 payload=0x561116e3bbf34b8e topology=0x5e0e5a961bea641e
|
||||||
|
[PipelineLODHash] lod=3 tiles=272 density=0xe505981dea225509 mesh=0x1b13027b94137ad0 payload=0x3f93cd2fda3fef1c topology=0x8e160cd2f5ab0805
|
||||||
|
[PipelineLODHash] lod=4 tiles=272 density=0xb743eb64967bddcd mesh=0xf6b5bd36b0ebfead payload=0xd1284c1540f50636 topology=0x4a6e197e2a1a9500
|
||||||
|
[PipelineLODHash] lod=5 tiles=208 density=0x38706b628a74dd17 mesh=0x445b1c7b51489cbb payload=0x713efc66290768f7 topology=0x56486b919146bb1e
|
||||||
|
[PipelineLODHash] lod=6 tiles=144 density=0xd53849b2002a1faa mesh=0xaa210abc8498c415 payload=0xd109aef8639706d1 topology=0x61a4d75fbbc35268
|
||||||
|
[PipelineLODHash] lod=7 tiles=96 density=0xb0ea9a140275c9cc mesh=0x3ffd8365c8b0ec29 payload=0x3577afb0a2e4a420 topology=0x97530aafde15b7e0
|
||||||
|
[PipelineLODHash] lod=8 tiles=306 density=0x8b3d1816799d67a0 mesh=0x80bf554f17700e1e payload=0xccbe22c3333a9c34 topology=0xcb11b28f6b6bcc50
|
||||||
|
[PipelineExactQueryHash] probes=9 density=0xf2df67b38b7802df unclamped=0x48b347986345b557 detail=0xefcba20c0c70c415 collision=0x137e8f6c0b03a624 path=direct-Core-queries
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[PipelineFullDetailHash] tiles=960 density=0xace56c8f205238ad mesh=0xa9c603a1248de6b8 payload=0xea55f1f4fcc6a894 topology=0x5ea7bc78a1b678ae
|
||||||
|
[PipelineWholeViewHash] tiles=2370 density=0x03331b1721d89092 mesh=0x1fa61520dc6c6d7b payload=0xe5c306e087381056 topology=0xef499f11d87ca569
|
||||||
|
[PipelineLODHash] lod=0 tiles=512 density=0xcd6ab28cfa504aca mesh=0xf03dc80a669fca31 payload=0x397aded1c3d2d297 topology=0xb4a1dc84fabc1fe3
|
||||||
|
[PipelineLODHash] lod=1 tiles=448 density=0xce6e713828b2a20a mesh=0x1cf408c25d67d18c payload=0x8a2b5d20571c997e topology=0x51cd985fe8e7d100
|
||||||
|
[PipelineLODHash] lod=2 tiles=320 density=0x8581c27a6966cccd mesh=0x610a6eb3ef75fe11 payload=0xdecaf47d125efd5c topology=0xa5ea883ebeb628e4
|
||||||
|
[PipelineLODHash] lod=3 tiles=208 density=0x5d87341a6428ea0b mesh=0x662096703512f5e2 payload=0x5703acca3ad9c2c7 topology=0xc8fb411f09c46f60
|
||||||
|
[PipelineLODHash] lod=4 tiles=240 density=0x0be8798407724eaf mesh=0x131c303cbbe51434 payload=0x2a90ecf0a2411ca0 topology=0xe3e054a371152e08
|
||||||
|
[PipelineLODHash] lod=5 tiles=144 density=0xf20897ad272103a9 mesh=0x13d00b6253ae1f72 payload=0x0db3880693a962fa topology=0x462bd87a80f15e89
|
||||||
|
[PipelineLODHash] lod=6 tiles=96 density=0xc040fcac457d6313 mesh=0x1ed132eeb718fb62 payload=0xcd0214e35577c6e3 topology=0x2c56c69e6fdcfd64
|
||||||
|
[PipelineLODHash] lod=7 tiles=96 density=0xc2d419446355fdb8 mesh=0x4ea44452574fc84b payload=0xfd9779bedfc9ae0f topology=0x8948546e770c9b72
|
||||||
|
[PipelineLODHash] lod=8 tiles=306 density=0x62db31696f2da831 mesh=0xd373f9e9481532fe payload=0x540a60526e0e3e46 topology=0xc725cb901e6dc335
|
||||||
|
[PipelineExactQueryHash] probes=9 density=0xc949c4df2ce6f9d9 unclamped=0xc949c4df2ce6f9d9 detail=0x114c501e2d830d94 collision=0xe6011d3a248d4849 path=direct-Core-queries
|
||||||
@@ -122,11 +122,11 @@ RECIPE_RE = re.compile(
|
|||||||
|
|
||||||
def owner_hash_baseline(recipe: str, style: int) -> tuple[Path, str]:
|
def owner_hash_baseline(recipe: str, style: int) -> tuple[Path, str]:
|
||||||
if recipe == "surface-world" and style == 1:
|
if recipe == "surface-world" and style == 1:
|
||||||
return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v225.baseline",
|
return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v227.baseline",
|
||||||
"L125-v225-stamped-passage-sweep")
|
"L130-v227-reach-units")
|
||||||
if recipe == "floating-islands" and style == 2:
|
if recipe == "floating-islands" and style == 2:
|
||||||
return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v225.baseline",
|
return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v227.baseline",
|
||||||
"L125-v225-stamped-passage-sweep")
|
"L130-v227-reach-units")
|
||||||
raise VerificationFailure(f"no pinned owner hash baseline for {recipe} style {style}")
|
raise VerificationFailure(f"no pinned owner hash baseline for {recipe} style {style}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||