wip(assembler): M1 repair round -- raised block and cliff fixed; native 7x faster than legacy
Luna, M1 repair round: the rectangular raised block and the broken cliff shared one cause, a type-2 solid AABB in the generated plan; it is now a tapered, terrain-following shelf, and a negative-control audit catches the old box behaviour; seam classification check passes. Bound audit 298 boxes / 8,046 samples, 0 misses. Evaluator and 120-tile density/mesh/payload/ topology hashes identical at W1/W8/W16. Cave regression: walkability 5,642/5,642, 64/64 tiles. Legacy mismatch unchanged (0 biome mismatches, 18.14% signs). Speed (matched workloads): 120-tile full detail 0.089 s native vs 0.625 s legacy; 529-tile clipmap 3.858 s vs 11.687 s -- 2.29 s above the ~1.57 s aim; LOD8 dominates (165 unknown tiles, 13.27 M field calls, 10.88 M column-cache misses). My capture review: coast matches legacy closely; surface clean but a dark flat slab on the far horizon; cliff shelf renders as a stack of thin plates with back faces showing (sub-voxel shelf thickness suspected). 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
fcb16fd265
commit
2c20f9eaea
61 files changed
+4308
-165
No files matched your search
@@ -33,6 +33,21 @@ class FStandaloneShapeWorld
|
||||
{
|
||||
public:
|
||||
enum class EDetailVariant : uint8 { Coherent, Smooth, PerVoxel };
|
||||
struct FBoxClassification
|
||||
{
|
||||
EVoxelTileClass Verdict=EVoxelTileClass::Mixed;
|
||||
bool bNativeSurface=false;
|
||||
bool bUnknown=false;
|
||||
};
|
||||
struct FClassificationThreadStats
|
||||
{
|
||||
uint64 SolidBoxes=0,AirBoxes=0,MixedBoxes=0,UnknownBoxes=0;
|
||||
uint64 NativeFloatFieldCalls=0,NativeLatticeFieldCalls=0,NativeUnclampedFieldCalls=0;
|
||||
double Milliseconds=0.0;
|
||||
};
|
||||
static void ResetThreadClassificationStats() { ThreadClassificationStats()={}; }
|
||||
static FClassificationThreadStats GetThreadClassificationStats()
|
||||
{ return ThreadClassificationStats(); }
|
||||
struct FFarConnectorSegment
|
||||
{
|
||||
FVector Start=FVector::ZeroVector;
|
||||
@@ -923,7 +938,10 @@ public:
|
||||
{
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeFloatFieldCalls;
|
||||
return ApplyEditBrushes(NativeDensity,X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
return LegacySurfaceDensityAt(X,Y,Z);
|
||||
int32 IX=0,IY=0,IZ=0;
|
||||
@@ -939,7 +957,10 @@ public:
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeLatticeFieldCalls;
|
||||
return ApplyEditBrushes(NativeDensity,X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z)))
|
||||
return LegacySurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
@@ -956,7 +977,10 @@ public:
|
||||
{
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeUnclampedFieldCalls;
|
||||
return ApplyEditBrushes(NativeDensity,X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
return LegacySurfaceDensityAt(X,Y,Z);
|
||||
return AnalyticDensityAt(X,Y,Z,false);
|
||||
@@ -1130,12 +1154,17 @@ private:
|
||||
|
||||
public:
|
||||
EVoxelTileClass ClassifyBox(const FIntVector& Origin,int32 Step,int32 Cells) const
|
||||
{ return ClassifyBoxDetailed(Origin,Step,Cells).Verdict; }
|
||||
|
||||
FBoxClassification ClassifyBoxDetailed(const FIntVector& Origin,int32 Step,int32 Cells) const
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
const auto Start=Clock::now();
|
||||
const int32 Pad=std::max(Step,1);
|
||||
int32 BMin[3]={Origin.X-Pad,Origin.Y-Pad,Origin.Z-Pad};
|
||||
int32 BMax[3]={Origin.X+(Cells+1)*Step,Origin.Y+(Cells+1)*Step,Origin.Z+(Cells+1)*Step};
|
||||
const VoxelForgeCore::WorldAssemblyStratumPlanV1* SurfacePlan=nullptr;
|
||||
bool bSurfaceOverlap=false,bOtherStrateOverlap=false;
|
||||
bool bSurfaceOverlap=false,bOtherStrateOverlap=false,bBadPlan=false;
|
||||
if(Owner&&Owner->Manager)
|
||||
{
|
||||
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
|
||||
@@ -1152,19 +1181,31 @@ public:
|
||||
static_cast<float>((static_cast<double>(ChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE));
|
||||
const auto* Candidate=FindWorldAssemblyStratum(StrateIndex,ChunkZ);
|
||||
if(!Candidate||(SurfacePlan&&SurfacePlan!=Candidate))
|
||||
return EVoxelTileClass::Mixed;
|
||||
bBadPlan=true;
|
||||
SurfacePlan=Candidate;
|
||||
}
|
||||
else bOtherStrateOverlap=true;
|
||||
}
|
||||
}
|
||||
const auto Finish=[&](EVoxelTileClass Verdict,bool bUnknown=false)
|
||||
{
|
||||
FBoxClassification Result{Verdict,bSurfaceOverlap&&!bOtherStrateOverlap,bUnknown};
|
||||
auto& Counts=ThreadClassificationStats();
|
||||
Counts.Milliseconds+=std::chrono::duration<double,std::milli>(Clock::now()-Start).count();
|
||||
if(!Result.bNativeSurface||bUnknown)++Counts.UnknownBoxes;
|
||||
else if(Verdict==EVoxelTileClass::AllSolid)++Counts.SolidBoxes;
|
||||
else if(Verdict==EVoxelTileClass::AllAir)++Counts.AirBoxes;
|
||||
else ++Counts.MixedBoxes;
|
||||
return Result;
|
||||
};
|
||||
// A box crossing recipes cannot use one field interval; unknown composition stays Mixed.
|
||||
// Une boite qui traverse plusieurs recettes reste Mixed, car l'intervalle d'un seul champ ne suffit pas.
|
||||
if(bSurfaceOverlap&&bOtherStrateOverlap)return EVoxelTileClass::Mixed;
|
||||
if(bBadPlan|| (bSurfaceOverlap&&bOtherStrateOverlap))
|
||||
return Finish(EVoxelTileClass::Mixed,true);
|
||||
if(!EditBrushes.empty()&&EditBoundsMin.X<=BMax[0]&&EditBoundsMax.X>=BMin[0]
|
||||
&&EditBoundsMin.Y<=BMax[1]&&EditBoundsMax.Y>=BMin[1]
|
||||
&&EditBoundsMin.Z<=BMax[2]&&EditBoundsMax.Z>=BMin[2])
|
||||
return EVoxelTileClass::Mixed;
|
||||
return Finish(EVoxelTileClass::Mixed,true);
|
||||
for(int32 BZ=FloorDiv(BMin[2],ActiveSpatialBinSize);BZ<=FloorDiv(BMax[2],ActiveSpatialBinSize);++BZ)
|
||||
for(int32 BY=FloorDiv(BMin[1],ActiveSpatialBinSize);BY<=FloorDiv(BMax[1],ActiveSpatialBinSize);++BY)
|
||||
for(int32 BX=FloorDiv(BMin[0],ActiveSpatialBinSize);BX<=FloorDiv(BMax[0],ActiveSpatialBinSize);++BX)
|
||||
@@ -1175,32 +1216,39 @@ public:
|
||||
const FPrimitive& P=Primitives[Id];bool Overlap=true;
|
||||
for(int32 A=0;A<3;++A)
|
||||
Overlap &= P.Max[A]+DetailBand>=BMin[A]&&P.Min[A]-DetailBand<=BMax[A];
|
||||
if(Overlap)return EVoxelTileClass::Mixed;
|
||||
if(Overlap)return Finish(EVoxelTileClass::Mixed);
|
||||
}
|
||||
}
|
||||
for(const FInterval& R:LayerRanges)
|
||||
if(R.Lo<=BMax[2]&&R.Hi>=BMin[2]
|
||||
&&(R.Lo>=BMin[2]||R.Hi<=BMax[2]))
|
||||
return EVoxelTileClass::Mixed;
|
||||
return Finish(EVoxelTileClass::Mixed);
|
||||
if(bSurfaceOverlap)
|
||||
{
|
||||
if(!WorldAssembly||!SurfacePlan)return EVoxelTileClass::Mixed;
|
||||
if(!WorldAssembly||!SurfacePlan)return Finish(EVoxelTileClass::Mixed,true);
|
||||
const VoxelForgeCore::Heightfield2D Block(WorldAssembly->recipe,*SurfacePlan);
|
||||
const auto Bounds=Block.interval(
|
||||
const auto Verdict=Block.classifyLatticeBox(
|
||||
static_cast<int64>(BMin[0])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
|
||||
static_cast<int64>(BMin[1])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
|
||||
static_cast<int64>(BMin[2])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
|
||||
static_cast<int64>(BMax[0])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
|
||||
static_cast<int64>(BMax[1])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
|
||||
static_cast<int64>(BMax[2])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||
if(!Bounds.known)return EVoxelTileClass::Mixed;
|
||||
if(Bounds.minimumDensitySubvoxels>0)return EVoxelTileClass::AllAir;
|
||||
if(Bounds.maximumDensitySubvoxels<0)return EVoxelTileClass::AllSolid;
|
||||
return EVoxelTileClass::Mixed;
|
||||
static_cast<int64>(BMax[2])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
|
||||
std::max(Step,1));
|
||||
switch(Verdict)
|
||||
{
|
||||
case VoxelForgeCore::HeightfieldBoxClass::allAir:
|
||||
return Finish(EVoxelTileClass::AllAir);
|
||||
case VoxelForgeCore::HeightfieldBoxClass::allSolid:
|
||||
return Finish(EVoxelTileClass::AllSolid);
|
||||
case VoxelForgeCore::HeightfieldBoxClass::mixed:
|
||||
return Finish(EVoxelTileClass::Mixed);
|
||||
default:return Finish(EVoxelTileClass::Mixed,true);
|
||||
}
|
||||
}
|
||||
const bool bRock=EvaluateFast((BMin[0]+BMax[0])*0.5,
|
||||
(BMin[1]+BMax[1])*0.5,(BMin[2]+BMax[2])*0.5);
|
||||
return bRock?EVoxelTileClass::AllSolid:EVoxelTileClass::AllAir;
|
||||
return Finish(bRock?EVoxelTileClass::AllSolid:EVoxelTileClass::AllAir);
|
||||
}
|
||||
|
||||
bool IsRock(int32 X,int32 Y,int32 Z) const
|
||||
@@ -1662,6 +1710,12 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static FClassificationThreadStats& ThreadClassificationStats()
|
||||
{
|
||||
static thread_local FClassificationThreadStats Stats;
|
||||
return Stats;
|
||||
}
|
||||
|
||||
const VoxelForgeCore::WorldAssemblyStratumPlanV1* FindWorldAssemblyStratum(
|
||||
int32 StrateIndex,int32 ChunkZ) const
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user