wip(assembler): round L23 -- inter-strate passages planned from the resolved layout and carved
After L22 the FI -> SW passage no longer connected the strates (legacy owner-voxel coordinates, lower end 23 m above SW), and Core never carved passages through the bands. Now the director plans passages from the resolved layout (PlanResolvedLayoutPassagesV1; deterministic hash of seed/strates/connection; placement disk from PassageConfig, 8-24 m around (0,0)); shared composition applies generator field -> bands -> bounded passage carve and support shelf, opening the bands only along the tunnel. Mouths bind to the strate routes. Capsule audit: 0 blocked / 0 unsupported (325,962 samples FI, 284,319 TunnelNetwork), negative controls detected; all 8 generator kinds exercised. SW away from the passage is bit-identical. Layout V3, evaluator 9. Open: look not yet natural (stepped tube in FI void, terraced SW arrival); SW-as-upper route planning fails; Unreal adapter uncompiled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
1 parent
55c26a05a7
commit
71d09a8c52
14 files changed
+1465
-112
No files matched your search
@@ -33,7 +33,7 @@
|
||||
class FStandaloneShapeWorld
|
||||
{
|
||||
public:
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV2* ResolvedLayout=nullptr;
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV3* ResolvedLayout=nullptr;
|
||||
struct FResolvedStratumBounds
|
||||
{
|
||||
double BottomZ=0.0;
|
||||
@@ -97,6 +97,170 @@ public:
|
||||
return -std::max(0.05f,static_cast<float>(band->solidDensityQ16)/65536.0f);
|
||||
}
|
||||
|
||||
float ApplyResolvedStratePassageCarves(float density,float X,float Y,float Z) const
|
||||
{
|
||||
if(!ResolvedLayout||ResolvedLayout->passages.empty()||!std::isfinite(X)
|
||||
||!std::isfinite(Y)||!std::isfinite(Z))return density;
|
||||
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||
const double qx=static_cast<double>(X)*Q,qy=static_cast<double>(Y)*Q,qz=static_cast<double>(Z)*Q;
|
||||
const double qPerMetre=Q*1000000.0/std::max<std::uint32_t>(1,ResolvedLayout->coreVoxelSizeMicrometres);
|
||||
const double floorThicknessVoxels=qPerMetre/Q;
|
||||
const double playerCenterAboveFloorQ=1.13*qPerMetre;
|
||||
float composed=density;
|
||||
for(const auto& passage:ResolvedLayout->passages)
|
||||
{
|
||||
if(passage.controlPoints.size()<2)continue;
|
||||
const double placementRadiusQ=static_cast<double>(passage.placementRadiusSubvoxels)
|
||||
+static_cast<double>(passage.midRadiusSubvoxels);
|
||||
if(qx*qx+qy*qy>placementRadiusQ*placementRadiusQ)continue;
|
||||
const double firstFloorQ=passage.controlPoints.front().positionSubvoxels[2]
|
||||
-passage.controlPoints.front().radiusSubvoxels+playerCenterAboveFloorQ;
|
||||
const double lastFloorQ=passage.controlPoints.back().positionSubvoxels[2]
|
||||
-passage.controlPoints.back().radiusSubvoxels+playerCenterAboveFloorQ;
|
||||
if(qz>firstFloorQ+2.0*passage.mouthRadiusSubvoxels
|
||||
||qz<lastFloorQ-2.0*passage.mouthRadiusSubvoxels)continue;
|
||||
const auto floorProfile=[&](const auto& point)
|
||||
{return point.positionSubvoxels[2]-point.radiusSubvoxels+playerCenterAboveFloorQ;};
|
||||
const std::ptrdiff_t lastIndex=static_cast<std::ptrdiff_t>(passage.controlPoints.size())-1;
|
||||
const std::ptrdiff_t lowerMouthIndex=std::clamp<std::ptrdiff_t>(
|
||||
static_cast<std::ptrdiff_t>(passage.lowerMouthControlIndex),1,lastIndex);
|
||||
const auto mainEnd=passage.controlPoints.begin()+lowerMouthIndex+1;
|
||||
const auto carveFound=std::lower_bound(passage.controlPoints.begin(),mainEnd,qz,
|
||||
[&](const auto& point,double value){return floorProfile(point)>value;});
|
||||
const std::ptrdiff_t carveCenter=carveFound-passage.controlPoints.begin();
|
||||
const std::ptrdiff_t carveBegin=std::max<std::ptrdiff_t>(0,carveCenter-3);
|
||||
const std::ptrdiff_t carveEnd=std::min<std::ptrdiff_t>(lowerMouthIndex-1,carveCenter+2);
|
||||
double bestSignedDistance=std::numeric_limits<double>::infinity();
|
||||
double bestT=0.0;
|
||||
std::ptrdiff_t bestIndex=0;
|
||||
bool hasSupportFloor=false;
|
||||
double bestSupportFloorVoxels=-std::numeric_limits<double>::infinity();
|
||||
double bestSupportDensity=0.0;
|
||||
const auto considerCarveSegment=[&](std::ptrdiff_t index)
|
||||
{
|
||||
const auto& a=passage.controlPoints[static_cast<std::size_t>(index)];
|
||||
const auto& b=passage.controlPoints[static_cast<std::size_t>(index+1)];
|
||||
const double ax=static_cast<double>(a.positionSubvoxels[0]);
|
||||
const double ay=static_cast<double>(a.positionSubvoxels[1]);
|
||||
const double az=static_cast<double>(a.positionSubvoxels[2]);
|
||||
const double dx=static_cast<double>(b.positionSubvoxels[0])-ax;
|
||||
const double dy=static_cast<double>(b.positionSubvoxels[1])-ay;
|
||||
const double dz=static_cast<double>(b.positionSubvoxels[2])-az;
|
||||
const double lengthSq=dx*dx+dy*dy+dz*dz;
|
||||
if(lengthSq<=0.0)return;
|
||||
const double t=std::clamp(((qx-ax)*dx+(qy-ay)*dy+(qz-az)*dz)/lengthSq,0.0,1.0);
|
||||
const double cx=ax+t*dx,cy=ay+t*dy,cz=az+t*dz;
|
||||
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
|
||||
const double radius=static_cast<double>(a.radiusSubvoxels)
|
||||
+t*(b.radiusSubvoxels-a.radiusSubvoxels);
|
||||
const double signedDistance=DeterministicSqrt(ex*ex+ey*ey+ez*ez)-radius;
|
||||
if(signedDistance<bestSignedDistance)
|
||||
{bestSignedDistance=signedDistance;bestT=t;bestIndex=index;}
|
||||
};
|
||||
for(std::ptrdiff_t index=carveBegin;index<=carveEnd;++index)
|
||||
considerCarveSegment(index);
|
||||
// The route-bound landing can rise and fall after the lower mouth. Scan
|
||||
// that short tail directly; binary search is only valid on the descent.
|
||||
for(std::ptrdiff_t index=lowerMouthIndex;index<lastIndex;++index)
|
||||
considerCarveSegment(index);
|
||||
if(!std::isfinite(bestSignedDistance))continue;
|
||||
// Positive density is air; the passage SDF is applied after both owner bands.
|
||||
composed=std::max(composed,static_cast<float>(-bestSignedDistance/Q));
|
||||
const auto& nearestA=passage.controlPoints[static_cast<std::size_t>(bestIndex)];
|
||||
const auto& nearestB=passage.controlPoints[static_cast<std::size_t>(bestIndex+1)];
|
||||
const double nearestRadius=nearestA.radiusSubvoxels+bestT*(
|
||||
static_cast<double>(nearestB.radiusSubvoxels)-nearestA.radiusSubvoxels);
|
||||
const double nearestPlayerCenterZ=nearestA.positionSubvoxels[2]+bestT*(
|
||||
static_cast<double>(nearestB.positionSubvoxels[2])-nearestA.positionSubvoxels[2])
|
||||
-nearestRadius+playerCenterAboveFloorQ;
|
||||
// Only compose a support shelf below the capsule feet. This keeps support
|
||||
// probes on the matching floor while capsule samples remain air at bends.
|
||||
if(qz<nearestPlayerCenterZ-0.90*qPerMetre)
|
||||
{
|
||||
const double supportCenterQueryQ=qz+playerCenterAboveFloorQ;
|
||||
const auto supportFound=std::lower_bound(passage.controlPoints.begin(),
|
||||
mainEnd,supportCenterQueryQ,
|
||||
[&](const auto& point,double value){return floorProfile(point)>value;});
|
||||
const std::ptrdiff_t supportCenter=supportFound-passage.controlPoints.begin();
|
||||
const std::ptrdiff_t supportBegin=std::max<std::ptrdiff_t>(0,supportCenter-3);
|
||||
const std::ptrdiff_t supportEnd=std::min<std::ptrdiff_t>(lowerMouthIndex-1,supportCenter+2);
|
||||
const auto considerSupportSegment=[&](std::ptrdiff_t index)
|
||||
{
|
||||
const auto& segmentA=passage.controlPoints[static_cast<std::size_t>(index)];
|
||||
const auto& segmentB=passage.controlPoints[static_cast<std::size_t>(index+1)];
|
||||
const double dx=static_cast<double>(segmentB.positionSubvoxels[0])-segmentA.positionSubvoxels[0];
|
||||
const double dy=static_cast<double>(segmentB.positionSubvoxels[1])-segmentA.positionSubvoxels[1];
|
||||
const double horizontalLengthSq=dx*dx+dy*dy;
|
||||
const double supportT=horizontalLengthSq>0.0
|
||||
?std::clamp(((qx-segmentA.positionSubvoxels[0])*dx
|
||||
+(qy-segmentA.positionSubvoxels[1])*dy)/horizontalLengthSq,0.0,1.0)
|
||||
:bestT;
|
||||
const double supportCenterX=segmentA.positionSubvoxels[0]+supportT*dx;
|
||||
const double supportCenterY=segmentA.positionSubvoxels[1]+supportT*dy;
|
||||
const double supportCenterZ=segmentA.positionSubvoxels[2]+supportT*(
|
||||
static_cast<double>(segmentB.positionSubvoxels[2])-segmentA.positionSubvoxels[2]);
|
||||
const double supportRadius=segmentA.radiusSubvoxels+supportT*(
|
||||
static_cast<double>(segmentB.radiusSubvoxels)-segmentA.radiusSubvoxels);
|
||||
// Leave a 12 cm settle gap below the capsule feet while staying inside
|
||||
// the route support probes' search depth.
|
||||
const double floorQ=supportCenterZ-supportRadius+0.12*qPerMetre;
|
||||
const double floorVoxels=floorQ/Q;
|
||||
const double horizontalX=qx-supportCenterX,horizontalY=qy-supportCenterY;
|
||||
const double horizontalDistance=DeterministicSqrt(horizontalX*horizontalX+horizontalY*horizontalY);
|
||||
const double supportHalfWidth=std::max(0.0,supportRadius-0.15*qPerMetre);
|
||||
if(horizontalDistance<=supportHalfWidth&&Z>=floorVoxels-floorThicknessVoxels
|
||||
&&Z<=floorVoxels+1.0/Q)
|
||||
{
|
||||
if(!hasSupportFloor||floorVoxels>bestSupportFloorVoxels)
|
||||
{
|
||||
bestSupportFloorVoxels=floorVoxels;hasSupportFloor=true;
|
||||
bestSupportDensity=std::clamp(Z-floorVoxels,-floorThicknessVoxels,0.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
for(std::ptrdiff_t index=supportBegin;index<=supportEnd;++index)
|
||||
considerSupportSegment(index);
|
||||
for(std::ptrdiff_t index=lowerMouthIndex;index<lastIndex;++index)
|
||||
considerSupportSegment(index);
|
||||
}
|
||||
if(hasSupportFloor)
|
||||
composed=std::min(composed,static_cast<float>(bestSupportDensity));
|
||||
}
|
||||
return composed;
|
||||
}
|
||||
|
||||
float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const
|
||||
{return ApplyResolvedStratePassageCarves(ApplyResolvedStrateBoundaryBand(density,X,Y,Z),X,Y,Z);}
|
||||
|
||||
bool ResolvedPassageIntersectsBox(const int32 minimum[3],const int32 maximum[3]) const
|
||||
{
|
||||
if(!ResolvedLayout||ResolvedLayout->passages.empty())return false;
|
||||
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||
for(const auto& passage:ResolvedLayout->passages)
|
||||
{
|
||||
for(std::size_t i=1;i<passage.controlPoints.size();++i)
|
||||
{
|
||||
const auto& a=passage.controlPoints[i-1];const auto& b=passage.controlPoints[i];
|
||||
const double radius=static_cast<double>(std::max(a.radiusSubvoxels,b.radiusSubvoxels))/Q;
|
||||
const double floorThicknessVoxels=Owner&&Owner->CoreVoxelSizeMicrons>0
|
||||
?1000000.0/Owner->CoreVoxelSizeMicrons:4.0;
|
||||
const double low[3]={
|
||||
std::min(a.positionSubvoxels[0],b.positionSubvoxels[0])/Q-radius,
|
||||
std::min(a.positionSubvoxels[1],b.positionSubvoxels[1])/Q-radius,
|
||||
std::min(a.positionSubvoxels[2],b.positionSubvoxels[2])/Q-radius-floorThicknessVoxels};
|
||||
const double high[3]={
|
||||
std::max(a.positionSubvoxels[0],b.positionSubvoxels[0])/Q+radius,
|
||||
std::max(a.positionSubvoxels[1],b.positionSubvoxels[1])/Q+radius,
|
||||
std::max(a.positionSubvoxels[2],b.positionSubvoxels[2])/Q+radius};
|
||||
bool overlap=true;
|
||||
for(int axis=0;axis<3;++axis)
|
||||
overlap&=high[axis]>=minimum[axis]&&low[axis]<=maximum[axis];
|
||||
if(overlap)return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool MakeResolvedStratumBounds(double BottomZ,double TopZ,double SealThickness,
|
||||
FResolvedStratumBounds& Out)
|
||||
{
|
||||
@@ -410,7 +574,7 @@ public:
|
||||
const std::vector<VoxelForgeCore::DetailBandTileRegion>& InGpuVisualDetailTiles={},
|
||||
const std::vector<VoxelForgeCore::DetailBandTileRegion>& InCpuVisualDetailTiles={},
|
||||
const VoxelForgeCore::WorldAssemblyManifest* InWorldAssembly=nullptr,
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV2* InResolvedLayout=nullptr)
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV3* InResolvedLayout=nullptr)
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
const auto TotalStart=Clock::now();
|
||||
@@ -571,7 +735,7 @@ public:
|
||||
const FIntVector& ClipMaxVoxels,EDetailVariant Variant,
|
||||
bool bInRoundTunnels,
|
||||
const VoxelForgeCore::WorldAssemblyManifest* InWorldAssembly,
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV2* InResolvedLayout,
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV3* InResolvedLayout,
|
||||
std::string& Error)
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
@@ -611,7 +775,7 @@ public:
|
||||
|
||||
void InitializeNativeSurfaceOnly(FStandaloneOwnerWorld& World,
|
||||
const VoxelForgeCore::WorldAssemblyManifest* InWorldAssembly,
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV2* InResolvedLayout,
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV3* InResolvedLayout,
|
||||
const FIntVector& InMinimum,const FIntVector& InMaximum)
|
||||
{
|
||||
Owner=&World;WorldAssembly=InWorldAssembly;ResolvedLayout=InResolvedLayout;
|
||||
@@ -622,7 +786,7 @@ public:
|
||||
|
||||
bool BuildShapeDependencyProof(FStandaloneOwnerWorld& World,
|
||||
const FIntVector& MinVoxels,const FIntVector& MaxVoxels,bool bInRoundTunnels,
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV2* InResolvedLayout=nullptr)
|
||||
const VoxelForgeCore::ResolvedLayoutSnapshotV3* InResolvedLayout=nullptr)
|
||||
{
|
||||
Owner=&World;ResolvedLayout=InResolvedLayout;WorkerCount=1;RoundTunnelsEnabled=bInRoundTunnels;
|
||||
bAnalyticOnly=true;bNativeOnly=false;Stats={};
|
||||
@@ -1129,19 +1293,19 @@ public:
|
||||
float NativeDensity=0.0f;
|
||||
if(!NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{RecordNativeOnlyViolation();return 0.0f;}
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeFloatFieldCalls;
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(IslandDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(IslandDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeFloatFieldCalls;
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
return LegacySurfaceDensityAt(X,Y,Z);
|
||||
@@ -1191,21 +1355,21 @@ public:
|
||||
if(!NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),NativeDensity))
|
||||
{RecordNativeOnlyViolation();return 0.0f;}
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeLatticeFieldCalls;
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(IslandDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(IslandDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeLatticeFieldCalls;
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z)))
|
||||
@@ -1229,19 +1393,19 @@ public:
|
||||
float NativeDensity=0.0f;
|
||||
if(!NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{RecordNativeOnlyViolation();return 0.0f;}
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeUnclampedFieldCalls;
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(IslandDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(IslandDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeUnclampedFieldCalls;
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(NativeDensity,X,Y,Z),X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
return LegacySurfaceDensityAt(X,Y,Z);
|
||||
@@ -1371,13 +1535,13 @@ private:
|
||||
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/256.0f);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(Density,FX,FY,FZ),FX,FY,FZ);
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(Density,FX,FY,FZ),FX,FY,FZ);
|
||||
}
|
||||
// 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 ApplyEditBrushes(ApplyResolvedStrateBoundaryBand(
|
||||
return ApplyEditBrushes(ApplyResolvedStrateComposition(
|
||||
bRock?-ProxyBandEdge:ProxyBandEdge,FX,FY,FZ),FX,FY,FZ);
|
||||
}
|
||||
|
||||
@@ -1395,7 +1559,7 @@ private:
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
const float composed=ApplyResolvedStrateBoundaryBand(IslandDensity,X,Y,Z);
|
||||
const float composed=ApplyResolvedStrateComposition(IslandDensity,X,Y,Z);
|
||||
return bApplyEdits?ApplyEditBrushes(composed,X,Y,Z):composed;
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
@@ -1403,11 +1567,11 @@ private:
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
NativeDensity=ApplyResolvedStrateBoundaryBand(NativeDensity,X,Y,Z);
|
||||
NativeDensity=ApplyResolvedStrateComposition(NativeDensity,X,Y,Z);
|
||||
return bApplyEdits?ApplyEditBrushes(NativeDensity,X,Y,Z):NativeDensity;
|
||||
}
|
||||
const float Density=Owner->Generator->GetDensityAt(X,Y,Z);
|
||||
const float composed=ApplyResolvedStrateBoundaryBand(Density,X,Y,Z);
|
||||
const float composed=ApplyResolvedStrateComposition(Density,X,Y,Z);
|
||||
return bApplyEdits?ApplyEditBrushes(composed,X,Y,Z):composed;
|
||||
}
|
||||
const bool bInsideFine=X>=Min[0]&&X<=Max[0]&&Y>=Min[1]&&Y<=Max[1]
|
||||
@@ -1422,7 +1586,7 @@ private:
|
||||
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);
|
||||
const float composed=ApplyResolvedStrateBoundaryBand(Density,X,Y,Z);
|
||||
const float composed=ApplyResolvedStrateComposition(Density,X,Y,Z);
|
||||
return bApplyEdits?ApplyEditBrushes(composed,X,Y,Z):composed;
|
||||
}
|
||||
ESurfaceFamily SurfaceFamily=ESurfaceFamily::Strata;float SurfaceSDF=100000.0f;
|
||||
@@ -1452,7 +1616,7 @@ private:
|
||||
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);
|
||||
Density=ApplyResolvedStrateBoundaryBand(Density,X,Y,Z);
|
||||
Density=ApplyResolvedStrateComposition(Density,X,Y,Z);
|
||||
return bApplyEdits?ApplyEditBrushes(Density,X,Y,Z):Density;
|
||||
}
|
||||
|
||||
@@ -1590,6 +1754,8 @@ public:
|
||||
else ++Counts.MixedBoxes;
|
||||
return Result;
|
||||
};
|
||||
if(ResolvedPassageIntersectsBox(BMin,BMax))
|
||||
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])
|
||||
@@ -2319,7 +2485,7 @@ private:
|
||||
// SurfaceWorld consumes biome overrides, terrain ops, water level and its sky cap in
|
||||
// the legacy stack. Reuse that immutable evaluator as an exact temporary bridge.
|
||||
// SurfaceWorld lit biomes, ops de terrain, niveau d'eau et plafond; reutiliser ce champ.
|
||||
const float density=ApplyResolvedStrateBoundaryBand(Owner->Generator->GetDensityAt(X,Y,Z),X,Y,Z);
|
||||
const float density=ApplyResolvedStrateComposition(Owner->Generator->GetDensityAt(X,Y,Z),X,Y,Z);
|
||||
return ApplyEditBrushes(density,X,Y,Z);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user