wip(standalone): shape-world join blends (room 12, strata/cave 3) -- source restored to last passing set, not rebuilt
Luna's continuation stopped when Windows could not start new processes (0xC0000142, low memory). Fixed-view join step: chamber 0.041, tunnel 0.434 (bar 0.450, barely). Routes 5642/5642 open. Shape stages 0.963 s / 0.870 s. Floor join plates still visible; final checks not run. 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
4f4e67c8ca
commit
7e3f926352
5 files changed
+300
-58
No files matched your search
@@ -47,6 +47,10 @@ public:
|
||||
uint64 WalkFailures = 0;
|
||||
double MaxCapsuleJoinRadiusDelta = 0.0;
|
||||
double MaxCapsuleJoinFloorDelta = 0.0;
|
||||
double MaxCapsuleJoinFloorSlopeDelta = 0.0;
|
||||
double MaxUnmarkedFloorSlopeDelta = 0.0;
|
||||
double MaxMarkedFloorSlopeDelta = 0.0;
|
||||
uint64 MarkedFloorSlopeJoins = 0;
|
||||
double LegacySegmentRadiusStep = 0.0;
|
||||
double SmoothedProfileRadiusStep = 0.0;
|
||||
double MaxTunnelBendDegrees = 0.0;
|
||||
@@ -99,6 +103,8 @@ public:
|
||||
static constexpr int32 DetailBand = 4;
|
||||
static constexpr float DetailSupremum = 4.0f;
|
||||
static constexpr double JoinBlendRadius = 0.0;
|
||||
static constexpr double RoomUnionBlendRadius = 12.0;
|
||||
static constexpr float StrataCaveBlendRadius = 3.0f;
|
||||
static constexpr int32 LineBinSize = 32;
|
||||
static constexpr int32 SpatialBinSize = 256;
|
||||
|
||||
@@ -170,10 +176,12 @@ public:
|
||||
static_cast<unsigned long long>(Stats.WalkSamples-Stats.WalkFailures),
|
||||
static_cast<unsigned long long>(Stats.WalkSamples));
|
||||
const double SmoothUnionGrowthBound=JoinBlendRadius/6.0;
|
||||
std::printf("[TunnelRadiusAudit] shared_joins=%llu legacy_fixed_segment_max_step=%.4f vox smoothed_profile_max_step=%.4f vox tapered_endpoint_max_delta=%.6f vox floor_endpoint_max_delta=%.6f vox smooth_union_growth_bound=%.4f vox thresholds=(0.005,0.005,0.25) status=%s\n",
|
||||
std::printf("[TunnelRadiusAudit] shared_joins=%llu legacy_fixed_segment_max_step=%.4f vox smoothed_profile_max_step=%.4f vox tapered_endpoint_max_delta=%.6f vox floor_endpoint_max_delta=%.6f vox floor_slope_join_delta=%.5f unmarked_floor_slope_delta=%.5f marked_floor_slope_delta=%.5f marked_slope_joins=%llu smooth_union_growth_bound=%.4f vox thresholds=(0.005,0.005,0.25) status=%s\n",
|
||||
static_cast<unsigned long long>(Stats.CapsuleJoinCount),Stats.LegacySegmentRadiusStep,
|
||||
Stats.SmoothedProfileRadiusStep,Stats.MaxCapsuleJoinRadiusDelta,
|
||||
Stats.MaxCapsuleJoinFloorDelta,SmoothUnionGrowthBound,
|
||||
Stats.MaxCapsuleJoinFloorDelta,Stats.MaxCapsuleJoinFloorSlopeDelta,
|
||||
Stats.MaxUnmarkedFloorSlopeDelta,Stats.MaxMarkedFloorSlopeDelta,
|
||||
static_cast<unsigned long long>(Stats.MarkedFloorSlopeJoins),SmoothUnionGrowthBound,
|
||||
Stats.MaxCapsuleJoinRadiusDelta<=0.005&&Stats.MaxCapsuleJoinFloorDelta<=0.005
|
||||
&&SmoothUnionGrowthBound<=0.25?"PASS":"FAIL");
|
||||
const double BendHorizontal=std::sqrt(Stats.MaxTunnelBendDirection.X*Stats.MaxTunnelBendDirection.X
|
||||
@@ -231,17 +239,23 @@ public:
|
||||
Density=(bRock?-1.0f:1.0f)*std::max(std::abs(Density),1.0f/16.0f);
|
||||
return Density;
|
||||
}
|
||||
return bRock?-(DetailBand+2.0f):(DetailBand+2.0f);
|
||||
// Match the fixed fallback to the edge of the stored proxy band. The
|
||||
// displacement is tapered to zero there, so this avoids a magnitude
|
||||
// jump along the candidate bit-mask boundary.
|
||||
constexpr float ProxyBandEdge=DetailSupremum+0.125f;
|
||||
return bRock?-ProxyBandEdge:ProxyBandEdge;
|
||||
}
|
||||
ESurfaceFamily SurfaceFamily=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
bool bFloorSurface=false;
|
||||
float RockDistance=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,&bFloorSurface);
|
||||
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
|
||||
float RockDistance=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,
|
||||
&bFloorSurface,&CaveInfluence,&FloorInfluence);
|
||||
const bool bInsideFine=X>=Min[0]&&X<=Max[0]&&Y>=Min[1]&&Y<=Max[1]
|
||||
&&Z>=Min[2]&&Z<=Max[2];
|
||||
const bool bCriticalAir=IsInsideCriticalAir(X,Y,Z);
|
||||
if(bInsideFine&&DetailVariant!=EDetailVariant::Smooth
|
||||
&&std::abs(RockDistance)<=DetailSupremum+0.125f)
|
||||
RockDistance+=DetailNoise(X,Y,Z,SurfaceSDF,SurfaceFamily,bFloorSurface);
|
||||
RockDistance+=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,FloorInfluence)
|
||||
*DetailBandFade(RockDistance);
|
||||
if(bCriticalAir)RockDistance=std::min(RockDistance,-1.0f/16.0f);
|
||||
float Density=-RockDistance;
|
||||
if((Density<0.0f)!=bRock||std::abs(Density)<0.05f)
|
||||
@@ -335,10 +349,12 @@ public:
|
||||
const size_t Zi=W*64+Bit;if(Zi>=static_cast<size_t>(Size[2]))continue;
|
||||
const int32 Z=Min[2]+static_cast<int32>(Zi);
|
||||
ESurfaceFamily Family=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
bool bFloorSurface=false;
|
||||
const float Raw=EffectiveRockDistance(X,Y,Z,&Family,&SurfaceSDF,&bFloorSurface);
|
||||
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
|
||||
const float Raw=EffectiveRockDistance(X,Y,Z,&Family,&SurfaceSDF,
|
||||
&bFloorSurface,&CaveInfluence,&FloorInfluence);
|
||||
if(std::abs(Raw)>=0.5f)continue;
|
||||
const float Detail=DetailNoise(X,Y,Z,SurfaceSDF,Family,bFloorSurface);
|
||||
const float Detail=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,FloorInfluence)
|
||||
*DetailBandFade(Raw);
|
||||
const size_t FamilyIndex=static_cast<size_t>(Family);
|
||||
FFamilyStats& F=Families[FamilyIndex];++F.Count;F.Sum+=Detail;F.SumSq+=Detail*Detail;
|
||||
if(std::abs(Detail)<0.05f)++F.NearZero;
|
||||
@@ -392,22 +408,26 @@ public:
|
||||
double Sum=0.0,SumSq=0.0;
|
||||
};
|
||||
std::array<FFamilyStats,3> FamilyStats{};
|
||||
constexpr std::array<float,9> YawOffsets={-32.0f,-24.0f,-16.0f,-8.0f,0.0f,8.0f,16.0f,24.0f,32.0f};
|
||||
constexpr std::array<float,5> PitchOffsets={-20.0f,-10.0f,0.0f,10.0f,20.0f};
|
||||
constexpr std::array<float,13> YawOffsets={-36.0f,-30.0f,-24.0f,-18.0f,-12.0f,-6.0f,
|
||||
0.0f,6.0f,12.0f,18.0f,24.0f,30.0f,36.0f};
|
||||
constexpr std::array<float,11> PitchOffsets={-80.0f,-70.0f,-60.0f,-50.0f,-40.0f,
|
||||
-30.0f,-20.0f,-10.0f,0.0f,10.0f,20.0f};
|
||||
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)
|
||||
{
|
||||
ESurfaceFamily Family=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
bool bFloorSurface=false;
|
||||
float D=EffectiveRockDistance(X,Y,Z,&Family,&SurfaceSDF,&bFloorSurface);
|
||||
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
|
||||
float D=EffectiveRockDistance(X,Y,Z,&Family,&SurfaceSDF,
|
||||
&bFloorSurface,&CaveInfluence,&FloorInfluence);
|
||||
float Detail=0.0f;
|
||||
const bool bInside=X>=Min[0]&&X<=Max[0]&&Y>=Min[1]&&Y<=Max[1]
|
||||
&&Z>=Min[2]&&Z<=Max[2];
|
||||
const bool bCriticalAir=IsInsideCriticalAir(X,Y,Z);
|
||||
if(bInside&&DetailVariant!=EDetailVariant::Smooth&&std::abs(D)<=DetailSupremum+0.125f)
|
||||
{Detail=DetailNoise(X,Y,Z,SurfaceSDF,Family,bFloorSurface);D+=Detail;}
|
||||
{Detail=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,FloorInfluence)
|
||||
*DetailBandFade(D);D+=Detail;}
|
||||
if(bCriticalAir)D=std::min(D,-1.0f/16.0f);
|
||||
if(OutFamily)*OutFamily=Family;
|
||||
if(OutRaw)*OutRaw=D-Detail;
|
||||
@@ -415,7 +435,9 @@ public:
|
||||
if(OutFloorSurface)*OutFloorSurface=bFloorSurface;
|
||||
return D;
|
||||
};
|
||||
uint64 TotalHits=0,TotalAxisLocked=0,TotalNearZero=0;
|
||||
uint64 TotalHits=0,TotalAxisLocked=0,TotalNearZero=0,FloorTaggedHits=0,FloorAxisLocked=0;
|
||||
uint64 FamilyTransitionPairs=0,StableFamilyPairs=0;
|
||||
double FamilyTransitionGradientSq=0.0,StableFamilyGradientSq=0.0;
|
||||
for(float YawOffset:YawOffsets)for(float PitchOffset:PitchOffsets)
|
||||
{
|
||||
const double YawRad=Yaw+YawOffset*0.017453292519943295;
|
||||
@@ -447,10 +469,50 @@ public:
|
||||
const double GZ=Distance(XH,YH,ZH+0.5)-Distance(XH,YH,ZH-0.5);
|
||||
const double GL=std::sqrt(GX*GX+GY*GY+GZ*GZ);
|
||||
const double AxisDot=GL>1.0e-8?std::max({std::abs(GX),std::abs(GY),std::abs(GZ)})/GL:1.0;
|
||||
for(int32 Axis=0;Axis<3;++Axis)
|
||||
{
|
||||
double AP[3]={XH,YH,ZH},AM[3]={XH,YH,ZH};
|
||||
AP[Axis]+=0.5;AM[Axis]-=0.5;
|
||||
ESurfaceFamily FamilyP=ESurfaceFamily::Strata,FamilyM=ESurfaceFamily::Strata;
|
||||
float DetailP=0.0f,DetailM=0.0f;bool bFloorP=false,bFloorM=false;
|
||||
Distance(AP[0],AP[1],AP[2],&FamilyP,nullptr,&DetailP,&bFloorP);
|
||||
Distance(AM[0],AM[1],AM[2],&FamilyM,nullptr,&DetailM,&bFloorM);
|
||||
const double Gradient=static_cast<double>(DetailP-DetailM);
|
||||
if(FamilyP!=FamilyM||bFloorP!=bFloorM)
|
||||
{FamilyTransitionGradientSq+=Gradient*Gradient;++FamilyTransitionPairs;}
|
||||
else
|
||||
{StableFamilyGradientSq+=Gradient*Gradient;++StableFamilyPairs;}
|
||||
}
|
||||
constexpr double ScanRadius=16.0;
|
||||
constexpr int32 ScanSteps=128;
|
||||
double ScanT=std::max(0.0,HitT-ScanRadius);
|
||||
ESurfaceFamily ScanFamily=ESurfaceFamily::Strata;
|
||||
bool bScanFloor=false;float ScanRaw=0.0f,ScanDetail=0.0f;
|
||||
Distance(OX+DX*ScanT,OY+DY*ScanT,OZ+DZ*ScanT,
|
||||
&ScanFamily,&ScanRaw,&ScanDetail,&bScanFloor);
|
||||
for(int32 Step=1;Step<=ScanSteps;++Step)
|
||||
{
|
||||
const double T=std::min(HitT+ScanRadius,ScanT+0.25);
|
||||
ESurfaceFamily NextFamily=ESurfaceFamily::Strata;
|
||||
bool bNextFloor=false;float NextRaw=0.0f,NextDetail=0.0f;
|
||||
Distance(OX+DX*T,OY+DY*T,OZ+DZ*T,
|
||||
&NextFamily,&NextRaw,&NextDetail,&bNextFloor);
|
||||
if(std::abs(ScanRaw)<=5.0f&&std::abs(NextRaw)<=5.0f)
|
||||
{
|
||||
const double Gradient=static_cast<double>(NextDetail-ScanDetail);
|
||||
if(ScanFamily!=NextFamily||bScanFloor!=bNextFloor)
|
||||
{FamilyTransitionGradientSq+=Gradient*Gradient;++FamilyTransitionPairs;}
|
||||
else
|
||||
{StableFamilyGradientSq+=Gradient*Gradient;++StableFamilyPairs;}
|
||||
}
|
||||
ScanT=T;ScanFamily=NextFamily;bScanFloor=bNextFloor;
|
||||
ScanRaw=NextRaw;ScanDetail=NextDetail;
|
||||
}
|
||||
FFamilyStats& S=FamilyStats[static_cast<size_t>(Family)];
|
||||
++S.Hits;++TotalHits;S.Sum+=Detail;S.SumSq+=Detail*Detail;
|
||||
if(std::abs(Detail)<0.05f){++S.NearZero;++TotalNearZero;}
|
||||
if(AxisDot>0.985){++S.AxisLocked;++TotalAxisLocked;}
|
||||
if(bFloorSurface){++FloorTaggedHits;if(AxisDot>0.985)++FloorAxisLocked;}
|
||||
if(YawOffset==0.0f&&PitchOffset==0.0f)
|
||||
{
|
||||
const char* Name=Family==ESurfaceFamily::Strata?"strata":
|
||||
@@ -466,17 +528,31 @@ public:
|
||||
}
|
||||
const double NearZeroShare=TotalHits?static_cast<double>(TotalNearZero)/TotalHits:1.0;
|
||||
const double AxisShare=TotalHits?static_cast<double>(TotalAxisLocked)/TotalHits:1.0;
|
||||
const double FloorAxisShare=FloorTaggedHits?static_cast<double>(FloorAxisLocked)/FloorTaggedHits:1.0;
|
||||
const double TransitionRMS=FamilyTransitionPairs
|
||||
?std::sqrt(FamilyTransitionGradientSq/FamilyTransitionPairs):0.0;
|
||||
const double StableRMS=StableFamilyPairs
|
||||
?std::sqrt(StableFamilyGradientSq/StableFamilyPairs):0.0;
|
||||
const double TransitionRatio=StableRMS>1.0e-6?TransitionRMS/StableRMS:1000000.0;
|
||||
double Sum=0.0,SumSq=0.0;
|
||||
for(const FFamilyStats& S:FamilyStats){Sum+=S.Sum;SumSq+=S.SumSq;}
|
||||
const double Mean=TotalHits?Sum/TotalHits:0.0;
|
||||
const double Variance=TotalHits?std::max(0.0,SumSq/TotalHits-Mean*Mean):0.0;
|
||||
const double SurfaceDetailRMS=std::sqrt(Variance);
|
||||
const double RelativeJoinStep=SurfaceDetailRMS>1.0e-6?TransitionRMS/SurfaceDetailRMS:1000000.0;
|
||||
const bool bDetailPass=TotalHits>=24&&std::sqrt(Variance)>=0.15&&NearZeroShare<0.50;
|
||||
const bool bGridPass=TotalHits>=24&&AxisShare<0.60;
|
||||
const bool bJoinCoverage=FloorTaggedHits>=8
|
||||
&&(FamilyTransitionPairs==0||(FamilyTransitionPairs>=8&&RelativeJoinStep<0.45));
|
||||
const bool bGridPass=TotalHits>=24&&AxisShare<0.60
|
||||
&&bJoinCoverage;
|
||||
std::printf("[FlatSurfaceAudit] rays=%llu detail_stddev=%.4f vox near_zero_share=%.1f%% threshold=50.0%% status=%s\n",
|
||||
static_cast<unsigned long long>(TotalHits),std::sqrt(Variance),NearZeroShare*100.0,
|
||||
bDetailPass?"PASS":"FAIL");
|
||||
std::printf("[GridStairAudit] rays=%llu axis_locked_normals=%.1f%% threshold=60.0%% status=%s\n",
|
||||
static_cast<unsigned long long>(TotalHits),AxisShare*100.0,bGridPass?"PASS":"FAIL");
|
||||
std::printf("[GridStairAudit] rays=%llu axis_locked_normals=%.1f%% threshold=60.0%% floor_tagged_hits=%llu floor_axis_locked=%.1f%% family_transition_pairs=%llu transition_rms=%.4f vox stable_rms=%.4f vox surface_detail_rms=%.4f vox relative_join_step=%.3f threshold=0.450 legacy_join_ratio=%.3f status=%s\n",
|
||||
static_cast<unsigned long long>(TotalHits),AxisShare*100.0,
|
||||
static_cast<unsigned long long>(FloorTaggedHits),FloorAxisShare*100.0,
|
||||
static_cast<unsigned long long>(FamilyTransitionPairs),TransitionRMS,StableRMS,
|
||||
SurfaceDetailRMS,RelativeJoinStep,TransitionRatio,bGridPass?"PASS":"FAIL");
|
||||
for(size_t I=0;I<FamilyStats.size();++I)
|
||||
{
|
||||
const char* Name=I==0?"strata":I==1?"cave":"solid_overlay";
|
||||
@@ -523,6 +599,19 @@ private:
|
||||
}
|
||||
static float SmoothMaxDistance(float A,float B,float Width)
|
||||
{return -SmoothMinDistance(-A,-B,Width);}
|
||||
static float SmoothUnit(float V)
|
||||
{
|
||||
V=std::clamp(V,0.0f,1.0f);
|
||||
return V*V*(3.0f-2.0f*V);
|
||||
}
|
||||
static float DetailBandFade(float SignedDistance)
|
||||
{
|
||||
// Keep full relief near the visible surface, then blend it to zero over
|
||||
// the outer 1.5 voxels of the proxy support band.
|
||||
constexpr float Edge=DetailSupremum+0.125f;
|
||||
constexpr float Width=1.5f;
|
||||
return SmoothUnit((Edge-std::abs(SignedDistance))/Width);
|
||||
}
|
||||
|
||||
void BuildLayerBounds()
|
||||
{
|
||||
@@ -844,8 +933,13 @@ private:
|
||||
FVector(R.Center.X,R.Center.Y,R.FloorCutZ-Relief),Params,
|
||||
static_cast<uint32>(Owner->Seed)).Z;
|
||||
for(size_t I=RoomPrimitiveStart;I<Primitives.size();++I)
|
||||
if(Primitives[I].bCarve)ApplyFloorClip(Primitives[I],FloorZ,0.0,0.0,0.0);
|
||||
if(Primitives[I].bCarve)ApplyFloorClip(Primitives[I],FloorZ,0.0,0.0,3.0);
|
||||
}
|
||||
// The packed signs still union room intervals exactly. Blend only
|
||||
// the analytic cave field where neighboring authored rooms meet;
|
||||
// this rounds the room-to-room edge without touching tunnel radii.
|
||||
for(size_t I=RoomPrimitiveStart;I<Primitives.size();++I)
|
||||
if(Primitives[I].bCarve)Primitives[I].BlendRadius=RoomUnionBlendRadius;
|
||||
}
|
||||
for(const FCachedRoomFloorJoin& J:Cache.RoomFloorJoins)
|
||||
{
|
||||
@@ -854,7 +948,7 @@ private:
|
||||
}
|
||||
const double RoomBlendRadius=ActiveBlendRadius;
|
||||
ActiveBlendRadius=JoinBlendRadius;
|
||||
ActiveFloorBlendRadius=1.5;
|
||||
ActiveFloorBlendRadius=3.0;
|
||||
for(const FCachedTunnel& T:Cache.Tunnels)
|
||||
{
|
||||
++Stats.TunnelCount;
|
||||
@@ -887,9 +981,27 @@ private:
|
||||
Stats.LegacySegmentRadiusStep=std::max(Stats.LegacySegmentRadiusStep,
|
||||
static_cast<double>(std::abs(std::max(RPrev,RHere)-std::max(RHere,RNext))));
|
||||
if(FloorProfiles.IsValidIndex(Join-1)&&FloorProfiles.IsValidIndex(Join))
|
||||
{
|
||||
Stats.MaxCapsuleJoinFloorDelta=std::max(Stats.MaxCapsuleJoinFloorDelta,
|
||||
static_cast<double>(std::abs(FloorProfiles[Join-1].EndFloorZ
|
||||
-FloorProfiles[Join].StartFloorZ)));
|
||||
const FVector PrevD=Points[Join]-Points[Join-1];
|
||||
const FVector NextD=Points[Join+1]-Points[Join];
|
||||
const double PrevXY=std::sqrt(PrevD.X*PrevD.X+PrevD.Y*PrevD.Y);
|
||||
const double NextXY=std::sqrt(NextD.X*NextD.X+NextD.Y*NextD.Y);
|
||||
const double PrevSlope=PrevXY>1.0e-6
|
||||
?(FloorProfiles[Join-1].EndFloorZ-FloorProfiles[Join-1].StartFloorZ)/PrevXY:0.0;
|
||||
const double NextSlope=NextXY>1.0e-6
|
||||
?(FloorProfiles[Join].EndFloorZ-FloorProfiles[Join].StartFloorZ)/NextXY:0.0;
|
||||
const double SlopeDelta=std::abs(PrevSlope-NextSlope);
|
||||
Stats.MaxCapsuleJoinFloorSlopeDelta=std::max(Stats.MaxCapsuleJoinFloorSlopeDelta,SlopeDelta);
|
||||
if(FloorProfiles[Join-1].bLedgeTransition||FloorProfiles[Join].bLedgeTransition)
|
||||
{
|
||||
++Stats.MarkedFloorSlopeJoins;
|
||||
Stats.MaxMarkedFloorSlopeDelta=std::max(Stats.MaxMarkedFloorSlopeDelta,SlopeDelta);
|
||||
}
|
||||
else Stats.MaxUnmarkedFloorSlopeDelta=std::max(Stats.MaxUnmarkedFloorSlopeDelta,SlopeDelta);
|
||||
}
|
||||
++Stats.CapsuleJoinCount;
|
||||
}
|
||||
if(Points.Num()>1)
|
||||
@@ -904,7 +1016,7 @@ private:
|
||||
const FVector Segment=Points[I+1]-Points[I];
|
||||
const double SegmentLength=std::sqrt(Segment.X*Segment.X+Segment.Y*Segment.Y+Segment.Z*Segment.Z);
|
||||
const double Extension=ContinuousJoinExtension(R0,R1,SegmentLength);
|
||||
float ZA=Points[I].Z-R0, ZB=Points[I+1].Z-R1;
|
||||
float ZA=Points[I].Z-R0,ZB=Points[I+1].Z-R1;
|
||||
if(FloorProfiles.IsValidIndex(I))ZA=FloorProfiles[I].StartFloorZ;
|
||||
if(FloorProfiles.IsValidIndex(I))ZB=FloorProfiles[I].EndFloorZ;
|
||||
AddTaperedCapsule(Points[I],Points[I+1],R0,R1,true,false,true,ZA,ZB,
|
||||
@@ -940,7 +1052,7 @@ private:
|
||||
}
|
||||
}
|
||||
const double PassageJoinBlend=ActiveBlendRadius;ActiveBlendRadius=JoinBlendRadius;
|
||||
ActiveFloorBlendRadius=1.5;
|
||||
ActiveFloorBlendRadius=3.0;
|
||||
for(const FVoxelPassage& P:Owner->Manager->GetPassages())
|
||||
{
|
||||
++Stats.PassageCount;
|
||||
@@ -954,6 +1066,20 @@ private:
|
||||
const float RNext=std::max(6.0f,Radii.IsValidIndex(Join+1)?Radii[Join+1]:P.Radius);
|
||||
Stats.LegacySegmentRadiusStep=std::max(Stats.LegacySegmentRadiusStep,
|
||||
static_cast<double>(std::abs(std::max(RPrev,RHere)-std::max(RHere,RNext))));
|
||||
if(P.NativeFloorProfileZ.IsValidIndex(Join-1)&&P.NativeFloorProfileZ.IsValidIndex(Join))
|
||||
{
|
||||
const FVector PrevD=Points[Join]-Points[Join-1];
|
||||
const FVector NextD=Points[Join+1]-Points[Join];
|
||||
const double PrevXY=std::sqrt(PrevD.X*PrevD.X+PrevD.Y*PrevD.Y);
|
||||
const double NextXY=std::sqrt(NextD.X*NextD.X+NextD.Y*NextD.Y);
|
||||
const double PrevSlope=PrevXY>1.0e-6
|
||||
?(P.NativeFloorProfileZ[Join]-P.NativeFloorProfileZ[Join-1])/PrevXY:0.0;
|
||||
const double NextSlope=NextXY>1.0e-6
|
||||
?(P.NativeFloorProfileZ[Join+1]-P.NativeFloorProfileZ[Join])/NextXY:0.0;
|
||||
const double SlopeDelta=std::abs(PrevSlope-NextSlope);
|
||||
Stats.MaxCapsuleJoinFloorSlopeDelta=std::max(Stats.MaxCapsuleJoinFloorSlopeDelta,SlopeDelta);
|
||||
Stats.MaxUnmarkedFloorSlopeDelta=std::max(Stats.MaxUnmarkedFloorSlopeDelta,SlopeDelta);
|
||||
}
|
||||
++Stats.CapsuleJoinCount;
|
||||
}
|
||||
if(Points.Num()>1)
|
||||
@@ -1562,10 +1688,12 @@ private:
|
||||
++LocalCandidates;
|
||||
const bool bCriticalAir=IsInsideCriticalAir(X,Y,Z);
|
||||
ESurfaceFamily SurfaceFamily=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
bool bFloorSurface=false;
|
||||
const float SDF=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,&bFloorSurface);
|
||||
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
|
||||
const float SDF=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,
|
||||
&bFloorSurface,&CaveInfluence,&FloorInfluence);
|
||||
if(std::abs(SDF)>DetailSupremum+0.125f)continue;
|
||||
float Displaced=SDF+DetailNoise(X,Y,Z,SurfaceSDF,SurfaceFamily,bFloorSurface);
|
||||
float Displaced=SDF+DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,FloorInfluence)
|
||||
*DetailBandFade(SDF);
|
||||
if(bCriticalAir)Displaced=std::min(Displaced,-1.0f/16.0f);
|
||||
const bool bNewRock=Displaced>=0.0f;
|
||||
const bool bOldRock=((RockWords[WordBase+(Zi>>6)]>>(Zi&63u))&1u)!=0;
|
||||
@@ -1660,52 +1788,48 @@ private:
|
||||
{
|
||||
const FPrimitive& P=Primitives[Id];if(!P.bCarve||!P.bCritical)continue;
|
||||
if(X<P.Min[0]||X>P.Max[0]||Y<P.Min[1]||Y>P.Max[1]||Z<P.Min[2]||Z>P.Max[2])continue;
|
||||
if(ShapeDistance(P,X,Y,Z)>0.0f)continue;
|
||||
if(P.bHasFloorClip)
|
||||
{
|
||||
const double Floor=P.FloorCenterZ+P.FloorSlopeX*(X-P.CenterSub[0]/16.0)
|
||||
+P.FloorSlopeY*(Y-P.CenterSub[1]/16.0);
|
||||
if(Z<Floor)continue;
|
||||
}
|
||||
return true;
|
||||
if(ShapeContains(P,X,Y,Z))return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float CaveDistance(double X,double Y,double Z,bool* OutFloorSurface=nullptr) const
|
||||
float CaveDistance(double X,double Y,double Z,bool* OutFloorSurface=nullptr,
|
||||
float* OutFloorInfluence=nullptr) const
|
||||
{
|
||||
const auto It=SpatialBins.find(PointBin(X,Y,Z));
|
||||
if(It==SpatialBins.end())
|
||||
{
|
||||
if(OutFloorSurface)*OutFloorSurface=false;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
|
||||
return 100000.0f;
|
||||
}
|
||||
float Best=100000.0f;
|
||||
bool bBestFloorSurface=false;
|
||||
float BestFloorInfluence=0.0f;
|
||||
for(uint32 Id:It->second)
|
||||
{
|
||||
const FPrimitive& P=Primitives[Id];if(!P.bCarve)continue;
|
||||
if(X<P.Min[0]-DetailBand||X>P.Max[0]+DetailBand||Y<P.Min[1]-DetailBand||Y>P.Max[1]+DetailBand
|
||||
||Z<P.Min[2]-DetailBand||Z>P.Max[2]+DetailBand)continue;
|
||||
float Distance=ShapeDistance(P,X,Y,Z);
|
||||
bool bFloorInfluencesSurface=false;
|
||||
float PrimitiveFloorInfluence=0.0f;
|
||||
if(P.bHasFloorClip)
|
||||
{
|
||||
const double Floor=P.FloorCenterZ+P.FloorSlopeX*(X-P.CenterSub[0]/16.0)
|
||||
+P.FloorSlopeY*(Y-P.CenterSub[1]/16.0);
|
||||
bFloorInfluencesSurface=OutFloorSurface!=nullptr
|
||||
&&std::abs(Z-Floor)<=DetailBand+P.FloorBlendRadius;
|
||||
const float FloorT=(static_cast<float>(std::abs(Z-Floor))-static_cast<float>(P.FloorBlendRadius))
|
||||
/static_cast<float>(std::max(DetailBand*2,1));
|
||||
PrimitiveFloorInfluence=1.0f-SmoothUnit(FloorT);
|
||||
Distance=SmoothMaxDistance(Distance,static_cast<float>(Floor-Z),
|
||||
static_cast<float>(P.FloorBlendRadius));
|
||||
}
|
||||
const float MetadataWidth=static_cast<float>(std::max(P.BlendRadius,6.0));
|
||||
const float PrimitiveWeight=SmoothUnit(0.5f+(Best-Distance)/(2.0f*MetadataWidth));
|
||||
const float Combined=SmoothMinDistance(Best,Distance,static_cast<float>(P.BlendRadius));
|
||||
if(Combined<Best)
|
||||
{
|
||||
Best=Combined;
|
||||
bBestFloorSurface=bFloorInfluencesSurface;
|
||||
}
|
||||
BestFloorInfluence=std::lerp(BestFloorInfluence,PrimitiveFloorInfluence,PrimitiveWeight);
|
||||
Best=Combined;
|
||||
}
|
||||
if(OutFloorSurface)*OutFloorSurface=bBestFloorSurface;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=BestFloorInfluence;
|
||||
if(OutFloorSurface)*OutFloorSurface=BestFloorInfluence>=0.5f;
|
||||
return Best;
|
||||
}
|
||||
|
||||
@@ -1725,27 +1849,37 @@ private:
|
||||
float EffectiveRockDistance(double X,double Y,double Z,
|
||||
ESurfaceFamily* OutFamily=nullptr,
|
||||
float* OutSurfaceSDF=nullptr,
|
||||
bool* OutFloorSurface=nullptr) const
|
||||
bool* OutFloorSurface=nullptr,
|
||||
float* OutCaveInfluence=nullptr,
|
||||
float* OutFloorInfluence=nullptr) const
|
||||
{
|
||||
const float Base=StrataDistance(Z);
|
||||
bool bCaveFloorSurface=false;
|
||||
const float Cave=CaveDistance(X,Y,Z,OutFloorSurface?&bCaveFloorSurface:nullptr);
|
||||
float CaveFloorInfluence=0.0f;
|
||||
const float Cave=CaveDistance(X,Y,Z,nullptr,
|
||||
(OutFloorSurface||OutFloorInfluence)?&CaveFloorInfluence:nullptr);
|
||||
const float Overlay=SolidOverlayDistance(X,Y,Z);
|
||||
const float CarveOrOverlay=std::max(Cave,Overlay);
|
||||
const ESurfaceFamily Family=Base<=CarveOrOverlay?ESurfaceFamily::Strata:
|
||||
(Cave>=Overlay?ESurfaceFamily::Cave:ESurfaceFamily::SolidOverlay);
|
||||
constexpr float FamilyBlendWidth=6.0f;
|
||||
const float CaveVsOverlay=SmoothUnit(0.5f+(Cave-Overlay)/(2.0f*FamilyBlendWidth));
|
||||
const float CarveInfluence=SmoothUnit(0.5f+(Base-CarveOrOverlay)/(2.0f*FamilyBlendWidth));
|
||||
const float CaveInfluence=CarveInfluence*CaveVsOverlay;
|
||||
const float FloorInfluence=CaveInfluence*CaveFloorInfluence;
|
||||
if(OutFamily)
|
||||
*OutFamily=Family;
|
||||
if(OutSurfaceSDF)
|
||||
*OutSurfaceSDF=Family==ESurfaceFamily::Strata?Base:
|
||||
(Family==ESurfaceFamily::Cave?Cave:Overlay);
|
||||
if(OutFloorSurface)*OutFloorSurface=Family==ESurfaceFamily::Cave&&bCaveFloorSurface;
|
||||
return std::min(Base,CarveOrOverlay);
|
||||
if(OutCaveInfluence)*OutCaveInfluence=CaveInfluence;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=FloorInfluence;
|
||||
if(OutFloorSurface)*OutFloorSurface=FloorInfluence>=0.5f;
|
||||
return SmoothMinDistance(Base,CarveOrOverlay,StrataCaveBlendRadius);
|
||||
}
|
||||
|
||||
float OwnerCaveRoughness(double X,double Y,double Z,float SurfaceSDF,
|
||||
const FStrateGenerationParams& Params,
|
||||
bool bCaveSurface) const
|
||||
float CaveInfluence) const
|
||||
{
|
||||
const float Depth=Params.SurfaceRoughness*2.0f;
|
||||
if(!(Depth>0.0f)||std::abs(SurfaceSDF)>=Depth||!(Params.RoughnessFrequency>0.0f))return 0.0f;
|
||||
@@ -1795,7 +1929,8 @@ private:
|
||||
FineValue=VoxelNoise::FBM(Fine.X,Fine.Y,Fine.Z,2);break;
|
||||
}
|
||||
float Total=(Rough+FineValue*0.4f)*VOXEL_NOISE_SCALE*Params.SurfaceRoughness;
|
||||
if(bCaveSurface&&SurfaceSDF<0.0f)Total=std::min(Total,0.0f);
|
||||
if(SurfaceSDF<0.0f)
|
||||
Total=std::lerp(Total,std::min(Total,0.0f),std::clamp(CaveInfluence,0.0f,1.0f));
|
||||
const float Fade=1.0f-std::abs(SurfaceSDF)/Depth;
|
||||
return Total*Fade*Fade;
|
||||
}
|
||||
@@ -1808,7 +1943,7 @@ private:
|
||||
}
|
||||
|
||||
float DetailNoise(double X,double Y,double Z,float SurfaceSDF,
|
||||
ESurfaceFamily SurfaceFamily,bool bFloorSurface=false) const
|
||||
float CaveInfluence,float FloorInfluence) const
|
||||
{
|
||||
if(DetailVariant==EDetailVariant::Smooth)return 0.0f;
|
||||
if(DetailVariant==EDetailVariant::PerVoxel)
|
||||
@@ -1820,9 +1955,9 @@ private:
|
||||
static_cast<float>(Y),static_cast<float>(Z),static_cast<uint32>(Owner->Seed));
|
||||
const FLayerField* Field=FindLayerField(Z);
|
||||
const float OwnerRelief=Field?OwnerCaveRoughness(X,Y,Z,SurfaceSDF,Field->Params,
|
||||
SurfaceFamily==ESurfaceFamily::Cave):0.0f;
|
||||
const float Contrast=bFloorSurface?2.40f:
|
||||
(SurfaceFamily==ESurfaceFamily::Cave?0.55f:1.35f);
|
||||
CaveInfluence):0.0f;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1830,12 +1965,14 @@ private:
|
||||
{
|
||||
const bool bCriticalAir=IsInsideCriticalAir(X,Y,Z);
|
||||
ESurfaceFamily SurfaceFamily=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
bool bFloorSurface=false;
|
||||
float RockDistance=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,&bFloorSurface);
|
||||
bool bFloorSurface=false;float CaveInfluence=0.0f,FloorInfluence=0.0f;
|
||||
float RockDistance=EffectiveRockDistance(X,Y,Z,&SurfaceFamily,&SurfaceSDF,
|
||||
&bFloorSurface,&CaveInfluence,&FloorInfluence);
|
||||
const bool bInsideFine=X>=Min[0]&&X<=Max[0]&&Y>=Min[1]&&Y<=Max[1]&&Z>=Min[2]&&Z<=Max[2];
|
||||
if(bInsideFine&&DetailVariant!=EDetailVariant::Smooth
|
||||
&&std::abs(RockDistance)<=DetailSupremum+0.125f)
|
||||
RockDistance+=DetailNoise(X,Y,Z,SurfaceSDF,SurfaceFamily,bFloorSurface);
|
||||
RockDistance+=DetailNoise(X,Y,Z,SurfaceSDF,CaveInfluence,FloorInfluence)
|
||||
*DetailBandFade(RockDistance);
|
||||
if(bCriticalAir)RockDistance=std::min(RockDistance,-1.0f/16.0f);
|
||||
return RockDistance>=0.0f;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user