wip(step3): 12.5 cm voxels, fall-through fixed, brick evaluator in game, organic tunnels -- speed gate FAILS
Stopped by the owner's decision (in-game lit captures were eating the round); he judges the look in game instead. 1. Fall-through with the research field: fixed. Deep drop, gate on: 2 holds (0.50 s), min foot clearance +43 cm; gate off: penetrates (-278 cm). Stress fixture offsets converted to metres. 2. VOXEL_SIZE 25 -> 12.5 cm. Physical sizes kept in metres (player, steps, gate, insets, research field sizes, dig radii, test thresholds); class defaults that count chunks/voxels doubled (ClipRadius 6, RenderDistanceChunks 1536, ViewDistance*, StrateViewMargin 6, PawnCollisionRadius 2, SkirtCells 4, EdgeSealThickness 128, decoration spacings, density volume res 256). Asset values override these defaults: the owner must double his own. Ring scale, six workers, idle, step-2f field before the look changes: 64 m cube (519^3) 4.55 s; 32 m cube (259^3) 0.95 s. 3. In game: tiles go through the brick evaluator (proved by a log marker); profile switch rebuilds the loaded world (~5,800 tiles); full-detail fill 12.4 s after spawn in the visible-window test. 4. Look: round winding tunnels, per-column ellipsoid/lattice caches. All step-2f geometry gates pass at 12.5 cm (0 crumbs, 1 solid component per profile, solid share 69-87%). 259^3 ring, six workers: 1.08-2.02 s (worst HyperComplex) -- the 600 ms gate FAILS. Lit captures failed (hidden/off-screen window, then blank frames); not pursued. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
ca78352e43
commit
bc0f9ee791
33 files changed
+2691
-803
No files matched your search
@@ -55,8 +55,8 @@ using FExploreJsonWriter = TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>;
|
||||
|
||||
constexpr int32 DefaultRenderWidth = 512;
|
||||
constexpr int32 DefaultRenderHeight = 288;
|
||||
constexpr float DefaultRenderStepVoxels = 0.25f;
|
||||
constexpr float DefaultRenderMaxDistanceVoxels = 160.0f;
|
||||
constexpr float DefaultRenderStepVoxels = 0.5f; // 6.25 cm, as at 25 cm/voxel.
|
||||
constexpr float DefaultRenderMaxDistanceVoxels = 320.0f; // 40 m.
|
||||
constexpr int32 DefaultExportSize = 128;
|
||||
constexpr int32 DefaultExportStep = 1;
|
||||
constexpr int32 DefaultMaxWalkCells = 32000000;
|
||||
@@ -1170,6 +1170,32 @@ struct FExploreWorld
|
||||
NewObject<UVoxelSettings>(GetTransientPackage(), NAME_None, RF_Transient));
|
||||
}
|
||||
|
||||
if (bUseAuthoredSettings)
|
||||
{
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeScale3AssetSettings] view_xy=%d view_up=%d view_down=%d "
|
||||
"pawn_collision_radius_chunks=%d strate_view_margin_chunks=%d clip_radius=%d "
|
||||
"render_distance_chunks=%d world_radius_voxels=%.6g edge_seal_thickness_voxels=%.6g "
|
||||
"decoration_radius_chunks=%d decoration_near_radius_chunks=%d "
|
||||
"decoration_region_size_cells=%d decoration_spacing_voxels=%d "
|
||||
"decoration_far_spacing_voxels=%d decoration_march_step_voxels=%d "
|
||||
"decoration_column_depth_voxels=%d density_volume_resolution=%d "
|
||||
"density_volume_debug_radius_cells=%d origin_spine_radius_voxels=%.6g "
|
||||
"max_brush_radius_voxels=%.6g max_total_volume_voxels3=%.6g "
|
||||
"inter_strate_gap_chunks=%d skirt_cells=%.6g"),
|
||||
Settings->ViewDistanceXY, Settings->ViewDistanceUp, Settings->ViewDistanceDown,
|
||||
Settings->PawnCollisionRadiusChunks, Settings->StrateViewMarginChunks,
|
||||
Settings->ClipRadius, Settings->RenderDistanceChunks,
|
||||
Settings->WorldRadiusVoxels, Settings->EdgeSealThickness,
|
||||
Settings->DecorationRadiusChunks, Settings->DecorationNearRadiusChunks,
|
||||
Settings->DecorationRegionSizeCells, Settings->DecorationSpacingVoxels,
|
||||
Settings->DecorationFarSpacingVoxels, Settings->DecorationMarchStepVoxels,
|
||||
Settings->DecorationColumnDepthVoxels, Settings->DensityVolumeResolution,
|
||||
Settings->DensityVolumeDebugRadiusCells, Settings->OriginSpineRadius,
|
||||
Settings->MaxBrushRadius, Settings->MaxTotalVolume,
|
||||
Settings->InterStrateGapChunks, Settings->SkirtCells);
|
||||
}
|
||||
|
||||
const int32 NumStrates = bUseAuthoredSettings
|
||||
? (Arguments.bGameRuntimeConfig
|
||||
? FMath::Max(Settings->TotalStrates, 1)
|
||||
@@ -1187,8 +1213,8 @@ struct FExploreWorld
|
||||
Settings->TotalStrates = NumStrates;
|
||||
Settings->InterStrateGapChunks = 0;
|
||||
Settings->WorldRadiusVoxels = 0.0f;
|
||||
Settings->EdgeSealThickness = 64.0f;
|
||||
Settings->OriginSpineRadius = 14.0f;
|
||||
Settings->EdgeSealThickness = 128.0f;
|
||||
Settings->OriginSpineRadius = 28.0f;
|
||||
Settings->bOpenSurfaceEntry = true;
|
||||
}
|
||||
else if (Arguments.bSeedOverride)
|
||||
@@ -1232,9 +1258,9 @@ struct FExploreWorld
|
||||
Definition->StrateDescription = FText::FromString(
|
||||
TEXT("Transient, deterministic commandlet definition."));
|
||||
// The commandlet's acceptance sweep uses the owner-facing base spacing:
|
||||
// 4 chunks * 32 voxels * 0.25 m = 32 m per strate. Production assets may be taller;
|
||||
// 8 chunks * 32 voxels * 0.125 m = 32 m per strate. Production assets may be taller;
|
||||
// this keeps the measured tunnel arithmetic tied to the stated ~32 m descent.
|
||||
Definition->StrateHeightInChunks = 4;
|
||||
Definition->StrateHeightInChunks = 8;
|
||||
Definition->TransitionType = EVoxelStrateTransition::Hard;
|
||||
Definition->GeneratorType = Index == Arguments.Slot
|
||||
? Arguments.Archetype
|
||||
@@ -2896,7 +2922,7 @@ FStep2dBoundaryStats ComputeStep2dBoundaryStats(
|
||||
const bool bBrickBoundary = (World[Axis] % 8) == 0;
|
||||
const bool bChunkBoundary = (World[Axis] % CHUNK_SIZE) == 0 && Axis < 2;
|
||||
const bool bFeatureBoundary = ((World[Axis] + CellSpacing / 2) % CellSpacing) == 0;
|
||||
if (FMath::Abs(Density[CenterIndex]) <= 12.0f)
|
||||
if (FMath::Abs(Density[CenterIndex]) <= VoxelPassageGeometry::MetersToVoxels(3.0f))
|
||||
{
|
||||
if (bBrickBoundary)
|
||||
{
|
||||
@@ -3074,10 +3100,13 @@ FStep2eVarietyMetrics ComputeStep2eVarietyMetrics(
|
||||
}
|
||||
}
|
||||
Result.OpenFraction = Total > 0 ? static_cast<double>(AirCount) / Total : 0.0;
|
||||
// Each sign-changing lattice edge estimates one quarter-meter-squared patch. This is a
|
||||
// Each sign-changing lattice edge estimates one voxel-face patch. This is a
|
||||
// consistent edge-count estimate, not a marching-cubes triangle integral.
|
||||
Result.SurfaceAreaSquareMeters = static_cast<double>(SurfaceEdgeCount) * 0.25 * 0.25;
|
||||
const double VolumeCubicMeters = static_cast<double>(Total) * 0.25 * 0.25 * 0.25;
|
||||
constexpr double VoxelMeters = static_cast<double>(VOXEL_SIZE) / 100.0;
|
||||
Result.SurfaceAreaSquareMeters = static_cast<double>(SurfaceEdgeCount)
|
||||
* VoxelMeters * VoxelMeters;
|
||||
const double VolumeCubicMeters = static_cast<double>(Total)
|
||||
* VoxelMeters * VoxelMeters * VoxelMeters;
|
||||
Result.SurfaceAreaPerVolume = VolumeCubicMeters > 0.0
|
||||
? Result.SurfaceAreaSquareMeters / VolumeCubicMeters : 0.0;
|
||||
const uint64 AllAdjacencies = HorizontalAdjacencies + VerticalAdjacencies;
|
||||
@@ -3100,7 +3129,8 @@ FStep2eVarietyMetrics ComputeStep2eVarietyMetrics(
|
||||
Result.MeanLongestVerticalAirRunVoxels = ColumnsWithAir > 0
|
||||
? static_cast<double>(TotalLongestRunVoxels) / ColumnsWithAir : 0.0;
|
||||
|
||||
constexpr int32 CoarseStep = 4;
|
||||
constexpr int32 VoxelsPerMeter = static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
constexpr int32 CoarseStep = VoxelsPerMeter;
|
||||
const int32 CoarseDimension = (Dimension - 1) / CoarseStep + 1;
|
||||
const int32 CoarseCount = CoarseDimension * CoarseDimension * CoarseDimension;
|
||||
TArray<int32> Parent;
|
||||
@@ -3323,7 +3353,8 @@ FStep2fFragmentMetrics ComputeStep2fFragmentMetrics(
|
||||
ComponentsIntersectingCore.Add(FindRoot(Index));
|
||||
}
|
||||
}
|
||||
constexpr int32 VoxelsPerCubicMeter = 4 * 4 * 4;
|
||||
constexpr int32 VoxelsPerMeter = static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
constexpr int32 VoxelsPerCubicMeter = VoxelsPerMeter * VoxelsPerMeter * VoxelsPerMeter;
|
||||
TMap<int32, FStep2fFragmentMetrics::FCrumbComponent> CrumbByRoot;
|
||||
for (int32 Index = 0; Index < Count; ++Index)
|
||||
{
|
||||
@@ -3427,18 +3458,39 @@ struct FStep2fGridSignatureMetrics
|
||||
};
|
||||
|
||||
FStep2fGridSignatureMetrics ComputeStep2fGridSignature(
|
||||
const TArray<float>& Density, int32 Dimension, float PitchVoxels)
|
||||
const UVoxelGenerator& Generator, FIntVector RingOrigin, int32 RingDimension,
|
||||
float PitchVoxels)
|
||||
{
|
||||
FStep2fGridSignatureMetrics Result;
|
||||
constexpr int32 SampleStep = 4;
|
||||
FScopedVoxelStackRegistration StackRegistration;
|
||||
constexpr int32 SampleStep = static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
constexpr int32 HalfWindow = static_cast<int32>(
|
||||
3200.0f / VOXEL_SIZE + 0.5f);
|
||||
constexpr int32 XYDimension = 2 * HalfWindow / SampleStep + 1;
|
||||
constexpr int32 HeightLayers = 9;
|
||||
const FIntVector RingCentre = RingOrigin + FIntVector(
|
||||
(RingDimension - 1) / 2, (RingDimension - 1) / 2, (RingDimension - 1) / 2);
|
||||
TArray<uint8> AirSamples;
|
||||
AirSamples.SetNumUninitialized(XYDimension * XYDimension * HeightLayers);
|
||||
int64 AirCount = 0;
|
||||
int64 SampleCount = 0;
|
||||
for (int32 Z = 0; Z < Dimension; Z += SampleStep)
|
||||
for (int32 Y = 0; Y < Dimension; Y += SampleStep)
|
||||
for (int32 X = 0; X < Dimension; X += SampleStep)
|
||||
for (int32 ZIndex = 0; ZIndex < HeightLayers; ++ZIndex)
|
||||
{
|
||||
AirCount += Density[(Z * Dimension + Y) * Dimension + X] > 0.0f ? 1 : 0;
|
||||
++SampleCount;
|
||||
const int32 Z = RingOrigin.Z + FMath::RoundToInt(
|
||||
static_cast<float>(RingDimension - 1) * ZIndex / (HeightLayers - 1));
|
||||
for (int32 YIndex = 0; YIndex < XYDimension; ++YIndex)
|
||||
for (int32 XIndex = 0; XIndex < XYDimension; ++XIndex)
|
||||
{
|
||||
const float WorldX = static_cast<float>(RingCentre.X - HalfWindow
|
||||
+ XIndex * SampleStep);
|
||||
const float WorldY = static_cast<float>(RingCentre.Y - HalfWindow
|
||||
+ YIndex * SampleStep);
|
||||
const uint8 bAir = VoxelForgeRedefinedDensityField::EvaluateParameterized(
|
||||
Generator, WorldX, WorldY, static_cast<float>(Z)) > 0.0f ? 1 : 0;
|
||||
AirSamples[(ZIndex * XYDimension + YIndex) * XYDimension + XIndex] = bAir;
|
||||
AirCount += bAir;
|
||||
++SampleCount;
|
||||
}
|
||||
}
|
||||
const double Mean = SampleCount > 0
|
||||
? static_cast<double>(AirCount) / SampleCount : 0.0;
|
||||
@@ -3453,31 +3505,35 @@ FStep2fGridSignatureMetrics ComputeStep2fGridSignature(
|
||||
for (int32 Direction = 0; Direction < 8; ++Direction)
|
||||
{
|
||||
const float Angle = static_cast<float>(Direction) * 3.14159265358979323846f / 8.0f;
|
||||
const int32 DX = FMath::RoundToInt(Radius * FMath::Cos(Angle));
|
||||
const int32 DY = FMath::RoundToInt(Radius * FMath::Sin(Angle));
|
||||
const int32 DX = FMath::RoundToInt(
|
||||
Radius * FMath::Cos(Angle) / SampleStep);
|
||||
const int32 DY = FMath::RoundToInt(
|
||||
Radius * FMath::Sin(Angle) / SampleStep);
|
||||
if (DX == 0 && DY == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
double Covariance = 0.0;
|
||||
int64 Pairs = 0;
|
||||
for (int32 Z = 0; Z < Dimension; Z += SampleStep)
|
||||
for (int32 Y = 0; Y < Dimension; Y += SampleStep)
|
||||
for (int32 Z = 0; Z < HeightLayers; ++Z)
|
||||
for (int32 Y = 0; Y < XYDimension; ++Y)
|
||||
{
|
||||
const int32 OtherY = Y + DY;
|
||||
if (OtherY < 0 || OtherY >= Dimension)
|
||||
if (OtherY < 0 || OtherY >= XYDimension)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int32 X = 0; X < Dimension; X += SampleStep)
|
||||
for (int32 X = 0; X < XYDimension; ++X)
|
||||
{
|
||||
const int32 OtherX = X + DX;
|
||||
if (OtherX < 0 || OtherX >= Dimension)
|
||||
if (OtherX < 0 || OtherX >= XYDimension)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const bool bAirA = Density[(Z * Dimension + Y) * Dimension + X] > 0.0f;
|
||||
const bool bAirB = Density[(Z * Dimension + OtherY) * Dimension + OtherX] > 0.0f;
|
||||
const bool bAirA = AirSamples[
|
||||
(Z * XYDimension + Y) * XYDimension + X] != 0;
|
||||
const bool bAirB = AirSamples[
|
||||
(Z * XYDimension + OtherY) * XYDimension + OtherX] != 0;
|
||||
Covariance += (static_cast<double>(bAirA) - Mean)
|
||||
* (static_cast<double>(bAirB) - Mean);
|
||||
++Pairs;
|
||||
@@ -3531,22 +3587,24 @@ FStep2fDetailSpectrum ComputeStep2fDetailSpectrum(const TArray<float>& Detail, i
|
||||
for (int32 X = 0; X < Dimension; ++X)
|
||||
{
|
||||
const int32 Index = (Z * Dimension + Y) * Dimension + X;
|
||||
if (X + 1 < Dimension)
|
||||
constexpr int32 PhysicalLagVoxels = static_cast<int32>(25.0f / VOXEL_SIZE + 0.5f);
|
||||
if (X + PhysicalLagVoxels < Dimension)
|
||||
{
|
||||
DifferenceEnergy += FMath::Square(
|
||||
static_cast<double>(Detail[Index + 1] - Detail[Index]));
|
||||
static_cast<double>(Detail[Index + PhysicalLagVoxels] - Detail[Index]));
|
||||
++DifferenceCount;
|
||||
}
|
||||
if (Y + 1 < Dimension)
|
||||
if (Y + PhysicalLagVoxels < Dimension)
|
||||
{
|
||||
DifferenceEnergy += FMath::Square(
|
||||
static_cast<double>(Detail[Index + Dimension] - Detail[Index]));
|
||||
static_cast<double>(Detail[Index + PhysicalLagVoxels * Dimension] - Detail[Index]));
|
||||
++DifferenceCount;
|
||||
}
|
||||
if (Z + 1 < Dimension)
|
||||
if (Z + PhysicalLagVoxels < Dimension)
|
||||
{
|
||||
DifferenceEnergy += FMath::Square(
|
||||
static_cast<double>(Detail[Index + Dimension * Dimension] - Detail[Index]));
|
||||
static_cast<double>(Detail[Index + PhysicalLagVoxels * Dimension * Dimension]
|
||||
- Detail[Index]));
|
||||
++DifferenceCount;
|
||||
}
|
||||
}
|
||||
@@ -3615,9 +3673,10 @@ float Step2fPointTriangleDistanceSquared(
|
||||
FIntVector SelectStep2fMeshOrigin(
|
||||
const TArray<float>& Density, FIntVector RingOrigin, int32 Dimension)
|
||||
{
|
||||
constexpr int32 PhysicalTileVoxels = 64;
|
||||
constexpr int32 ScoreStepVoxels = 4;
|
||||
constexpr int32 CandidateStepVoxels = 32;
|
||||
constexpr int32 VoxelsPerMeter = static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
constexpr int32 PhysicalTileVoxels = 16 * VoxelsPerMeter;
|
||||
constexpr int32 ScoreStepVoxels = VoxelsPerMeter;
|
||||
constexpr int32 CandidateStepVoxels = 8 * VoxelsPerMeter;
|
||||
const int32 MaximumStart = Dimension - 1 - PhysicalTileVoxels;
|
||||
if (Density.Num() != Dimension * Dimension * Dimension || MaximumStart < 0)
|
||||
{
|
||||
@@ -3801,7 +3860,8 @@ TSharedRef<FJsonObject> Step2eChamberVolumeQuantilesJson(
|
||||
{
|
||||
TSharedRef<FJsonObject> Json = MakeShared<FJsonObject>();
|
||||
constexpr double Pi = 3.14159265358979323846;
|
||||
constexpr double CubicMetersPerVoxel = 0.25 * 0.25 * 0.25;
|
||||
constexpr double VoxelMeters = static_cast<double>(VOXEL_SIZE) / 100.0;
|
||||
constexpr double CubicMetersPerVoxel = VoxelMeters * VoxelMeters * VoxelMeters;
|
||||
const double Quantiles[] = {0.10, 0.50, 0.90};
|
||||
const TCHAR* Names[] = {TEXT("p10_m3"), TEXT("p50_m3"), TEXT("p90_m3")};
|
||||
for (int32 Index = 0; Index < UE_ARRAY_COUNT(Quantiles); ++Index)
|
||||
@@ -4191,7 +4251,7 @@ int32 RunStep2d(const FString& Params)
|
||||
Window->SetNumberField(TEXT("origin_z_voxels"), Origin.Z);
|
||||
Window->SetNumberField(TEXT("samples_per_axis"), Dimension);
|
||||
Window->SetNumberField(TEXT("sample_stride_voxels"), 1);
|
||||
Window->SetNumberField(TEXT("sample_spacing_cm"), 25.0);
|
||||
Window->SetNumberField(TEXT("sample_spacing_cm"), VOXEL_SIZE);
|
||||
Report->SetObjectField(TEXT("full_resolution_window"), Window);
|
||||
Report->SetStringField(TEXT("field_definition"),
|
||||
TEXT("A seed-offset periodic cross-corridor signed field per strate, joined with rounded "
|
||||
@@ -4199,7 +4259,7 @@ int32 RunStep2d(const FString& Params)
|
||||
"noise bands (8, 4, 2, and 1 lattice point) with total bounded amplitude 5.25 are "
|
||||
"evaluated at every full-resolution sample that can affect the zero set."));
|
||||
Report->SetStringField(TEXT("resolution_contract"),
|
||||
TEXT("The lattice remains one sample per 25 cm. No coarse density result is interpolated "
|
||||
TEXT("The lattice remains one sample per 12.5 cm. No coarse density result is interpolated "
|
||||
"onto it: every potentially surface-affecting point evaluates all four detail bands. "
|
||||
"Brick skips require a final-field sign proof including the full noise supremum, a "
|
||||
"floating-point safety margin, and the one-sample marching-cubes halo."));
|
||||
@@ -4701,19 +4761,18 @@ int32 RunStep2e(const FString& Params)
|
||||
Report->SetObjectField(TEXT("parameter_ranges_across_eight_profiles"),
|
||||
Step2eParameterRangesJson());
|
||||
Report->SetStringField(TEXT("resolution_contract"),
|
||||
TEXT("One exact field sample per 25 cm lattice point. The four existing 8/4/2/1-sample "
|
||||
TEXT("One exact field sample per 12.5 cm lattice point. The four existing 16/8/4/2-sample "
|
||||
"detail bands are evaluated for every potentially surface-affecting point; no coarse "
|
||||
"field is interpolated onto the lattice. 4-cubed step 2e skips require the final macro field "
|
||||
"Lipschitz interval plus the full 5.25-unit detail supremum and marching-cubes halo."));
|
||||
"Lipschitz interval plus the full 10.5-unit detail supremum and marching-cubes halo."));
|
||||
Report->SetStringField(TEXT("finer_lattice_scaling"),
|
||||
TEXT("For 12.5 cm voxels, double room pitch, room height, tunnel/feature dimensions and "
|
||||
"the broad-to-medium noise periods in sample units to preserve meter-scale shapes. "
|
||||
"Keep the 1-sample detail band or add a finer octave. The lattice grows 8x for a fixed "
|
||||
TEXT("At 12.5 cm, metre-valued macro and noise dimensions convert to twice as many samples; "
|
||||
"the four detail bands retain their metre wavelengths. The lattice grows 8x for a fixed "
|
||||
"world volume; surface bricks grow roughly with area while certified interior bricks "
|
||||
"remain cheap. This scale has not been timed."));
|
||||
"remain cheap."));
|
||||
Report->SetStringField(TEXT("variety_metric_method"),
|
||||
TEXT("Open fraction uses every ring sample. Surface area estimates sign-changing lattice "
|
||||
"edges times 0.25 m squared. Nominal chamber-volume p10/p50/p90 values use the "
|
||||
"edges times 0.125 m squared. Nominal chamber-volume p10/p50/p90 values use the "
|
||||
"uniform per-cell radius roll and room height as circular-cylinder volumes. Tunnel-neck "
|
||||
"share and connected-component sizes use a 1 m downsampled six-neighbor occupancy grid. "
|
||||
"Verticality is the mean longest contiguous open run per XY column, with open-column "
|
||||
@@ -4846,6 +4905,238 @@ int32 RunStep2e(const FString& Params)
|
||||
return bPassed ? 0 : 2;
|
||||
}
|
||||
|
||||
int32 RunStep3ScaleBenchmark(const FString& Params)
|
||||
{
|
||||
FExploreArguments Arguments;
|
||||
FString Error;
|
||||
if (!ParseArguments(Params, Arguments, Error))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeStep3Scale] argument error: %s"), *Error);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int32 Seed = 1337;
|
||||
int32 Workers = VoxelForgeRegionEval::WorkerCount;
|
||||
int32 Profile = 0;
|
||||
FParse::Value(*Params, TEXT("seed="), Seed);
|
||||
FParse::Value(*Params, TEXT("regionworkers="), Workers);
|
||||
FParse::Value(*Params, TEXT("profile="), Profile);
|
||||
Workers = FMath::Clamp(Workers, 1, 32);
|
||||
Profile = FMath::Clamp(Profile, 0,
|
||||
VoxelForgeRedefinedDensityField::GetParameterSetCount() - 1);
|
||||
|
||||
FString ResearchOut;
|
||||
FParse::Value(*Params, TEXT("researchout="), ResearchOut);
|
||||
if (ResearchOut.IsEmpty())
|
||||
{
|
||||
ResearchOut = FPaths::Combine(Arguments.OutDirectory, TEXT("Research/step3-scale"));
|
||||
}
|
||||
ResearchOut = FPaths::ConvertRelativePathToFull(ResearchOut);
|
||||
IFileManager::Get().MakeDirectory(*ResearchOut, true);
|
||||
IFileManager::Get().MakeDirectory(*Arguments.OutDirectory, true);
|
||||
|
||||
FExploreWorld World;
|
||||
int32 RecipeIndex = INDEX_NONE;
|
||||
uint32 RecipeHash = 0;
|
||||
int32 EditChunkCount = 0;
|
||||
FString WorldError;
|
||||
const double PrepareStart = FPlatformTime::Seconds();
|
||||
if (!PrepareRegionEvalWorld(World, Arguments, Seed,
|
||||
RecipeIndex, RecipeHash, EditChunkCount, WorldError))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeStep3Scale] world preparation failed: %s"),
|
||||
*WorldError);
|
||||
return 2;
|
||||
}
|
||||
const double WorldPrepareSeconds = FPlatformTime::Seconds() - PrepareStart;
|
||||
if (World.DiffLayer != nullptr)
|
||||
{
|
||||
World.DiffLayer->Clear();
|
||||
}
|
||||
|
||||
const int32 CenterZ = (World.TargetTopWorldZ + World.TargetBottomWorldZ) / 2;
|
||||
const TCHAR* ProfileName = TEXT("unknown");
|
||||
VoxelForgeRedefinedDensityField::FGenerationParameters ProfileParameters;
|
||||
if (!VoxelForgeRedefinedDensityField::GetParameterSetInfo(
|
||||
Profile, ProfileName, ProfileParameters))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeStep3Scale] profile %d is unavailable."), Profile);
|
||||
return 2;
|
||||
}
|
||||
VoxelForgeRedefinedDensityField::SetEnabled(false);
|
||||
VoxelForgeRedefinedDensityField::SetParameterizedEnabled(true);
|
||||
VoxelForgeRedefinedDensityField::SetLegacyStep2eAuditMode(false);
|
||||
VoxelForgeRedefinedDensityField::SetDetailScale(1.0f);
|
||||
VoxelForgeRedefinedDensityField::SetParameterSet(Profile);
|
||||
|
||||
const int32 Dimensions[] = { 519, 259 };
|
||||
TArray<TSharedPtr<FJsonValue>> CubeRows;
|
||||
bool bPass = Workers == 6;
|
||||
for (const int32 Dimension : Dimensions)
|
||||
{
|
||||
const int32 HalfSpan = (Dimension - 1) / 2;
|
||||
const FIntVector Origin(-HalfSpan, -HalfSpan, CenterZ - HalfSpan);
|
||||
const int64 ExpectedSamples = static_cast<int64>(Dimension)
|
||||
* Dimension * Dimension;
|
||||
TArray<TSharedPtr<FJsonValue>> TrialRows;
|
||||
TArray<double> WallTimes;
|
||||
TArray<double> CpuTimes;
|
||||
uint64 FirstQuantizedHash = 0;
|
||||
uint64 FirstRawHash = 0;
|
||||
bool bDeterministic = true;
|
||||
int32 ObservedWorkersMin = Workers;
|
||||
int64 EvaluatedSamples = -1;
|
||||
int64 SkippedSamples = -1;
|
||||
uint64 BrickCount = 0;
|
||||
uint64 SkippedBricks = 0;
|
||||
|
||||
for (int32 Trial = 0; Trial < 3; ++Trial)
|
||||
{
|
||||
VoxelForgeRegionEval::FTiming Timing;
|
||||
TArray<float> Densities;
|
||||
if (!VoxelForgeRegionEval::EvaluateRedefined(
|
||||
*World.Generator, Origin, Dimension, Workers, 1.0f,
|
||||
Densities, Timing, /*bEnableBrickSkips=*/true,
|
||||
/*bParameterized=*/true))
|
||||
{
|
||||
UE_LOG(LogTemp, Error,
|
||||
TEXT("[VoxelForgeStep3Scale] dimension=%d trial=%d evaluation failed."),
|
||||
Dimension, Trial + 1);
|
||||
VoxelForgeRedefinedDensityField::SetParameterizedEnabled(false);
|
||||
return 2;
|
||||
}
|
||||
if (Densities.Num() != ExpectedSamples || Timing.SampleCount != ExpectedSamples
|
||||
|| Timing.NonFiniteSamples != 0)
|
||||
{
|
||||
UE_LOG(LogTemp, Error,
|
||||
TEXT("[VoxelForgeStep3Scale] dimension=%d trial=%d sample/finite invariant failed."),
|
||||
Dimension, Trial + 1);
|
||||
VoxelForgeRedefinedDensityField::SetParameterizedEnabled(false);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (Trial == 0)
|
||||
{
|
||||
FirstQuantizedHash = Timing.QuantizedHash;
|
||||
FirstRawHash = Timing.RawFloatHash;
|
||||
EvaluatedSamples = Timing.EvaluatedSamples;
|
||||
SkippedSamples = static_cast<int64>(Timing.SkippedSamples);
|
||||
BrickCount = Timing.BrickCount;
|
||||
SkippedBricks = Timing.SkippedBricks;
|
||||
}
|
||||
else
|
||||
{
|
||||
bDeterministic &= Timing.QuantizedHash == FirstQuantizedHash
|
||||
&& Timing.RawFloatHash == FirstRawHash;
|
||||
}
|
||||
ObservedWorkersMin = FMath::Min(ObservedWorkersMin,
|
||||
Timing.ObservedWorkerThreads);
|
||||
WallTimes.Add(Timing.WallSeconds);
|
||||
CpuTimes.Add(Timing.WorkerCpuSeconds);
|
||||
|
||||
TSharedRef<FJsonObject> TrialJson = MakeShared<FJsonObject>();
|
||||
TrialJson->SetNumberField(TEXT("trial"), Trial + 1);
|
||||
TrialJson->SetNumberField(TEXT("wall_seconds"), Timing.WallSeconds);
|
||||
TrialJson->SetNumberField(TEXT("worker_cpu_seconds"), Timing.WorkerCpuSeconds);
|
||||
TrialJson->SetNumberField(TEXT("workers_requested"), Timing.Workers);
|
||||
TrialJson->SetNumberField(TEXT("workers_observed"), Timing.ObservedWorkerThreads);
|
||||
TrialJson->SetNumberField(TEXT("evaluated_samples"),
|
||||
static_cast<double>(Timing.EvaluatedSamples));
|
||||
TrialJson->SetNumberField(TEXT("skipped_samples"),
|
||||
static_cast<double>(Timing.SkippedSamples));
|
||||
TrialJson->SetNumberField(TEXT("bricks"), static_cast<double>(Timing.BrickCount));
|
||||
TrialJson->SetNumberField(TEXT("skipped_bricks"),
|
||||
static_cast<double>(Timing.SkippedBricks));
|
||||
TrialJson->SetStringField(TEXT("quantized_hash"), FString::Printf(
|
||||
TEXT("%016llx"), static_cast<unsigned long long>(Timing.QuantizedHash)));
|
||||
TrialJson->SetStringField(TEXT("raw_float_hash"), FString::Printf(
|
||||
TEXT("%016llx"), static_cast<unsigned long long>(Timing.RawFloatHash)));
|
||||
TrialRows.Add(MakeShared<FJsonValueObject>(TrialJson));
|
||||
}
|
||||
|
||||
WallTimes.Sort();
|
||||
CpuTimes.Sort();
|
||||
TSharedRef<FJsonObject> Cube = MakeShared<FJsonObject>();
|
||||
Cube->SetNumberField(TEXT("dimension"), Dimension);
|
||||
Cube->SetNumberField(TEXT("sample_count"), static_cast<double>(ExpectedSamples));
|
||||
Cube->SetNumberField(TEXT("intervals_per_axis"), Dimension - 1);
|
||||
Cube->SetNumberField(TEXT("sample_spacing_cm"), VOXEL_SIZE);
|
||||
Cube->SetNumberField(TEXT("extent_m_per_axis"),
|
||||
static_cast<double>(Dimension - 1) * VOXEL_SIZE / 100.0);
|
||||
Cube->SetNumberField(TEXT("density_output_mib"),
|
||||
static_cast<double>(ExpectedSamples) * sizeof(float) / (1024.0 * 1024.0));
|
||||
Cube->SetNumberField(TEXT("workers_requested"), Workers);
|
||||
Cube->SetNumberField(TEXT("minimum_workers_observed"), ObservedWorkersMin);
|
||||
Cube->SetNumberField(TEXT("evaluated_samples"), static_cast<double>(EvaluatedSamples));
|
||||
Cube->SetNumberField(TEXT("skipped_samples"), static_cast<double>(SkippedSamples));
|
||||
Cube->SetNumberField(TEXT("bricks"), static_cast<double>(BrickCount));
|
||||
Cube->SetNumberField(TEXT("skipped_bricks"), static_cast<double>(SkippedBricks));
|
||||
Cube->SetNumberField(TEXT("median_wall_seconds"), WallTimes[WallTimes.Num() / 2]);
|
||||
Cube->SetNumberField(TEXT("min_wall_seconds"), WallTimes[0]);
|
||||
Cube->SetNumberField(TEXT("max_wall_seconds"), WallTimes.Last());
|
||||
Cube->SetNumberField(TEXT("median_worker_cpu_seconds"), CpuTimes[CpuTimes.Num() / 2]);
|
||||
Cube->SetBoolField(TEXT("deterministic_three_trials"), bDeterministic);
|
||||
Cube->SetStringField(TEXT("quantized_hash"), FString::Printf(
|
||||
TEXT("%016llx"), static_cast<unsigned long long>(FirstQuantizedHash)));
|
||||
Cube->SetStringField(TEXT("raw_float_hash"), FString::Printf(
|
||||
TEXT("%016llx"), static_cast<unsigned long long>(FirstRawHash)));
|
||||
Cube->SetArrayField(TEXT("trials"), TrialRows);
|
||||
CubeRows.Add(MakeShared<FJsonValueObject>(Cube));
|
||||
bPass &= bDeterministic && ObservedWorkersMin == 6;
|
||||
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeStep3Scale] dimension=%d samples=%lld extent_m=%.3f workers=%d "
|
||||
"median_wall_s=%.6f min=%.6f max=%.6f evaluated=%lld skipped=%lld "
|
||||
"deterministic=%d hash=%016llx"),
|
||||
Dimension, static_cast<long long>(ExpectedSamples),
|
||||
static_cast<double>(Dimension - 1) * VOXEL_SIZE / 100.0,
|
||||
Workers, WallTimes[WallTimes.Num() / 2], WallTimes[0], WallTimes.Last(),
|
||||
static_cast<long long>(EvaluatedSamples), static_cast<long long>(SkippedSamples),
|
||||
bDeterministic ? 1 : 0,
|
||||
static_cast<unsigned long long>(FirstQuantizedHash));
|
||||
}
|
||||
|
||||
TSharedRef<FJsonObject> Report = MakeShared<FJsonObject>();
|
||||
Report->SetNumberField(TEXT("schema_version"), 1);
|
||||
Report->SetStringField(TEXT("tool"), TEXT("VoxelForgeStep3Scale"));
|
||||
Report->SetBoolField(TEXT("pass"), bPass);
|
||||
Report->SetNumberField(TEXT("seed"), Seed);
|
||||
Report->SetNumberField(TEXT("profile"), Profile);
|
||||
Report->SetStringField(TEXT("profile_name"), ProfileName);
|
||||
Report->SetNumberField(TEXT("worker_count"), Workers);
|
||||
Report->SetNumberField(TEXT("voxel_size_cm"), VOXEL_SIZE);
|
||||
Report->SetNumberField(TEXT("chunk_size_voxels"), CHUNK_SIZE);
|
||||
Report->SetNumberField(TEXT("chunk_size_m"),
|
||||
static_cast<double>(CHUNK_SIZE) * VOXEL_SIZE / 100.0);
|
||||
Report->SetNumberField(TEXT("detail_scale"), 1.0);
|
||||
Report->SetBoolField(TEXT("brick_skips_enabled"), true);
|
||||
Report->SetNumberField(TEXT("world_prepare_seconds"), WorldPrepareSeconds);
|
||||
Report->SetNumberField(TEXT("recipe_index"), RecipeIndex);
|
||||
Report->SetNumberField(TEXT("recipe_hash"), RecipeHash);
|
||||
Report->SetNumberField(TEXT("edit_chunk_count"), EditChunkCount);
|
||||
Report->SetArrayField(TEXT("cubes"), CubeRows);
|
||||
|
||||
FString JsonText;
|
||||
const TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonText);
|
||||
const FString ReportPath = FPaths::Combine(ResearchOut, TEXT("step3_scale_benchmark.json"));
|
||||
const FString LaunchReportPath = FPaths::Combine(
|
||||
Arguments.OutDirectory, TEXT("step3_scale_benchmark.json"));
|
||||
if (!FJsonSerializer::Serialize(Report, Writer)
|
||||
|| !FFileHelper::SaveStringToFile(JsonText, *ReportPath,
|
||||
FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)
|
||||
|| !FFileHelper::SaveStringToFile(JsonText, *LaunchReportPath,
|
||||
FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeStep3Scale] report write failed: %s"), *ReportPath);
|
||||
VoxelForgeRedefinedDensityField::SetParameterizedEnabled(false);
|
||||
return 2;
|
||||
}
|
||||
VoxelForgeRedefinedDensityField::SetParameterizedEnabled(false);
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeStep3Scale] pass=%d report=%s"), bPass ? 1 : 0, *ReportPath);
|
||||
return bPass ? 0 : 2;
|
||||
}
|
||||
|
||||
int32 RunStep2f(const FString& Params)
|
||||
{
|
||||
FExploreArguments Arguments;
|
||||
@@ -4943,9 +5234,10 @@ int32 RunStep2f(const FString& Params)
|
||||
FStep2fShapeSnapshot Result;
|
||||
Result.Variety = ComputeStep2eVarietyMetrics(Density, Dimension);
|
||||
Result.Fragments = ComputeStep2fFragmentMetrics(Density, Dimension);
|
||||
Result.Grid = ComputeStep2fGridSignature(Density, Dimension, P.RoomPitchVoxels);
|
||||
Result.Grid = ComputeStep2fGridSignature(
|
||||
*World.Generator, Origin, Dimension, P.RoomPitchVoxels);
|
||||
|
||||
constexpr int32 DetailDimension = 32;
|
||||
constexpr int32 DetailDimension = 8 * static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
const FIntVector DetailOrigin = Origin + FIntVector(
|
||||
(Dimension - DetailDimension) / 2,
|
||||
(Dimension - DetailDimension) / 2,
|
||||
@@ -4970,11 +5262,13 @@ int32 RunStep2f(const FString& Params)
|
||||
const bool bPreviousSkirts = World.Mesher->bGenerateSkirts;
|
||||
World.Mesher->bGenerateSkirts = false;
|
||||
FVoxelMeshData FineMesh;
|
||||
// GenerateMesh clamps cells per tile to CHUNK_SIZE. Eight level-0 tiles
|
||||
// cover the same 64-sample cube as the one level-1 tile below.
|
||||
for (int32 TileZ = 0; TileZ < 2; ++TileZ)
|
||||
for (int32 TileY = 0; TileY < 2; ++TileY)
|
||||
for (int32 TileX = 0; TileX < 2; ++TileX)
|
||||
// GenerateMesh clamps cells per tile to CHUNK_SIZE. At 12.5 cm, a 16 m
|
||||
// full-detail cube is four level-0 chunks across and two level-1 chunks across.
|
||||
constexpr int32 Level0TilesPerAxis = static_cast<int32>(
|
||||
16.0f / (CHUNK_SIZE * VOXEL_SIZE / 100.0f));
|
||||
for (int32 TileZ = 0; TileZ < Level0TilesPerAxis; ++TileZ)
|
||||
for (int32 TileY = 0; TileY < Level0TilesPerAxis; ++TileY)
|
||||
for (int32 TileX = 0; TileX < Level0TilesPerAxis; ++TileX)
|
||||
{
|
||||
const FIntVector TileOrigin = MeshOrigin + FIntVector(
|
||||
TileX * CHUNK_SIZE, TileY * CHUNK_SIZE, TileZ * CHUNK_SIZE);
|
||||
@@ -4987,8 +5281,24 @@ int32 RunStep2f(const FString& Params)
|
||||
FineMesh.Triangles.Add(VertexOffset + Index);
|
||||
}
|
||||
}
|
||||
const FVoxelMeshData CoarseMesh = World.Mesher->GenerateMesh(
|
||||
MeshOrigin, 2, CHUNK_SIZE);
|
||||
FVoxelMeshData CoarseMesh;
|
||||
constexpr int32 Level1TilesPerAxis = static_cast<int32>(
|
||||
16.0f / (CHUNK_SIZE * 2 * VOXEL_SIZE / 100.0f));
|
||||
for (int32 TileZ = 0; TileZ < Level1TilesPerAxis; ++TileZ)
|
||||
for (int32 TileY = 0; TileY < Level1TilesPerAxis; ++TileY)
|
||||
for (int32 TileX = 0; TileX < Level1TilesPerAxis; ++TileX)
|
||||
{
|
||||
const FIntVector TileOrigin = MeshOrigin + FIntVector(
|
||||
TileX * CHUNK_SIZE * 2, TileY * CHUNK_SIZE * 2, TileZ * CHUNK_SIZE * 2);
|
||||
const FVoxelMeshData TileMesh = World.Mesher->GenerateMesh(
|
||||
TileOrigin, 2, CHUNK_SIZE);
|
||||
const int32 VertexOffset = CoarseMesh.Vertices.Num();
|
||||
CoarseMesh.Vertices.Append(TileMesh.Vertices);
|
||||
for (const int32 Index : TileMesh.Triangles)
|
||||
{
|
||||
CoarseMesh.Triangles.Add(VertexOffset + Index);
|
||||
}
|
||||
}
|
||||
World.Mesher->bGenerateSkirts = bPreviousSkirts;
|
||||
Result.Mesh = ComputeStep2fMeshMetrics(FineMesh);
|
||||
Result.Lod1VertexCount = CoarseMesh.Vertices.Num();
|
||||
@@ -4999,7 +5309,7 @@ int32 RunStep2f(const FString& Params)
|
||||
// coarse vertex only needs nearby cells unless its distance is already
|
||||
// large enough to fail the LOD gate; expanding the search makes the
|
||||
// reported value exact even for badly diverged surfaces.
|
||||
constexpr float LodBucketSizeCm = VOXEL_SIZE * 4.0f;
|
||||
constexpr float LodBucketSizeCm = 100.0f;
|
||||
TMap<FIntVector, TArray<int32>> FineTriangleBuckets;
|
||||
FineTriangleBuckets.Reserve(FineMesh.Triangles.Num());
|
||||
for (int32 Triangle = 0; Triangle + 2 < FineMesh.Triangles.Num(); Triangle += 3)
|
||||
@@ -5092,8 +5402,11 @@ int32 RunStep2f(const FString& Params)
|
||||
if (World.Manager != nullptr)
|
||||
{
|
||||
const TArray<FStrateSlot>& Layout = World.Manager->GetLayout();
|
||||
constexpr int32 XYStep = 4; // 1 m coverage grid
|
||||
constexpr int32 ShellOffsets[] = {1, 5, 9};
|
||||
constexpr int32 XYStep = static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
constexpr int32 ShellOffsets[] = {
|
||||
static_cast<int32>(25.0f / VOXEL_SIZE + 0.5f),
|
||||
static_cast<int32>(125.0f / VOXEL_SIZE + 0.5f),
|
||||
static_cast<int32>(225.0f / VOXEL_SIZE + 0.5f)};
|
||||
for (const FStrateSlot& Slot : Layout)
|
||||
{
|
||||
if (Slot.Definition == nullptr)
|
||||
@@ -5130,9 +5443,9 @@ int32 RunStep2f(const FString& Params)
|
||||
Json->SetNumberField(TEXT("six_worker_ring_median_ms"), MedianMs);
|
||||
Json->SetNumberField(TEXT("solid_fraction"), 1.0 - Variety.OpenFraction);
|
||||
Json->SetNumberField(TEXT("air_fraction"), Variety.OpenFraction);
|
||||
Json->SetNumberField(TEXT("air_components_25cm_grid"),
|
||||
Json->SetNumberField(TEXT("air_components_12_5cm_grid"),
|
||||
Shape.Fragments.AirComponents);
|
||||
Json->SetNumberField(TEXT("solid_components_25cm_grid"),
|
||||
Json->SetNumberField(TEXT("solid_components_12_5cm_grid"),
|
||||
Shape.Fragments.SolidComponents);
|
||||
Json->SetNumberField(TEXT("air_crumbs_below_1m3"),
|
||||
static_cast<double>(Shape.Fragments.AirCrumbsBelowOneCubicMeter));
|
||||
@@ -5185,6 +5498,9 @@ int32 RunStep2f(const FString& Params)
|
||||
Json->SetNumberField(TEXT("pitch_autocorrelation_peak"), Shape.Grid.PitchCorrelationPeak);
|
||||
Json->SetNumberField(TEXT("nearby_autocorrelation_peak"), Shape.Grid.NeighborCorrelationPeak);
|
||||
Json->SetNumberField(TEXT("pitch_autocorrelation_excess"), Shape.Grid.PitchPeakExcess);
|
||||
Json->SetNumberField(TEXT("grid_signature_probe_extent_m"), 64.0);
|
||||
Json->SetNumberField(TEXT("grid_signature_probe_spacing_m"), 1.0);
|
||||
Json->SetNumberField(TEXT("grid_signature_probe_height_layers"), 9);
|
||||
Json->SetNumberField(TEXT("detail_rms"), Shape.Detail.Rms);
|
||||
Json->SetNumberField(TEXT("detail_lattice_scale_energy_ratio"),
|
||||
Shape.Detail.LatticeScaleEnergyRatio);
|
||||
@@ -5207,7 +5523,7 @@ int32 RunStep2f(const FString& Params)
|
||||
return Json;
|
||||
};
|
||||
|
||||
constexpr int32 CrumbBoundaryPadding = 64;
|
||||
constexpr int32 CrumbBoundaryPadding = 16 * static_cast<int32>(100.0f / VOXEL_SIZE + 0.5f);
|
||||
const int32 PaddedCrumbDimension = Dimension + 2 * CrumbBoundaryPadding;
|
||||
const FIntVector PaddedCrumbOrigin = Origin
|
||||
- FIntVector(CrumbBoundaryPadding, CrumbBoundaryPadding, CrumbBoundaryPadding);
|
||||
@@ -5295,7 +5611,7 @@ int32 RunStep2f(const FString& Params)
|
||||
bStep2eBandLimitRejected &= LegacyShape.Detail.LatticeScaleEnergyRatio > 0.20;
|
||||
WorstStep2eLodDistance = FMath::Max(
|
||||
WorstStep2eLodDistance, LegacyShape.Lod1P95SurfaceErrorVoxels);
|
||||
bStep2eLodRejected |= LegacyShape.Lod1P95SurfaceErrorVoxels > 0.5;
|
||||
bStep2eLodRejected |= LegacyShape.Lod1P95SurfaceErrorVoxels > 1.0;
|
||||
WorstStep2ePitchCorrelation = FMath::Max(
|
||||
WorstStep2ePitchCorrelation, LegacyShape.Grid.PitchCorrelationPeak);
|
||||
WorstStep2ePitchExcess = FMath::Max(
|
||||
@@ -5383,9 +5699,9 @@ int32 RunStep2f(const FString& Params)
|
||||
&& NewShape.Mesh.ShareDihedralsOver45Degrees <= 0.25
|
||||
&& NewShape.Mesh.P95DihedralDegrees <= 70.0;
|
||||
bStep2fBandLimitPassed &= NewShape.Detail.LatticeScaleEnergyRatio <= 0.20
|
||||
&& NewShape.Detail.Rms >= 0.40;
|
||||
&& NewShape.Detail.Rms >= 0.80;
|
||||
bStep2fLodPassed &= NewShape.Lod1VertexCount > 0
|
||||
&& NewShape.Lod1P95SurfaceErrorVoxels <= 0.5;
|
||||
&& NewShape.Lod1P95SurfaceErrorVoxels <= 1.0;
|
||||
bStep2fGridPassed &= NewShape.Grid.PitchCorrelationPeak <= 0.40
|
||||
&& NewShape.Grid.PitchPeakExcess <= 0.08;
|
||||
bStep2fStructurePassed &= NewSolidFraction >= 0.25 && NewSolidFraction <= 0.88
|
||||
@@ -5565,6 +5881,39 @@ int32 RunStep2f(const FString& Params)
|
||||
const bool bDeterminism = HardestHash == RepeatHash && HardestHash == OneWorkerHash
|
||||
&& Step2eSameWorkerRun(HardestTiming, RepeatTiming)
|
||||
&& Step2eSameWorkerRun(HardestTiming, OneWorkerTiming);
|
||||
|
||||
FIntVector BrickParityOrigin(-28, -28,
|
||||
FMath::FloorToInt(static_cast<float>(CenterZ) / CHUNK_SIZE) * CHUNK_SIZE + 4);
|
||||
const FIntVector BrickParitySize(
|
||||
VoxelForgeRedefinedDensityField::ParameterizedBrickSamples,
|
||||
VoxelForgeRedefinedDensityField::ParameterizedBrickSamples, 16);
|
||||
VoxelForgeRedefinedDensityField::FParameterizedBrickContext BrickParityContext;
|
||||
TArray<float> BrickParityDetail;
|
||||
TArray<float> BrickParityColumn;
|
||||
TArray<float> BrickParityValues;
|
||||
VoxelForgeRedefinedDensityField::EvaluateParameterizedDensityBrick(
|
||||
*World.Generator, BrickParityOrigin, BrickParitySize, 1.0f,
|
||||
BrickParityContext, BrickParityDetail, BrickParityColumn, BrickParityValues);
|
||||
int64 BrickScalarMismatchCount = 0;
|
||||
for (int32 Z = 0; Z < BrickParitySize.Z; ++Z)
|
||||
for (int32 Y = 0; Y < BrickParitySize.Y; ++Y)
|
||||
for (int32 X = 0; X < BrickParitySize.X; ++X)
|
||||
{
|
||||
const float ScalarValue = VoxelForgeRedefinedDensityField::EvaluateParameterized(
|
||||
*World.Generator, static_cast<float>(BrickParityOrigin.X + X),
|
||||
static_cast<float>(BrickParityOrigin.Y + Y),
|
||||
static_cast<float>(BrickParityOrigin.Z + Z));
|
||||
const float BrickValue = BrickParityValues.IsValidIndex(
|
||||
(Z * BrickParitySize.Y + Y) * BrickParitySize.X + X)
|
||||
? BrickParityValues[(Z * BrickParitySize.Y + Y) * BrickParitySize.X + X]
|
||||
: FLT_MAX;
|
||||
BrickScalarMismatchCount += FMemory::Memcmp(
|
||||
&ScalarValue, &BrickValue, sizeof(float)) == 0 ? 0 : 1;
|
||||
}
|
||||
const bool bParameterizedBrickScalarParity =
|
||||
BrickParityValues.Num() == BrickParitySize.X * BrickParitySize.Y * BrickParitySize.Z
|
||||
&& BrickScalarMismatchCount == 0;
|
||||
|
||||
const FStep2dBrickProofAudit ProofAudit = AuditStep2dBrickProofs(
|
||||
*World.Generator, Origin, Dimension, true);
|
||||
const bool bBoundAudit = ProofAudit.CorrectlySkippedBricksAudited > 0
|
||||
@@ -5600,7 +5949,8 @@ int32 RunStep2f(const FString& Params)
|
||||
&& bStep2fGridPassed && bStep2fStructurePassed;
|
||||
const bool bSpeedPass = Workers == 6 && WorstStep2fMs <= 600.0;
|
||||
const bool bPassed = bAllGeometryGatesRejectStep2e && bAllGeometryGatesPassStep2f
|
||||
&& bSpeedPass && bDeterminism && bBoundAudit && bUndersizedBoundCaught
|
||||
&& bSpeedPass && bDeterminism && bParameterizedBrickScalarParity
|
||||
&& bBoundAudit && bUndersizedBoundCaught
|
||||
&& bBoundaryPass && bDeliberateSeamCaught && HardestTiming.NonFiniteSamples == 0;
|
||||
|
||||
TSharedRef<FJsonObject> Gates = MakeShared<FJsonObject>();
|
||||
@@ -5621,7 +5971,7 @@ int32 RunStep2f(const FString& Params)
|
||||
Step2eCrumbNumbers->SetNumberField(TEXT("crumbs_below_1m3_max"), WorstStep2eCrumbs);
|
||||
TSharedRef<FJsonObject> Step2fCrumbNumbers = MakeShared<FJsonObject>();
|
||||
Step2fCrumbNumbers->SetNumberField(TEXT("crumbs_below_1m3_max"), WorstStep2fCrumbs);
|
||||
AddGate(TEXT("crumbs"), TEXT("zero 25 cm-grid components smaller than 64 voxels, measured in a 64-sample-padded volume and restricted to components intersecting the 259-cube"),
|
||||
AddGate(TEXT("crumbs"), TEXT("zero 12.5 cm-grid components smaller than 512 voxels (1 m3), measured in a 128-sample-padded volume and restricted to components intersecting the 259-cube"),
|
||||
bStep2eCrumbsRejected, bStep2fCrumbGatePassed, Step2eCrumbNumbers, Step2fCrumbNumbers);
|
||||
TSharedRef<FJsonObject> Step2eFlakeNumbers = MakeShared<FJsonObject>();
|
||||
Step2eFlakeNumbers->SetNumberField(TEXT("max_dihedral_share_over_45deg"), WorstStep2eDihedralShare);
|
||||
@@ -5637,13 +5987,13 @@ int32 RunStep2f(const FString& Params)
|
||||
TSharedRef<FJsonObject> Step2fDetailNumbers = MakeShared<FJsonObject>();
|
||||
Step2fDetailNumbers->SetNumberField(TEXT("max_lattice_scale_energy_ratio"), WorstStep2fDetailEnergy);
|
||||
Step2fDetailNumbers->SetNumberField(TEXT("min_detail_rms"), BestStep2fDetailRms);
|
||||
AddGate(TEXT("band_limited_detail"), TEXT("detail RMS >= 0.40 and normalized lag-1 difference energy <= 0.20"),
|
||||
AddGate(TEXT("band_limited_detail"), TEXT("detail RMS >= 0.80 voxel units; normalized 25 cm difference energy <= 0.20"),
|
||||
bStep2eBandLimitRejected, bStep2fBandLimitPassed, Step2eDetailNumbers, Step2fDetailNumbers);
|
||||
TSharedRef<FJsonObject> Step2eLodNumbers = MakeShared<FJsonObject>();
|
||||
Step2eLodNumbers->SetNumberField(TEXT("max_l1_p95_surface_distance_voxels"), WorstStep2eLodDistance);
|
||||
TSharedRef<FJsonObject> Step2fLodNumbers = MakeShared<FJsonObject>();
|
||||
Step2fLodNumbers->SetNumberField(TEXT("max_l1_p95_surface_distance_voxels"), WorstStep2fLodDistance);
|
||||
AddGate(TEXT("lod_stability"), TEXT("L1 mesh p95 estimated distance from the L0 isosurface <= 0.5 lattice samples"),
|
||||
AddGate(TEXT("lod_stability"), TEXT("L1 mesh p95 estimated distance from the L0 isosurface <= 1 lattice sample (12.5 cm)"),
|
||||
bStep2eLodRejected, bStep2fLodPassed, Step2eLodNumbers, Step2fLodNumbers);
|
||||
TSharedRef<FJsonObject> Step2eGridNumbers = MakeShared<FJsonObject>();
|
||||
Step2eGridNumbers->SetNumberField(TEXT("max_pitch_autocorrelation"), WorstStep2ePitchCorrelation);
|
||||
@@ -5687,19 +6037,19 @@ int32 RunStep2f(const FString& Params)
|
||||
Report->SetStringField(TEXT("field_definition"),
|
||||
TEXT("Rooms use strongly jittered cells with per-room radii, axis ratios and heights. "
|
||||
"A conservative nearest-neighbor cap leaves a solid web between chambers; a rooted "
|
||||
"tree of narrow tunnels and capped shafts joins them. Sparse ledges, pillars, "
|
||||
"tree of winding, rounded tubes with hash-varied widths and capped shafts joins them. Sparse ledges, pillars, "
|
||||
"stalactites and large hanging masses remain per-cell rolls. The point and "
|
||||
"brick detail samplers share independently rotated 48/24/12-sample bands with a "
|
||||
"twelve-sample shortest period and a smooth ridge response; their final-field "
|
||||
"detail supremum is 3.822 units."));
|
||||
"brick detail samplers share independently rotated 96/48/24-sample bands with a "
|
||||
"24-sample shortest period and a smooth ridge response; their final-field "
|
||||
"detail supremum is 7.644 voxel units."));
|
||||
Report->SetStringField(TEXT("component_method"),
|
||||
TEXT("26-neighbor connected components are counted on the exact 25 cm sign lattice. "
|
||||
"Raw components below 64 samples (< 1 m3) are reported, then a 64-sample pad is "
|
||||
TEXT("26-neighbor connected components are counted on the exact 12.5 cm sign lattice. "
|
||||
"Raw components below 512 samples (< 1 m3) are reported, then a 128-sample (16 m) pad is "
|
||||
"evaluated around each 259-cube and only components intersecting the original cube "
|
||||
"are counted again; this prevents a clipped large component at the ring edge from "
|
||||
"being called a crumb. The one-meter downsampled air component count is also reported."));
|
||||
Report->SetStringField(TEXT("mesh_method"),
|
||||
TEXT("Eight level-0 tiles and one level-1 tile cover the same 64-sample cube selected "
|
||||
TEXT("Sixty-four level-0 tiles and eight level-1 tiles cover the same 128-sample (16 m) cube selected "
|
||||
"for maximum coarse-sampled surface crossings. "
|
||||
"The share of manifold triangle edges whose geometric dihedral exceeds 45 degrees "
|
||||
"and its p95 are measured. Each level-1 vertex is compared with nearby level-0 "
|
||||
@@ -5787,6 +6137,12 @@ int32 RunStep2f(const FString& Params)
|
||||
Existing->SetNumberField(TEXT("brick_boundary_gradient_jump_rms"), BoundaryStats.BrickJumpRms);
|
||||
Existing->SetNumberField(TEXT("brick_interior_gradient_jump_rms"), BoundaryStats.InteriorJumpRms);
|
||||
Existing->SetBoolField(TEXT("one_and_six_worker_determinism"), bDeterminism);
|
||||
Existing->SetBoolField(TEXT("brick_path_matches_scalar_bit_exact"),
|
||||
bParameterizedBrickScalarParity);
|
||||
Existing->SetNumberField(TEXT("brick_scalar_parity_samples"),
|
||||
BrickParitySize.X * BrickParitySize.Y * BrickParitySize.Z);
|
||||
Existing->SetNumberField(TEXT("brick_scalar_parity_mismatches"),
|
||||
static_cast<double>(BrickScalarMismatchCount));
|
||||
Existing->SetStringField(TEXT("six_worker_hash"), FString::Printf(
|
||||
TEXT("%016llx"), static_cast<unsigned long long>(HardestHash)));
|
||||
Existing->SetStringField(TEXT("repeat_six_worker_hash"), FString::Printf(
|
||||
@@ -8896,17 +9252,17 @@ FString BuildManifestJson(
|
||||
WriteJsonVector(*Writer, TEXT("render_camera_voxels"), Arguments.RenderCamera, 1.0f);
|
||||
}
|
||||
WriteJsonIntVector(*Writer, TEXT("region_origin_voxels"), Export.RegionOrigin);
|
||||
WriteJsonBounds(*Writer, TEXT("region_bounds_voxels"), Export.RegionOrigin, Export.RegionSize, 0.25f);
|
||||
WriteJsonBounds(*Writer, TEXT("region_bounds_voxels"), Export.RegionOrigin, Export.RegionSize, VOXEL_SIZE / 100.0f);
|
||||
Writer->WriteObjectStart(TEXT("region_bounds_metres"));
|
||||
Writer->WriteObjectStart(TEXT("min"));
|
||||
Writer->WriteValue(TEXT("x"), static_cast<double>(Export.RegionOrigin.X) * 0.25);
|
||||
Writer->WriteValue(TEXT("y"), static_cast<double>(Export.RegionOrigin.Y) * 0.25);
|
||||
Writer->WriteValue(TEXT("z"), static_cast<double>(Export.RegionOrigin.Z) * 0.25);
|
||||
Writer->WriteValue(TEXT("x"), static_cast<double>(Export.RegionOrigin.X) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("y"), static_cast<double>(Export.RegionOrigin.Y) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("z"), static_cast<double>(Export.RegionOrigin.Z) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteObjectEnd();
|
||||
Writer->WriteObjectStart(TEXT("max_exclusive"));
|
||||
Writer->WriteValue(TEXT("x"), static_cast<double>(Export.RegionOrigin.X + Export.RegionSize) * 0.25);
|
||||
Writer->WriteValue(TEXT("y"), static_cast<double>(Export.RegionOrigin.Y + Export.RegionSize) * 0.25);
|
||||
Writer->WriteValue(TEXT("z"), static_cast<double>(Export.RegionOrigin.Z + Export.RegionSize) * 0.25);
|
||||
Writer->WriteValue(TEXT("x"), static_cast<double>(Export.RegionOrigin.X + Export.RegionSize) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("y"), static_cast<double>(Export.RegionOrigin.Y + Export.RegionSize) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("z"), static_cast<double>(Export.RegionOrigin.Z + Export.RegionSize) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteObjectEnd();
|
||||
Writer->WriteValue(TEXT("units"), TEXT("metres"));
|
||||
Writer->WriteObjectEnd();
|
||||
@@ -10114,11 +10470,11 @@ bool RunTunnelCoreProbe(
|
||||
"measured=%.6g_voxels/%d"),
|
||||
*Axis->Name, SampleCount, Axis->ValidFinalCrossings,
|
||||
Axis->FinalPeriodicAmplitudeVoxels,
|
||||
Axis->FinalPeriodicAmplitudeVoxels * 25.0f,
|
||||
Axis->FinalPeriodicAmplitudeVoxels * VOXEL_SIZE,
|
||||
Axis->FinalPeriodicPeriodVoxels,
|
||||
Axis->FinalPeriodicMeasuredLengthVoxels, Axis->FinalPeriodicMeasuredSamples,
|
||||
Axis->ValidCoreCrossings, Axis->CorePeriodicAmplitudeVoxels,
|
||||
Axis->CorePeriodicAmplitudeVoxels * 25.0f,
|
||||
Axis->CorePeriodicAmplitudeVoxels * VOXEL_SIZE,
|
||||
Axis->CorePeriodicPeriodVoxels,
|
||||
Axis->CorePeriodicMeasuredLengthVoxels, Axis->CorePeriodicMeasuredSamples);
|
||||
}
|
||||
@@ -10409,11 +10765,11 @@ bool RunTunnelCoreProbe(
|
||||
Mouth.CoreBottomSampleCount, Mouth.FinalSolidSampleCount,
|
||||
Mouth.CoreInducedSolidSampleCount,
|
||||
Mouth.MaxWallPeriodicAmplitudeVoxels,
|
||||
Mouth.MaxWallPeriodicAmplitudeVoxels * 25.0f,
|
||||
Mouth.MaxWallPeriodicAmplitudeVoxels * VOXEL_SIZE,
|
||||
Mouth.MaxFloorPeriodicAmplitudeVoxels,
|
||||
Mouth.MaxFloorPeriodicAmplitudeVoxels * 25.0f,
|
||||
Mouth.MaxFloorPeriodicAmplitudeVoxels * VOXEL_SIZE,
|
||||
Mouth.MaxLocalMedianFloorPeriodicAmplitudeVoxels,
|
||||
Mouth.MaxLocalMedianFloorPeriodicAmplitudeVoxels * 25.0f,
|
||||
Mouth.MaxLocalMedianFloorPeriodicAmplitudeVoxels * VOXEL_SIZE,
|
||||
Mouth.LateralWindowVoxels, Mouth.LateralStepVoxels, *MouthPath);
|
||||
}
|
||||
|
||||
@@ -10459,12 +10815,12 @@ void WriteTunnelCoreProbeAxis(
|
||||
Writer.WriteValue(TEXT("final_min_crossing_voxels"), static_cast<double>(Axis.FinalMinCrossingVoxels));
|
||||
Writer.WriteValue(TEXT("final_max_crossing_voxels"), static_cast<double>(Axis.FinalMaxCrossingVoxels));
|
||||
Writer.WriteValue(TEXT("core_periodic_amplitude_voxels"), static_cast<double>(Axis.CorePeriodicAmplitudeVoxels));
|
||||
Writer.WriteValue(TEXT("core_periodic_amplitude_cm"), static_cast<double>(Axis.CorePeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer.WriteValue(TEXT("core_periodic_amplitude_cm"), static_cast<double>(Axis.CorePeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer.WriteValue(TEXT("core_periodic_period_voxels"), static_cast<double>(Axis.CorePeriodicPeriodVoxels));
|
||||
Writer.WriteValue(TEXT("core_periodic_measured_samples"), Axis.CorePeriodicMeasuredSamples);
|
||||
Writer.WriteValue(TEXT("core_periodic_measured_length_voxels"), static_cast<double>(Axis.CorePeriodicMeasuredLengthVoxels));
|
||||
Writer.WriteValue(TEXT("final_periodic_amplitude_voxels"), static_cast<double>(Axis.FinalPeriodicAmplitudeVoxels));
|
||||
Writer.WriteValue(TEXT("final_periodic_amplitude_cm"), static_cast<double>(Axis.FinalPeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer.WriteValue(TEXT("final_periodic_amplitude_cm"), static_cast<double>(Axis.FinalPeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer.WriteValue(TEXT("final_periodic_period_voxels"), static_cast<double>(Axis.FinalPeriodicPeriodVoxels));
|
||||
Writer.WriteValue(TEXT("final_periodic_measured_samples"), Axis.FinalPeriodicMeasuredSamples);
|
||||
Writer.WriteValue(TEXT("final_periodic_measured_length_voxels"), static_cast<double>(Axis.FinalPeriodicMeasuredLengthVoxels));
|
||||
@@ -10482,12 +10838,12 @@ void WriteTunnelMouthProbeAxis(
|
||||
Writer.WriteValue(TEXT("min_crossing_voxels"), static_cast<double>(Axis.MinCrossingVoxels));
|
||||
Writer.WriteValue(TEXT("max_crossing_voxels"), static_cast<double>(Axis.MaxCrossingVoxels));
|
||||
Writer.WriteValue(TEXT("periodic_amplitude_voxels"), static_cast<double>(Axis.PeriodicAmplitudeVoxels));
|
||||
Writer.WriteValue(TEXT("periodic_amplitude_cm"), static_cast<double>(Axis.PeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer.WriteValue(TEXT("periodic_amplitude_cm"), static_cast<double>(Axis.PeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer.WriteValue(TEXT("periodic_period_voxels"), static_cast<double>(Axis.PeriodicPeriodVoxels));
|
||||
Writer.WriteValue(TEXT("periodic_measured_samples"), Axis.PeriodicMeasuredSamples);
|
||||
Writer.WriteValue(TEXT("periodic_measured_length_voxels"), static_cast<double>(Axis.PeriodicMeasuredLengthVoxels));
|
||||
Writer.WriteValue(TEXT("local_median_periodic_amplitude_voxels"), static_cast<double>(Axis.LocalMedianPeriodicAmplitudeVoxels));
|
||||
Writer.WriteValue(TEXT("local_median_periodic_amplitude_cm"), static_cast<double>(Axis.LocalMedianPeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer.WriteValue(TEXT("local_median_periodic_amplitude_cm"), static_cast<double>(Axis.LocalMedianPeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer.WriteValue(TEXT("local_median_periodic_period_voxels"), static_cast<double>(Axis.LocalMedianPeriodicPeriodVoxels));
|
||||
Writer.WriteObjectEnd();
|
||||
}
|
||||
@@ -10676,18 +11032,18 @@ FString BuildExploreJson(
|
||||
Writer->WriteValue(TEXT("final_solid_sample_count"), Output.TunnelCoreProbe.Mouth.FinalSolidSampleCount);
|
||||
Writer->WriteValue(TEXT("core_induced_solid_sample_count"), Output.TunnelCoreProbe.Mouth.CoreInducedSolidSampleCount);
|
||||
Writer->WriteValue(TEXT("max_wall_periodic_amplitude_voxels"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxWallPeriodicAmplitudeVoxels));
|
||||
Writer->WriteValue(TEXT("max_wall_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxWallPeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer->WriteValue(TEXT("max_wall_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxWallPeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer->WriteValue(TEXT("max_floor_periodic_amplitude_voxels"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxFloorPeriodicAmplitudeVoxels));
|
||||
Writer->WriteValue(TEXT("max_floor_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxFloorPeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer->WriteValue(TEXT("max_floor_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxFloorPeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer->WriteValue(TEXT("max_local_median_wall_periodic_amplitude_voxels"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxLocalMedianWallPeriodicAmplitudeVoxels));
|
||||
Writer->WriteValue(TEXT("max_local_median_wall_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxLocalMedianWallPeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer->WriteValue(TEXT("max_local_median_wall_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxLocalMedianWallPeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer->WriteValue(TEXT("max_local_median_floor_periodic_amplitude_voxels"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxLocalMedianFloorPeriodicAmplitudeVoxels));
|
||||
Writer->WriteValue(TEXT("max_local_median_floor_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxLocalMedianFloorPeriodicAmplitudeVoxels) * 25.0);
|
||||
Writer->WriteValue(TEXT("max_local_median_floor_periodic_amplitude_cm"), static_cast<double>(Output.TunnelCoreProbe.Mouth.MaxLocalMedianFloorPeriodicAmplitudeVoxels) * VOXEL_SIZE);
|
||||
Writer->WriteValue(TEXT("mouth_periodic_detrend"), TEXT("degree-six smooth trend over the complete longest contiguous run; legacy local-median retained for audit"));
|
||||
Writer->WriteValue(TEXT("periodic_acceptance_cm"), 2.0);
|
||||
Writer->WriteValue(TEXT("periodic_acceptance_pass"),
|
||||
Output.TunnelCoreProbe.Mouth.MaxWallPeriodicAmplitudeVoxels * 25.0f <= 2.0f
|
||||
&& Output.TunnelCoreProbe.Mouth.MaxFloorPeriodicAmplitudeVoxels * 25.0f <= 2.0f);
|
||||
Output.TunnelCoreProbe.Mouth.MaxWallPeriodicAmplitudeVoxels * VOXEL_SIZE <= 2.0f
|
||||
&& Output.TunnelCoreProbe.Mouth.MaxFloorPeriodicAmplitudeVoxels * VOXEL_SIZE <= 2.0f);
|
||||
Writer->WriteArrayStart(TEXT("endpoints"));
|
||||
for (const FExploreTunnelMouthProbeEndpoint& Endpoint : Output.TunnelCoreProbe.Mouth.Endpoints)
|
||||
{
|
||||
@@ -10862,15 +11218,15 @@ FString BuildExploreJson(
|
||||
Writer->WriteObjectEnd();
|
||||
|
||||
Writer->WriteObjectStart(TEXT("world"));
|
||||
Writer->WriteValue(TEXT("voxel_size_m"), 0.25);
|
||||
Writer->WriteValue(TEXT("voxel_size_m"), VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("world_radius_voxels"), 0);
|
||||
Writer->WriteValue(TEXT("lateral_regions_enabled"), false);
|
||||
Writer->WriteValue(TEXT("diff_layer_mutated"), false);
|
||||
Writer->WriteValue(TEXT("target_strate_slot"), Arguments.Slot);
|
||||
Writer->WriteValue(TEXT("target_bottom_voxel_z"), World.TargetBottomWorldZ);
|
||||
Writer->WriteValue(TEXT("target_top_voxel_z_exclusive"), World.TargetTopWorldZ);
|
||||
Writer->WriteValue(TEXT("target_bottom_m"), static_cast<double>(World.TargetBottomWorldZ) * 0.25);
|
||||
Writer->WriteValue(TEXT("target_top_m_exclusive"), static_cast<double>(World.TargetTopWorldZ) * 0.25);
|
||||
Writer->WriteValue(TEXT("target_bottom_m"), static_cast<double>(World.TargetBottomWorldZ) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("target_top_m_exclusive"), static_cast<double>(World.TargetTopWorldZ) * VOXEL_SIZE / 100.0);
|
||||
Writer->WriteValue(TEXT("target_boundary_seal_thickness_voxels"),
|
||||
static_cast<double>(World.TargetBoundarySealThickness));
|
||||
WritePlayerDimensions(*Writer, TEXT("player_dimensions"));
|
||||
@@ -10977,12 +11333,12 @@ FString BuildExploreJson(
|
||||
if (Output.Walk.bHasArrival)
|
||||
{
|
||||
WriteJsonVector(*Writer, TEXT("arrival_mouth_voxels"), Output.Walk.ArrivalVoxels, 1.0f);
|
||||
WriteJsonVector(*Writer, TEXT("arrival_mouth_metres"), Output.Walk.ArrivalVoxels, 0.25f);
|
||||
WriteJsonVector(*Writer, TEXT("arrival_mouth_metres"), Output.Walk.ArrivalVoxels, VOXEL_SIZE / 100.0f);
|
||||
}
|
||||
if (Output.Walk.bHasDeparture)
|
||||
{
|
||||
WriteJsonVector(*Writer, TEXT("departure_mouth_voxels"), Output.Walk.DepartureVoxels, 1.0f);
|
||||
WriteJsonVector(*Writer, TEXT("departure_mouth_metres"), Output.Walk.DepartureVoxels, 0.25f);
|
||||
WriteJsonVector(*Writer, TEXT("departure_mouth_metres"), Output.Walk.DepartureVoxels, VOXEL_SIZE / 100.0f);
|
||||
}
|
||||
Writer->WriteValue(TEXT("connectivity_result"), ConnectivityResultName(Report.Result));
|
||||
Writer->WriteValue(TEXT("connectivity_result_code"), static_cast<int32>(Report.Result));
|
||||
@@ -11042,13 +11398,13 @@ FString BuildExploreJson(
|
||||
if (Report.bHasAgentFinalPosition)
|
||||
{
|
||||
WriteJsonVector(*Writer, TEXT("agent_final_position_voxels"), Report.AgentFinalVoxels, 1.0f);
|
||||
WriteJsonVector(*Writer, TEXT("agent_final_position_metres"), Report.AgentFinalVoxels, 0.25f);
|
||||
WriteJsonVector(*Writer, TEXT("agent_final_position_metres"), Report.AgentFinalVoxels, VOXEL_SIZE / 100.0f);
|
||||
}
|
||||
Writer->WriteValue(TEXT("last_reached_position_available"), Report.bHasLastReachedPosition);
|
||||
if (Report.bHasLastReachedPosition)
|
||||
{
|
||||
WriteJsonVector(*Writer, TEXT("last_reached_position_voxels"), Report.LastReachedVoxels, 1.0f);
|
||||
WriteJsonVector(*Writer, TEXT("last_reached_position_metres"), Report.LastReachedVoxels, 0.25f);
|
||||
WriteJsonVector(*Writer, TEXT("last_reached_position_metres"), Report.LastReachedVoxels, VOXEL_SIZE / 100.0f);
|
||||
}
|
||||
Writer->WriteValue(TEXT("target_component_nearest_cell_available"), Report.bHasTargetComponentNearestCell);
|
||||
if (Report.bHasTargetComponentNearestCell)
|
||||
@@ -11056,7 +11412,7 @@ FString BuildExploreJson(
|
||||
WriteJsonVector(*Writer, TEXT("target_component_nearest_cell_voxels"),
|
||||
Report.TargetComponentNearestVoxels, 1.0f);
|
||||
WriteJsonVector(*Writer, TEXT("target_component_nearest_cell_metres"),
|
||||
Report.TargetComponentNearestVoxels, 0.25f);
|
||||
Report.TargetComponentNearestVoxels, VOXEL_SIZE / 100.0f);
|
||||
}
|
||||
Writer->WriteValue(TEXT("agent_to_target_component_gap_voxels"),
|
||||
static_cast<double>(Report.AgentToTargetComponentGapVoxels));
|
||||
@@ -11148,7 +11504,7 @@ FString BuildExploreJson(
|
||||
Writer->WriteValue(TEXT("mesh_file"), Output.Export.MeshFileName);
|
||||
Writer->WriteValue(TEXT("manifest_file"), Output.Export.ManifestFileName);
|
||||
WriteJsonIntVector(*Writer, TEXT("region_origin_voxels"), Output.Export.RegionOrigin);
|
||||
WriteJsonBounds(*Writer, TEXT("region_bounds_voxels"), Output.Export.RegionOrigin, Output.Export.RegionSize, 0.25f);
|
||||
WriteJsonBounds(*Writer, TEXT("region_bounds_voxels"), Output.Export.RegionOrigin, Output.Export.RegionSize, VOXEL_SIZE / 100.0f);
|
||||
Writer->WriteValue(TEXT("region_size_cells_per_axis"), Output.Export.RegionSize);
|
||||
Writer->WriteValue(TEXT("canonical_mesher_tile_cells"), CHUNK_SIZE);
|
||||
Writer->WriteValue(TEXT("canonical_mesher_tile_count"), Output.Export.MesherTileCount);
|
||||
@@ -12965,6 +13321,10 @@ int32 UVoxelForgeExploreCommandlet::Main(const FString& Params)
|
||||
{
|
||||
return RunStep2f(Params);
|
||||
}
|
||||
if (FParse::Param(*Params, TEXT("step3scale")))
|
||||
{
|
||||
return RunStep3ScaleBenchmark(Params);
|
||||
}
|
||||
if (FParse::Param(*Params, TEXT("step2e")))
|
||||
{
|
||||
return RunStep2e(Params);
|
||||
|
||||
Reference in new issue
Block a user