wip(standalone): owner LOD0 defects -- skirt curtains clipped, exact edge roots; interrupted (OpenAI capacity)

Not verified as a whole. In the tree when Luna's session ended ("model at capacity"):
- fins: LOD seam skirts could hang into tunnel air; skirt triangles are now clipped against the solid
  half-space and carry a per-face mask so a host can hide skirts between same-LOD neighbours.
- choppy LOD0 stairs: marching cubes' linear edge interpolation misplaced vertices where the relief
  bends within one cell; edge crossings corrected with the exact field (82 patches, midpoint-edge
  errors 18,818 -> 3,288); normal halo now ignores the +-4.125 fallback samples.
- an explicit unclamped Core distance query for audits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-06 00:17:14 +02:00
1 parent 08ceed200d
commit b3af0e589e
7 files changed
+1304 -62

No files matched your search

+91 -35
View File
@@ -313,7 +313,7 @@ public:
const size_t NZ=static_cast<size_t>(Size[2]);
WordsPerZ=(NZ+63u)/64u;
RockWords.assign(static_cast<size_t>(Size[0])*Size[1]*WordsPerZ,0);
SurfaceDistanceQ=std::make_unique_for_overwrite<int8[]>(static_cast<size_t>(NodeCount));
SurfaceDistanceQ=std::make_unique_for_overwrite<int16[]>(static_cast<size_t>(NodeCount));
BuildPackedRockIntervals(Stats.RockIntervalLines);
BuildCandidateBands(Stats.CandidateAxisLines,Stats.CandidateMergeLines,
Stats.CandidateMergeSeconds);
@@ -348,7 +348,7 @@ public:
Stats.DetailBandLines.WorkerSeconds*1000.0);
std::printf("[ShapeAllocation] words=%.2fMiB candidate_axis_words=%.2fMiB proxy=%.2fMiB primitives=%.2fMiB spatial_bins=%llu spatial_bin_refs=%llu spatial_bin_capacity=%llu inline_bins=%llu overflow_bins=%llu far_primitive_build=%.3fms far_bin_rebuild=%.3fms\n",
static_cast<double>(WordBytes)/1048576.0,static_cast<double>(CandidateAxisBytes)/1048576.0,
static_cast<double>(Stats.SignNodes*sizeof(int8))/1048576.0,
static_cast<double>(Stats.SignNodes*sizeof(int16))/1048576.0,
static_cast<double>(Primitives.capacity()*sizeof(FPrimitive))/1048576.0,
static_cast<unsigned long long>(SpatialBins.size()),
static_cast<unsigned long long>(BinReferences),
@@ -364,7 +364,7 @@ public:
static_cast<unsigned long long>(Stats.SignNodes),
static_cast<double>(WordBytes)/1048576.0,
static_cast<unsigned long long>(Stats.SurfaceProxyNodes),
static_cast<double>(Stats.SignNodes*sizeof(int8))/1048576.0,WorkerCount);
static_cast<double>(Stats.SignNodes*sizeof(int16))/1048576.0,WorkerCount);
std::printf("[ShapeStage] local-shapes=%.3f ms intervals+signs=%.3f ms surface-band=%.3f ms far-parents=%.3f ms total=%.3f ms candidates=%llu flips=%llu walk=%llu/%llu\n",
Stats.ShapeSeconds*1000.0,Stats.IntervalSeconds*1000.0,Stats.SurfaceSeconds*1000.0,Stats.FarShapeSeconds*1000.0,
std::chrono::duration<double>(Clock::now()-TotalStart).count()*1000.0,
@@ -539,6 +539,24 @@ public:
static_cast<float>(Z));
}
float DensityAtUnclamped(float X,float Y,float Z) const
{
return AnalyticDensityAt(X,Y,Z,false);
}
VoxelForgeCore::DetailFieldSample DetailSampleAt(float X,float Y,float Z) const
{
VoxelForgeCore::DetailFieldSample Sample;
AnalyticDensityAt(X,Y,Z,false,&Sample.displacement,
&Sample.caveInfluence,&Sample.floorInfluence);
return Sample;
}
bool IsProxyBandFallback(float Density) const
{
return std::abs(std::abs(Density)-(DetailSupremum+0.125f))<1.0e-4f;
}
bool IsAnalyticOnly() const { return bAnalyticOnly; }
void DensityAtLatticeX8(int32 XStart,int32 XStep,int32 Y,int32 Z,
@@ -578,11 +596,11 @@ public:
float Density;
if(CandidateWords[Word]&Mask)
{
const int8 Proxy=SurfaceDistanceQ[NodeBase
const int16 Proxy=SurfaceDistanceQ[NodeBase
+static_cast<size_t>(Lane*XStep)];
Density=static_cast<float>(Proxy)*(1.0f/16.0f);
Density=static_cast<float>(Proxy)*(1.0f/256.0f);
if((Density<0.0f)!=bRock)
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/16.0f);
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/256.0f);
}
else
Density=bRock?-ProxyBandEdge:ProxyBandEdge;
@@ -607,10 +625,10 @@ private:
if(CandidateWords[Word]&Mask)
{
const size_t Node=Zi*static_cast<size_t>(Size[1])*Size[0]+Column;
const int8 Proxy=SurfaceDistanceQ[Node];
float Density=static_cast<float>(Proxy)*(1.0f/16.0f);
const int16 Proxy=SurfaceDistanceQ[Node];
float Density=static_cast<float>(Proxy)*(1.0f/256.0f);
if((Density<0.0f)!=bRock)
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/16.0f);
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/256.0f);
return ApplyEditBrushes(Density,FX,FY,FZ);
}
// Match the fixed fallback to the edge of the stored proxy band. The
@@ -620,8 +638,14 @@ private:
return ApplyEditBrushes(bRock?-ProxyBandEdge:ProxyBandEdge,FX,FY,FZ);
}
float AnalyticDensityAt(float X,float Y,float Z) const
float AnalyticDensityAt(float X,float Y,float Z,bool bClampNearZero=true,
float* OutDetailDisplacement=nullptr,
float* OutCaveInfluence=nullptr,
float* OutFloorInfluence=nullptr) const
{
if(OutDetailDisplacement)*OutDetailDisplacement=0.0f;
if(OutCaveInfluence)*OutCaveInfluence=0.0f;
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
const bool bInsideFine=X>=Min[0]&&X<=Max[0]&&Y>=Min[1]&&Y<=Max[1]
&&Z>=Min[2]&&Z<=Max[2];
if(!bInsideFine)
@@ -631,8 +655,9 @@ private:
if(bCriticalAir)RockDistance=std::min(RockDistance,-1.0f/16.0f);
const bool bRock=RockDistance>=0.0f;
float Density=-RockDistance;
if((Density<0.0f)!=bRock||std::abs(Density)<0.05f)
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),0.05f);
if((Density<0.0f)!=bRock||(bClampNearZero&&std::abs(Density)<0.05f))
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),
bClampNearZero?0.05f:1.0e-7f);
return ApplyEditBrushes(Density,X,Y,Z);
}
ESurfaceFamily SurfaceFamily=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
@@ -641,19 +666,27 @@ private:
float RockDistance=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,
&bFloorSurface,&CaveInfluence,&FloorInfluence,&bCriticalAir,nullptr,false,
&PassageInfluence);
if(OutCaveInfluence)*OutCaveInfluence=CaveInfluence;
if(OutFloorInfluence)*OutFloorInfluence=FloorInfluence;
if(bInsideFine&&DetailVariant!=EDetailVariant::Smooth
&&std::abs(RockDistance)<=DetailSupremum+0.125f)
{
const float Fade=DetailBandFadeAt(X,Y,Z,RockDistance,SurfaceSDF,
CaveInfluence,FloorInfluence);
if(Fade>0.0f)RockDistance+=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,
FloorInfluence,PassageInfluence)*Fade;
if(Fade>0.0f)
{
const float Detail=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,
FloorInfluence,PassageInfluence)*Fade;
RockDistance+=Detail;
if(OutDetailDisplacement)*OutDetailDisplacement=Detail;
}
}
if(bCriticalAir)RockDistance=std::min(RockDistance,-1.0f/16.0f);
const bool bRock=RockDistance>=0.0f;
float Density=-RockDistance;
if((Density<0.0f)!=bRock||std::abs(Density)<0.05f)
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),0.05f);
if((Density<0.0f)!=bRock||(bClampNearZero&&std::abs(Density)<0.05f))
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),
bClampNearZero?0.05f:1.0e-7f);
return ApplyEditBrushes(Density,X,Y,Z);
}
@@ -923,7 +956,9 @@ public:
const double OX=CameraX*4.0,OY=CameraY*4.0,OZ=CameraZ*4.0;
auto Distance=[&](double X,double Y,double Z,ESurfaceFamily* OutFamily=nullptr,
float* OutRaw=nullptr,float* OutDetail=nullptr,
bool* OutFloorSurface=nullptr,float* OutPassageInfluence=nullptr)
bool* OutFloorSurface=nullptr,float* OutPassageInfluence=nullptr,
float* OutCaveInfluence=nullptr,float* OutFloorInfluence=nullptr,
float* OutSurfaceSDF=nullptr)
{
ESurfaceFamily Family=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
@@ -948,6 +983,9 @@ public:
if(OutDetail)*OutDetail=Detail;
if(OutFloorSurface)*OutFloorSurface=bFloorSurface;
if(OutPassageInfluence)*OutPassageInfluence=PassageInfluence;
if(OutCaveInfluence)*OutCaveInfluence=CaveInfluence;
if(OutFloorInfluence)*OutFloorInfluence=FloorInfluence;
if(OutSurfaceSDF)*OutSurfaceSDF=SurfaceSDF;
return D;
};
uint64 TotalHits=0,TotalAxisLocked=0,TotalNearZero=0,FloorTaggedHits=0,FloorAxisLocked=0;
@@ -982,7 +1020,9 @@ public:
const double XH=OX+DX*HitT,YH=OY+DY*HitT,ZH=OZ+DZ*HitT;
ESurfaceFamily Family=ESurfaceFamily::Strata;float Raw=0.0f,Detail=0.0f;
bool bFloorSurface=false;float PassageInfluence=0.0f;
Distance(XH,YH,ZH,&Family,&Raw,&Detail,&bFloorSurface,&PassageInfluence);
float CaveInfluence=0.0f,FloorInfluence=0.0f,SurfaceSDF=100000.0f;
Distance(XH,YH,ZH,&Family,&Raw,&Detail,&bFloorSurface,&PassageInfluence,
&CaveInfluence,&FloorInfluence,&SurfaceSDF);
const double GX=Distance(XH+0.5,YH,ZH)-Distance(XH-0.5,YH,ZH);
const double GY=Distance(XH,YH+0.5,ZH)-Distance(XH,YH-0.5,ZH);
const double GZ=Distance(XH,YH,ZH+0.5)-Distance(XH,YH,ZH-0.5);
@@ -1036,8 +1076,19 @@ public:
{
const char* Name=Family==ESurfaceFamily::Strata?"strata":
Family==ESurfaceFamily::Cave?"cave":"solid_overlay";
std::printf("[SurfaceRay] t=%.2f vox hit=(%.2f,%.2f,%.2f) family=%s floor_surface=%s passage_influence=%.3f raw_sdf=%.4f detail=%.4f axis_dot=%.4f\n",
HitT,XH,YH,ZH,Name,bFloorSurface?"yes":"no",PassageInfluence,Raw,Detail,AxisDot);
const FLayerField* Field=FindLayerField(ZH);
FOwnerNoiseLineContext OwnerNoise8,OwnerNoise2;
const float Owner8=Field?OwnerCaveRoughness(XH,YH,ZH,SurfaceSDF,
*Field,CaveInfluence,OwnerNoise8,nullptr,8):0.0f;
const float Owner2=Field?OwnerCaveRoughness(XH,YH,ZH,SurfaceSDF,
*Field,CaveInfluence,OwnerNoise2,nullptr,2):0.0f;
const float Relief=SurfaceRelief(static_cast<float>(XH),
static_cast<float>(YH),static_cast<float>(ZH),
static_cast<uint32>(Owner->Seed));
std::printf("[SurfaceRay] t=%.2f vox hit=(%.2f,%.2f,%.2f) family=%s floor_surface=%s cave_influence=%.3f floor_influence=%.3f passage_influence=%.3f surface_sdf=%.4f raw_sdf=%.4f detail=%.4f relief=%.4f owner8=%.4f owner2=%.4f axis_dot=%.4f\n",
HitT,XH,YH,ZH,Name,bFloorSurface?"yes":"no",CaveInfluence,
FloorInfluence,PassageInfluence,SurfaceSDF,Raw,Detail,Relief,
Owner8,Owner2,AxisDot);
}
bFound=true;break;
}
@@ -1245,6 +1296,12 @@ private:
constexpr float Width=1.5f;
return SmoothUnit((Edge-std::abs(SignedDistance))/Width);
}
static float DetailContrast(float CaveInfluence,float FloorInfluence)
{
const float Cave=std::clamp(CaveInfluence,0.0f,1.0f);
const float Floor=std::clamp(FloorInfluence,0.0f,1.0f);
return 1.35f-0.80f*Cave+1.85f*Floor;
}
static constexpr float DetailBandInnerRadius=1.5f;
static float DetailBandFade(float SignedDistance,float Edge)
{
@@ -1271,8 +1328,7 @@ private:
}
const float ReliefBound=std::abs(MacroValue)
+(0.80f+0.25f*MacroValue)*(0.85f+0.18f);
const float Contrast=1.35f-0.80f*std::clamp(CaveInfluence,0.0f,1.0f)
+1.85f*std::clamp(FloorInfluence,0.0f,1.0f);
const float Contrast=DetailContrast(CaveInfluence,FloorInfluence);
const float LocalSupremum=std::min(3.9f,(ReliefBound+0.5f*OwnerBound)*Contrast);
return std::clamp(LocalSupremum+0.125f,DetailBandInnerRadius,DetailSupremum+0.125f);
}
@@ -3040,10 +3096,10 @@ private:
void StoreSurfaceDistance(size_t Node,float Density)
{
int32 Q=static_cast<int32>(std::lround(Density*16.0f));
Q=std::clamp(Q,-127,127);
int32 Q=static_cast<int32>(std::lround(Density*256.0f));
Q=std::clamp(Q,-32767,32767);
if(Q==0)Q=Density<0.0f?-1:1;
SurfaceDistanceQ[Node]=static_cast<int8>(Q);
SurfaceDistanceQ[Node]=static_cast<int16>(Q);
}
bool IsInsideSolidOverlay(int32 X,int32 Y,int32 Z) const
@@ -3727,8 +3783,8 @@ private:
static float SurfaceRelief(float X,float Y,float Z,uint32 Seed)
{
// The low band carries the broad rock shapes and also gently varies mid-band
// amplitude. The quieter 6-voxel octave keeps fine relief without restoring
// the same tight bubble pattern on every exposed surface.
// amplitude. Keep the finest octave wider than a few marching-cubes cells so
// it does not alias into voxel-sized ledges on the full-detail surface.
const float Macro=FStandaloneResearchTunnels::ValueNoise(X,Y,Z,32,Seed^0xB5297A4Du);
const float Mid=FStandaloneResearchTunnels::ValueNoise(X,Y,Z,16,Seed^0x63D83595u);
const float Fine=FStandaloneResearchTunnels::ValueNoise(X,Y,Z,6,Seed^0xA511E9B3u);
@@ -3794,7 +3850,7 @@ private:
FOwnerNoiseLineContext OwnerNoise;
FDetailNoiseLineContext(float X,float Y,uint32 Seed)
:Macro(X,Y,32,Seed^0xB5297A4Du),Mid(X,Y,16,Seed^0x63D83595u),
Fine(X,Y,6,Seed^0xA511E9B3u)
Fine(X,Y,6,Seed^0xA511E9B3u)
{}
float SurfaceReliefAt(float Z,bool bMacroKnown=false,float KnownMacro=0.0f)
@@ -3827,9 +3883,9 @@ private:
if(Field)
OwnerRelief=OwnerCaveRoughnessForDetail(X,Y,Z,SurfaceSDF,*Field,
CaveInfluence,PassageWeight,OwnerNoise);
const float Contrast=1.35f-0.80f*std::clamp(CaveInfluence,0.0f,1.0f)
+1.85f*std::clamp(FloorInfluence,0.0f,1.0f);
return std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
const float Contrast=DetailContrast(CaveInfluence,FloorInfluence);
const float Detail=std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
return Detail;
}
float DetailNoiseOnLine(double X,double Y,double Z,float SurfaceSDF,
@@ -3864,9 +3920,9 @@ private:
if(Profile)
Profile->OwnerRoughnessSampleNanoseconds+=static_cast<uint64>(
std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now()-OwnerStart).count());
const float Contrast=1.35f-0.80f*std::clamp(CaveInfluence,0.0f,1.0f)
+1.85f*std::clamp(FloorInfluence,0.0f,1.0f);
return std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
const float Contrast=DetailContrast(CaveInfluence,FloorInfluence);
const float Detail=std::clamp((Relief+OwnerRelief*0.5f)*Contrast,-3.9f,3.9f);
return Detail;
}
bool EvaluateFast(double X,double Y,double Z) const
@@ -4012,7 +4068,7 @@ private:
std::unordered_map<FBinKey,FBinItems,FBinHash> SpatialBins;
std::unordered_map<FBinKey,FBinItems,FBinHash> CriticalAirBins;
std::vector<uint64> RockWords;
std::unique_ptr<int8[]> SurfaceDistanceQ;
std::unique_ptr<int16[]> SurfaceDistanceQ;
std::array<std::vector<uint64>,3> CandidateAxisWords;
std::vector<uint64> CandidateWords;
FBuildStats Stats;