wip(L17, side branch): FloatingIslands seal-cap fix + owner/Core chunk-scale change (breaks SurfaceWorld)
Not for assembler/world: the 8 m -> 4 m strate chunk change moves every stratum, so the SurfaceWorld spawn camera floats in a void and the L1 mesh export shrank 58.7 -> 31.7 MB. Kept for its diagnostics, the boundarySeal finding and the readable capture shading. See Linux17/REPORT.md. 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
9a7c87e47b
commit
34ae1d7187
30 files changed
+1353
-70
No files matched your search
@@ -249,8 +249,8 @@ namespace VoxelForgeCore
|
||||
// L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles.
|
||||
inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256;
|
||||
inline constexpr std::uint32_t WorldAssemblySchemaVersion = 1;
|
||||
// Version 6 binds every compiled tile page to the world's base density evaluator.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 6;
|
||||
// Version 7 fixes owner/Core chunk mapping and native adjacent-stratum boundaries.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 7;
|
||||
|
||||
enum class FieldChannel : std::uint32_t
|
||||
{
|
||||
|
||||
@@ -47,6 +47,18 @@ public:
|
||||
return static_cast<double>(CHUNK_SIZE) * OwnerVoxelSizeCm / GetCoreVoxelSizeCm();
|
||||
}
|
||||
|
||||
int32 OwnerChunkLowerBoundaryCoreVoxel(int32 ChunkZ) const
|
||||
{
|
||||
return static_cast<int32>(std::floor(
|
||||
static_cast<double>(ChunkZ) * GetCoreVoxelsPerOwnerChunk()));
|
||||
}
|
||||
|
||||
int32 OwnerChunkUpperBoundaryCoreVoxel(int32 ChunkZ) const
|
||||
{
|
||||
return static_cast<int32>(std::ceil(
|
||||
static_cast<double>(ChunkZ) * GetCoreVoxelsPerOwnerChunk()));
|
||||
}
|
||||
|
||||
enum class EDetailVariant : uint8 { Coherent, Smooth, PerVoxel };
|
||||
struct FBoxClassification
|
||||
{
|
||||
@@ -712,14 +724,21 @@ public:
|
||||
if(Owner&&Owner->Manager)
|
||||
{
|
||||
const double TileZ0=Origin.Z,TileZ1=Origin.Z+static_cast<double>(Cells)*Step;
|
||||
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
for(const FStrateSlot& Slot:Owner->Manager->GetLayout())
|
||||
{
|
||||
const int32 MidChunkZ=(Slot.TopChunkZ+Slot.BottomChunkZ)/2;
|
||||
if(bUseNativeManifestFields
|
||||
&&Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,MidChunkZ))
|
||||
==ECaveGeneratorType::FloatingIslands)
|
||||
continue;
|
||||
const FStrateGenerationParams Params=Owner->Manager->GetGenerationParams(
|
||||
FIntVector(0,0,(Slot.TopChunkZ+Slot.BottomChunkZ)/2));
|
||||
FIntVector(0,0,MidChunkZ));
|
||||
const float HalfWidth=static_cast<float>(std::max(8.0,
|
||||
static_cast<double>(Params.BoundarySealThickness)+8.0));
|
||||
const float Boundaries[2]={static_cast<float>(Slot.BottomChunkZ)*CHUNK_SIZE,
|
||||
static_cast<float>(Slot.TopChunkZ+1)*CHUNK_SIZE};
|
||||
const float Boundaries[2]={
|
||||
static_cast<float>(static_cast<double>(Slot.BottomChunkZ)*CoreVoxelsPerOwnerChunk),
|
||||
static_cast<float>(static_cast<double>(Slot.TopChunkZ+1)*CoreVoxelsPerOwnerChunk)};
|
||||
for(const float Z:Boundaries)
|
||||
if(Z+HalfWidth>=TileZ0&&Z-HalfWidth<=TileZ1)
|
||||
Out.stratumBoundaries.push_back({Z,HalfWidth});
|
||||
@@ -1028,19 +1047,21 @@ public:
|
||||
float NativeDensity=0.0f;
|
||||
if(!NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{RecordNativeOnlyViolation();return 0.0f;}
|
||||
return NativeDensity;
|
||||
return ApplyAdjacentStratumBoundary(X,Y,Z,NativeDensity,false);
|
||||
}
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeFloatFieldCalls;
|
||||
return ApplyEditBrushes(IslandDensity,X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
|
||||
X,Y,Z,IslandDensity,true),X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeFloatFieldCalls;
|
||||
return ApplyEditBrushes(NativeDensity,X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
|
||||
X,Y,Z,NativeDensity,false),X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
return LegacySurfaceDensityAt(X,Y,Z);
|
||||
@@ -1064,21 +1085,27 @@ public:
|
||||
if(!NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),NativeDensity))
|
||||
{RecordNativeOnlyViolation();return 0.0f;}
|
||||
return NativeDensity;
|
||||
return ApplyAdjacentStratumBoundary(
|
||||
static_cast<float>(X),static_cast<float>(Y),static_cast<float>(Z),
|
||||
NativeDensity,false);
|
||||
}
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeLatticeFieldCalls;
|
||||
return ApplyEditBrushes(IslandDensity,X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
|
||||
static_cast<float>(X),static_cast<float>(Y),static_cast<float>(Z),
|
||||
IslandDensity,true),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(NativeDensity,X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
|
||||
static_cast<float>(X),static_cast<float>(Y),static_cast<float>(Z),
|
||||
NativeDensity,false),X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z)))
|
||||
@@ -1102,19 +1129,21 @@ public:
|
||||
float NativeDensity=0.0f;
|
||||
if(!NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{RecordNativeOnlyViolation();return 0.0f;}
|
||||
return NativeDensity;
|
||||
return ApplyAdjacentStratumBoundary(X,Y,Z,NativeDensity,false);
|
||||
}
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeUnclampedFieldCalls;
|
||||
return ApplyEditBrushes(IslandDensity,X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
|
||||
X,Y,Z,IslandDensity,true),X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeUnclampedFieldCalls;
|
||||
return ApplyEditBrushes(NativeDensity,X,Y,Z);
|
||||
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
|
||||
X,Y,Z,NativeDensity,false),X,Y,Z);
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
return LegacySurfaceDensityAt(X,Y,Z);
|
||||
@@ -1260,12 +1289,18 @@ private:
|
||||
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
IslandDensity=ApplyAdjacentStratumBoundary(X,Y,Z,IslandDensity,true);
|
||||
return bApplyEdits?ApplyEditBrushes(IslandDensity,X,Y,Z):IslandDensity;
|
||||
}
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
{
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
NativeDensity=ApplyAdjacentStratumBoundary(X,Y,Z,NativeDensity,false);
|
||||
return bApplyEdits?ApplyEditBrushes(NativeDensity,X,Y,Z):NativeDensity;
|
||||
}
|
||||
const float Density=Owner->Generator->GetDensityAt(X,Y,Z);
|
||||
return bApplyEdits?ApplyEditBrushes(Density,X,Y,Z):Density;
|
||||
}
|
||||
@@ -1321,8 +1356,11 @@ public:
|
||||
return SharedDensitySource->GetNativeSurfaceHeightsAt(X,Y,ChunkZ,OutGroundZ,OutCeilingZ);
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
||!std::isfinite(X)||!std::isfinite(Y))return false;
|
||||
const std::int64_t chunkMinimum=static_cast<std::int64_t>(ChunkZ)*CHUNK_SIZE;
|
||||
const std::int64_t chunkMaximum=chunkMinimum+CHUNK_SIZE;
|
||||
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
const std::int64_t chunkMinimum=static_cast<std::int64_t>(std::floor(
|
||||
static_cast<double>(ChunkZ)*CoreVoxelsPerOwnerChunk));
|
||||
const std::int64_t chunkMaximum=static_cast<std::int64_t>(std::ceil(
|
||||
static_cast<double>(ChunkZ+1)*CoreVoxelsPerOwnerChunk));
|
||||
if(bNativeOnly&&(!NativeOnlyContainsColumn(X,Y)
|
||||
||chunkMaximum<NativeOnlyMinimum.Z||chunkMinimum>NativeOnlyMaximum.Z
|
||||
||Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
|
||||
@@ -1344,7 +1382,8 @@ public:
|
||||
const VoxelForgeCore::Heightfield2D Block(WorldAssembly->recipe,*Plan);
|
||||
if(!Block.isValid())return false;
|
||||
const auto Column=Block.point(ToFixed(X),ToFixed(Y),
|
||||
static_cast<int64>(ChunkZ)*CHUNK_SIZE*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||
static_cast<int64>(std::llround(static_cast<double>(ChunkZ)
|
||||
*CoreVoxelsPerOwnerChunk*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)));
|
||||
OutGroundZ=static_cast<float>(Column.groundHeightSubvoxels/Scale);
|
||||
OutCeilingZ=static_cast<float>(Column.capHeightSubvoxels/Scale);
|
||||
return std::isfinite(OutGroundZ)&&std::isfinite(OutCeilingZ);
|
||||
@@ -1360,10 +1399,11 @@ public:
|
||||
const int32 Pad=std::max(Step,1);
|
||||
const int32 BMin=Origin.Z-Pad;
|
||||
const int32 BMax=Origin.Z+(Cells+1)*Step;
|
||||
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin)
|
||||
/static_cast<float>(CHUNK_SIZE));
|
||||
/static_cast<float>(CoreVoxelsPerOwnerChunk));
|
||||
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax)
|
||||
/static_cast<float>(CHUNK_SIZE));
|
||||
/static_cast<float>(CoreVoxelsPerOwnerChunk));
|
||||
const VoxelForgeCore::WorldAssemblyStratumPlanV1* Plan=nullptr;
|
||||
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
|
||||
{
|
||||
@@ -1407,12 +1447,13 @@ public:
|
||||
bool bIslandOtherStrateOverlap=false,bBadPlan=false;
|
||||
if(Owner&&Owner->Manager)
|
||||
{
|
||||
// Keep the delivered SurfaceWorld chunk mapping unchanged.
|
||||
// Conserver le mapping de chunks SurfaceWorld deja livre.
|
||||
// All manifest strata use the same resolved owner-chunk to Core-voxel scale.
|
||||
// Toutes les strates du manifeste partagent l'echelle owner/Core resolue.
|
||||
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
|
||||
/static_cast<float>(CHUNK_SIZE));
|
||||
/static_cast<float>(CoreVoxelsPerOwnerChunk));
|
||||
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax[2])
|
||||
/static_cast<float>(CHUNK_SIZE));
|
||||
/static_cast<float>(CoreVoxelsPerOwnerChunk));
|
||||
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
|
||||
{
|
||||
const ECaveGeneratorType Type=Owner->Manager->GetGeneratorTypeForChunk(
|
||||
@@ -1544,19 +1585,6 @@ public:
|
||||
{
|
||||
if(!IslandPlan)return Finish(EVoxelTileClass::Mixed,true);
|
||||
constexpr std::int64_t Scale=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
||||
const std::int64_t Bottom=IslandPlan->manifest.recipe.layoutMinimumZSubvoxels;
|
||||
const std::int64_t Top=IslandPlan->manifest.recipe.layoutMaximumZSubvoxels;
|
||||
const std::int64_t Seal=IslandPlan->manifest.recipe.boundarySealSubvoxels;
|
||||
const std::int64_t BoxBottom=static_cast<std::int64_t>(BMin[2])*Scale;
|
||||
const std::int64_t BoxTop=static_cast<std::int64_t>(BMax[2])*Scale;
|
||||
const bool bBottomSealOverlap=BoxBottom<Bottom+Seal&&BoxTop>=Bottom;
|
||||
const bool bTopSealOverlap=BoxBottom<=Top&&BoxTop>Top-Seal;
|
||||
if(bBottomSealOverlap)
|
||||
return Finish(BoxBottom>=Bottom&&BoxTop<=Bottom+Seal
|
||||
?EVoxelTileClass::AllSolid:EVoxelTileClass::Mixed);
|
||||
if(bTopSealOverlap)
|
||||
return Finish(BoxBottom>=Top-Seal&&BoxTop<=Top
|
||||
?EVoxelTileClass::AllSolid:EVoxelTileClass::Mixed);
|
||||
const VoxelForgeCore::FloatingIslandFieldV1 Block(
|
||||
IslandPlan->manifest.recipe,IslandPlan->manifest.plan);
|
||||
if(!Block.isValid())return Finish(EVoxelTileClass::Mixed,true);
|
||||
@@ -2079,7 +2107,8 @@ private:
|
||||
{
|
||||
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return false;
|
||||
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CHUNK_SIZE));
|
||||
const int32 ChunkZ=FMath::FloorToInt(Z
|
||||
/static_cast<float>(GetCoreVoxelsPerOwnerChunk()));
|
||||
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
|
||||
!=ECaveGeneratorType::SurfaceWorld)return false;
|
||||
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
|
||||
@@ -2125,23 +2154,79 @@ private:
|
||||
const VoxelForgeCore::FloatingIslandFieldV1 Field(
|
||||
Plan->manifest.recipe,Plan->manifest.plan);
|
||||
if(!Field.isValid())return false;
|
||||
std::int64_t Density=Field.densitySubvoxels(ToFixed(X),ToFixed(Y),ToFixed(Z));
|
||||
const std::int64_t Bottom=Plan->manifest.recipe.layoutMinimumZSubvoxels;
|
||||
const std::int64_t Top=Plan->manifest.recipe.layoutMaximumZSubvoxels;
|
||||
const std::int64_t Seal=Plan->manifest.recipe.boundarySealSubvoxels;
|
||||
const std::int64_t Zq=ToFixed(Z);
|
||||
if(Zq>=Bottom&&Zq<Bottom+Seal)Density=std::min(Density,-std::max<std::int64_t>(1,Zq-Bottom));
|
||||
if(Zq<=Top&&Zq>Top-Seal)Density=std::min(Density,-std::max<std::int64_t>(1,Top-Zq));
|
||||
// The recipe's boundary seal is a feature margin, not a horizontal solid cap.
|
||||
// La marge de scellement du plan borne ses formes, sans remplir tout le plan XY.
|
||||
const std::int64_t Density=Field.densitySubvoxels(ToFixed(X),ToFixed(Y),ToFixed(Z));
|
||||
OutDensity=static_cast<float>(static_cast<double>(Density)/Scale);
|
||||
return std::isfinite(OutDensity);
|
||||
}
|
||||
|
||||
float ApplyAdjacentStratumBoundary(float X,float Y,float Z,float Density,
|
||||
bool bFloatingIsland) const
|
||||
{
|
||||
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager
|
||||
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return Density;
|
||||
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CoreVoxelsPerOwnerChunk));
|
||||
const ECaveGeneratorType CurrentType=Owner->Manager->GetGeneratorTypeForChunk(
|
||||
FIntVector(0,0,ChunkZ));
|
||||
if(bFloatingIsland&&CurrentType==ECaveGeneratorType::FloatingIslands)
|
||||
{
|
||||
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
|
||||
static_cast<float>((static_cast<double>(ChunkZ)*CHUNK_SIZE+CHUNK_SIZE/2)*VOXEL_SIZE));
|
||||
const auto* Plan=FindWorldAssemblyFloatingIslandStratum(StrateIndex,ChunkZ);
|
||||
if(!Plan)return Density;
|
||||
const int32 LowerChunk=Plan->bottomChunkZ-1;
|
||||
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,LowerChunk))
|
||||
!=ECaveGeneratorType::SurfaceWorld)return Density;
|
||||
const double Boundary=static_cast<double>(Plan->bottomChunkZ)
|
||||
*CoreVoxelsPerOwnerChunk;
|
||||
float LowerDensity=0.0f,UpperDensity=0.0f;
|
||||
if(!NativeSurfaceDensityAt(X,Y,static_cast<float>(Boundary-0.5),LowerDensity)
|
||||
||!NativeFloatingIslandDensityAt(X,Y,static_cast<float>(Boundary+0.5),UpperDensity)
|
||||
||(LowerDensity<0.0f)==(UpperDensity<0.0f))return Density;
|
||||
|
||||
// Clip the two signed-distance fields to their shared owner-stratum plane.
|
||||
// This keeps a solid-below/air-above seam continuous at every mesh sample step.
|
||||
// Les deux champs sont limites au plan commun, quel que soit le pas de maillage.
|
||||
const float Plane=static_cast<float>(static_cast<double>(Z)-Boundary);
|
||||
return LowerDensity<0.0f?std::min(Density,Plane)
|
||||
:std::max(Density,-Plane);
|
||||
}
|
||||
if(!bFloatingIsland&&CurrentType==ECaveGeneratorType::SurfaceWorld)
|
||||
{
|
||||
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
|
||||
static_cast<float>((static_cast<double>(ChunkZ)*CHUNK_SIZE+CHUNK_SIZE/2)*VOXEL_SIZE));
|
||||
const auto* Plan=FindWorldAssemblyStratum(StrateIndex,ChunkZ);
|
||||
if(!Plan)return Density;
|
||||
const int32 UpperChunk=Plan->topChunkZ+1;
|
||||
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,UpperChunk))
|
||||
!=ECaveGeneratorType::FloatingIslands)return Density;
|
||||
const auto* UpperPlan=FindWorldAssemblyFloatingIslandStratum(
|
||||
Owner->Manager->GetStrateIndex(static_cast<float>((
|
||||
static_cast<double>(UpperChunk)*CHUNK_SIZE+CHUNK_SIZE/2)*VOXEL_SIZE)),UpperChunk);
|
||||
if(!UpperPlan)return Density;
|
||||
const double Boundary=static_cast<double>(UpperPlan->bottomChunkZ)
|
||||
*CoreVoxelsPerOwnerChunk;
|
||||
float LowerDensity=0.0f,UpperDensity=0.0f;
|
||||
if(!NativeSurfaceDensityAt(X,Y,static_cast<float>(Boundary-0.5),LowerDensity)
|
||||
||!NativeFloatingIslandDensityAt(X,Y,static_cast<float>(Boundary+0.5),UpperDensity)
|
||||
||(LowerDensity<0.0f)==(UpperDensity<0.0f))return Density;
|
||||
|
||||
const float Plane=static_cast<float>(static_cast<double>(Z)-Boundary);
|
||||
return LowerDensity<0.0f?std::max(Density,Plane)
|
||||
:std::min(Density,-Plane);
|
||||
}
|
||||
return Density;
|
||||
}
|
||||
|
||||
bool UsesLegacySurfaceField(float X,float Y,float Z) const
|
||||
{
|
||||
if(!Owner||!Owner->Manager||!Owner->Generator)return false;
|
||||
const FIntVector ChunkCoord(FMath::FloorToInt(X/static_cast<float>(CHUNK_SIZE)),
|
||||
FMath::FloorToInt(Y/static_cast<float>(CHUNK_SIZE)),
|
||||
FMath::FloorToInt(Z/static_cast<float>(CHUNK_SIZE)));
|
||||
const float CoreVoxelsPerOwnerChunk=static_cast<float>(GetCoreVoxelsPerOwnerChunk());
|
||||
const FIntVector ChunkCoord(FMath::FloorToInt(X/CoreVoxelsPerOwnerChunk),
|
||||
FMath::FloorToInt(Y/CoreVoxelsPerOwnerChunk),
|
||||
FMath::FloorToInt(Z/CoreVoxelsPerOwnerChunk));
|
||||
return Owner->Manager->GetGeneratorTypeForChunk(ChunkCoord)
|
||||
==ECaveGeneratorType::SurfaceWorld;
|
||||
}
|
||||
@@ -2351,19 +2436,26 @@ private:
|
||||
int32 Top=MIN_int32,Bottom=MAX_int32;
|
||||
for(const FStrateSlot& Slot:Layout)
|
||||
{
|
||||
const int32 MidChunkZ=(Slot.TopChunkZ+Slot.BottomChunkZ)/2;
|
||||
// A manifest-backed FloatingIslands stratum supplies its own sparse island
|
||||
// field; it must not extend the legacy solid envelope across the open sky.
|
||||
if(bUseNativeManifestFields
|
||||
&&Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,MidChunkZ))
|
||||
==ECaveGeneratorType::FloatingIslands)
|
||||
continue;
|
||||
Top=std::max(Top,Slot.TopChunkZ);Bottom=std::min(Bottom,Slot.BottomChunkZ);
|
||||
if(!Slot.Definition)continue;
|
||||
const int32 MidChunkZ=(Slot.TopChunkZ+Slot.BottomChunkZ)/2;
|
||||
FLayerField Field;
|
||||
Field.Lo=Slot.BottomChunkZ*CHUNK_SIZE;
|
||||
Field.Hi=(Slot.TopChunkZ+1)*CHUNK_SIZE;
|
||||
Field.Lo=OwnerChunkLowerBoundaryCoreVoxel(Slot.BottomChunkZ);
|
||||
Field.Hi=OwnerChunkUpperBoundaryCoreVoxel(Slot.TopChunkZ+1);
|
||||
Field.StrateIndex=Slot.StrateIndex;
|
||||
Field.Params=Owner->Manager->GetGenerationParams(FIntVector(0,0,MidChunkZ));
|
||||
LayerFields.push_back(std::move(Field));
|
||||
}
|
||||
if(Top>=Bottom)
|
||||
{
|
||||
LayerRanges.push_back({Bottom*CHUNK_SIZE,(Top+1)*CHUNK_SIZE});
|
||||
LayerRanges.push_back({OwnerChunkLowerBoundaryCoreVoxel(Bottom),
|
||||
OwnerChunkUpperBoundaryCoreVoxel(Top+1)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3474,8 +3566,9 @@ private:
|
||||
auto Unit=[&](uint32 H){return static_cast<double>(Hash(H)>>8)*(1.0/16777216.0);};
|
||||
for(const FStrateSlot& Slot:Layout)
|
||||
{
|
||||
const double ZBottom=static_cast<double>(Slot.BottomChunkZ)*CHUNK_SIZE;
|
||||
const double ZTop=static_cast<double>(Slot.TopChunkZ+1)*CHUNK_SIZE;
|
||||
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
const double ZBottom=static_cast<double>(Slot.BottomChunkZ)*CoreVoxelsPerOwnerChunk;
|
||||
const double ZTop=static_cast<double>(Slot.TopChunkZ+1)*CoreVoxelsPerOwnerChunk;
|
||||
for(int32 GY=GY0;GY<=GY1;++GY)for(int32 GX=GX0;GX<=GX1;++GX)
|
||||
{
|
||||
uint32 H=Hash(Seed^static_cast<uint32>(GX)*0x9E3779B9u
|
||||
|
||||
@@ -1162,8 +1162,13 @@ namespace VoxelForgeCore
|
||||
|
||||
const std::int64_t tileMinimum[3]={boundsMin.X,boundsMin.Y,boundsMin.Z};
|
||||
const std::int64_t tileMaximum[3]={boundsMax.X,boundsMax.Y,boundsMax.Z};
|
||||
const int32 firstSurfaceChunk=FloorDiv(boundsMin.Z,CHUNK_SIZE);
|
||||
const int32 lastSurfaceChunk=FloorDiv(boundsMax.Z,CHUNK_SIZE);
|
||||
const double coreVoxelsPerOwnerChunk=static_cast<double>(CHUNK_SIZE)
|
||||
*static_cast<double>(impl_->owner->OwnerVoxelSizeMicrons)
|
||||
/static_cast<double>(std::max(1u,impl_->owner->CoreVoxelSizeMicrons));
|
||||
const int32 firstSurfaceChunk=FMath::FloorToInt(
|
||||
static_cast<double>(boundsMin.Z)/coreVoxelsPerOwnerChunk);
|
||||
const int32 lastSurfaceChunk=FMath::FloorToInt(
|
||||
static_cast<double>(boundsMax.Z)/coreVoxelsPerOwnerChunk);
|
||||
const WorldAssemblyStratumPlanV1* selectedPlan=nullptr;
|
||||
for(int32 chunkZ=firstSurfaceChunk;chunkZ<=lastSurfaceChunk;++chunkZ)
|
||||
{
|
||||
@@ -1183,9 +1188,6 @@ namespace VoxelForgeCore
|
||||
if(!selectedPlan||!Heightfield2D(impl_->worldAssembly->recipe,*selectedPlan).isValid())
|
||||
return false;
|
||||
|
||||
const double coreVoxelsPerOwnerChunk=static_cast<double>(CHUNK_SIZE)
|
||||
*static_cast<double>(impl_->owner->OwnerVoxelSizeMicrons)
|
||||
/static_cast<double>(std::max(1u,impl_->owner->CoreVoxelSizeMicrons));
|
||||
const int32 firstIslandChunk=FMath::FloorToInt(
|
||||
static_cast<double>(boundsMin.Z)/coreVoxelsPerOwnerChunk);
|
||||
const int32 lastIslandChunk=FMath::FloorToInt(
|
||||
|
||||
Reference in new issue
Block a user