diff --git a/Source/VoxelForge/Private/VoxelClipmapDesiredTiles.h b/Source/VoxelForge/Private/VoxelClipmapDesiredTiles.h index c3b2876..9834bac 100644 --- a/Source/VoxelForge/Private/VoxelClipmapDesiredTiles.h +++ b/Source/VoxelForge/Private/VoxelClipmapDesiredTiles.h @@ -9,6 +9,8 @@ namespace VoxelClipmapDesiredTiles int32 ClipRadius = 3; int32 MaxClipLevel = 4; int32 RenderDistanceChunks = 0; + // Far sheet ring selection. AVoxelWorld always passes false (the runtime no longer meshes + // sheets); it stays here because the clipmap automation tests still exercise it. bool bFarSheetRing = true; int32 FarSheetSpanLevels = 2; }; diff --git a/Source/VoxelForge/Private/VoxelMarchingCubesMesher.cpp b/Source/VoxelForge/Private/VoxelMarchingCubesMesher.cpp index a5f241d..3c99e88 100644 --- a/Source/VoxelForge/Private/VoxelMarchingCubesMesher.cpp +++ b/Source/VoxelForge/Private/VoxelMarchingCubesMesher.cpp @@ -1126,218 +1126,3 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels, return MeshData; } - -//============================================================================= -// F18 — FEUILLE DE CHAMP LOINTAIN (voir le doc de la déclaration dans le .h) -//============================================================================= -// Deux grilles déplacées (sol + cap) au lieu d'un marching cubes 3D. Conventions IDENTIQUES à -// GenerateMesh : positions monde cm, UVs planaires (voxels), masques F6 par GetBiomeMaterialAt, -// jupes double-face extrudées le long de −N par seau, indices sol‖cap + NumCeilingTriangles. -// Winding : le chemin MC émet (0,2,1) des tables Bourke ⇒ une surface orientée +Z s'écrit -// (x,y) → (x,y+1) → (x+1,y) ; le cap (orienté −Z) inverse. -FVoxelMeshData UVoxelMarchingCubesMesher::GenerateSheetMesh(FIntVector OriginVoxels, int32 StepXY, - int32 CellsXY, int32 StrateChunkZ, - int32 HoleMinXVox, int32 HoleMinYVox, - int32 HoleMaxXVox, int32 HoleMaxYVox) -{ - FVoxelMeshData MeshData; - if (!Generator) return MeshData; - StepXY = FMath::Max(1, StepXY); - CellsXY = FMath::Clamp(CellsXY, 2, 512); - - // TROU XY — cellule [x0, x0+Step]×[y0, y0+Step] entièrement dans le rectangle (Max exclusif) - // ⇒ sautée : la zone est couverte par les coquilles MC (voir VoxelWorld.h SheetHole*). - auto CellInHole = [&](int32 cx, int32 cy) -> bool - { - const int32 X0 = OriginVoxels.X + cx * StepXY; - const int32 Y0 = OriginVoxels.Y + cy * StepXY; - return X0 >= HoleMinXVox && X0 + StepXY <= HoleMaxXVox - && Y0 >= HoleMinYVox && Y0 + StepXY <= HoleMaxYVox; - }; - - const int32 GridDim = CellsXY + 1; // points de grille par axe - const int32 MDim = GridDim + 2; // + anneau de marge ±1 (normales continues entre feuilles) - - // Early-out : la validité SurfaceWorld ne dépend que de ChunkZ (les strates sont des couches - // horizontales) — une sonde suffit. La sentinelle par colonne plus bas reste par prudence. - { - float T0 = 0.0f, C0 = 0.0f; - if (!Generator->GetSurfaceHeightAt((float)OriginVoxels.X, (float)OriginVoxels.Y, - StrateChunkZ, T0, C0)) - { - return MeshData; // pas une strate SurfaceWorld → feuille vide - } - } - - // Colonnes (TerrainZ, CeilSurf) en Z-voxel monde absolu, marge incluse. X==FLT_MAX ⇒ invalide. - static thread_local TArray SheetCols; - SheetCols.SetNumUninitialized(MDim * MDim); - for (int32 gy = -1; gy <= GridDim; ++gy) - { - if (ShouldAbortWork()) return FVoxelMeshData(); - for (int32 gx = -1; gx <= GridDim; ++gx) - { - float Tz = 0.0f, Cz = 0.0f; - const bool bOk = Generator->GetSurfaceHeightAt( - (float)(OriginVoxels.X + gx * StepXY), (float)(OriginVoxels.Y + gy * StepXY), - StrateChunkZ, Tz, Cz); - SheetCols[(gy + 1) * MDim + (gx + 1)] = bOk ? FVector2f(Tz, Cz) - : FVector2f(FLT_MAX, -FLT_MAX); - } - } - auto Col = [&](int32 gx, int32 gy) -> const FVector2f& - { - return SheetCols[(gy + 1) * MDim + (gx + 1)]; - }; - - // Index de vertex par point de grille (−1 = pas créé), sol et cap séparés — le partage de - // vertex est structurel (grille régulière), pas besoin de map de déduplication. - static thread_local TArray GroundIdx; - static thread_local TArray CapIdx; - GroundIdx.Init(-1, GridDim * GridDim); - CapIdx.Init(-1, GridDim * GridDim); - - auto MakeVert = [&](int32 gx, int32 gy, bool bCap) -> int32 - { - int32& Slot = (bCap ? CapIdx : GroundIdx)[gy * GridDim + gx]; - if (Slot >= 0) return Slot; - - const FVector2f C = Col(gx, gy); - const float H = bCap ? C.Y : C.X; - // Pente par différences centrales sur la grille de hauteurs (voxels/voxels — l'échelle cm - // se simplifie). Voisin invalide ⇒ composante plate (ne devrait pas arriver : cf. early-out). - auto HAt = [&](int32 x, int32 y) -> float - { - const FVector2f& N = Col(x, y); - return (N.X == FLT_MAX) ? H : (bCap ? N.Y : N.X); - }; - const float Sx = (HAt(gx + 1, gy) - HAt(gx - 1, gy)) / (2.0f * (float)StepXY); - const float Sy = (HAt(gx, gy + 1) - HAt(gx, gy - 1)) / (2.0f * (float)StepXY); - // Sol : air au-dessus ⇒ normale vers le haut. Cap : l'air (l'intérieur de la strate) est - // EN-DESSOUS ⇒ normale vers le bas (−∇(z − C) = (Cx, Cy, −1)). - FVector Normal = bCap ? FVector(Sx, Sy, -1.0f) : FVector(-Sx, -Sy, 1.0f); - if (!Normal.Normalize()) - { - Normal = FVector(0.0f, 0.0f, bCap ? -1.0f : 1.0f); - } - - const float Xv = (float)(OriginVoxels.X + gx * StepXY); - const float Yv = (float)(OriginVoxels.Y + gy * StepXY); - const FVector WorldPos(Xv * VOXEL_SIZE, Yv * VOXEL_SIZE, H * VOXEL_SIZE); - - Slot = MeshData.Vertices.Num(); - MeshData.Vertices.Add(WorldPos); - MeshData.Normals.Add(Normal); - MeshData.UVs.Add(FVector2D(Xv, Yv)); // == WorldPos.XY / VOXEL_SIZE (convention MC) - - // Mêmes masques F6 que GenerateMesh (palette biome dominant/voisin, pente, fondu). - int32 PalD = 0, PalN = 0; float BlendW = 0.0f; - Generator->GetBiomeMaterialAt(Xv, Yv, H, PalD, PalN, BlendW); - const uint8 Rr = (uint8)FMath::Clamp(PalD, 0, 255); - const uint8 Aa = (uint8)FMath::Clamp(PalN, 0, 255); - const uint8 Gg = (uint8)FMath::Clamp(FMath::RoundToInt((1.0f - FMath::Abs((float)Normal.Z)) * 255.0f), 0, 255); - const uint8 Bb = (uint8)FMath::Clamp(FMath::RoundToInt(BlendW * 255.0f), 0, 255); - MeshData.Colors.Add(FColor(Rr, Gg, Bb, Aa)); - - return Slot; - }; - - static thread_local TArray SheetGroundTris; - static thread_local TArray SheetCapTris; - SheetGroundTris.Reset(); - SheetCapTris.Reset(); - - for (int32 cy = 0; cy < CellsXY; ++cy) - { - if (ShouldAbortWork()) return FVoxelMeshData(); - for (int32 cx = 0; cx < CellsXY; ++cx) - { - if (CellInHole(cx, cy)) continue; // couverte par les coquilles MC proches - if (Col(cx, cy).X == FLT_MAX || Col(cx + 1, cy).X == FLT_MAX || - Col(cx, cy + 1).X == FLT_MAX || Col(cx + 1, cy + 1).X == FLT_MAX) - { - continue; - } - - // SOL (polygroup 0) — orienté +Z. - const int32 g00 = MakeVert(cx, cy, false); - const int32 g10 = MakeVert(cx + 1, cy, false); - const int32 g01 = MakeVert(cx, cy + 1, false); - const int32 g11 = MakeVert(cx + 1, cy + 1, false); - SheetGroundTris.Add(g00); SheetGroundTris.Add(g01); SheetGroundTris.Add(g10); - SheetGroundTris.Add(g10); SheetGroundTris.Add(g01); SheetGroundTris.Add(g11); - - // CAP (polygroup 1) — orienté −Z ⇒ winding inversé. - const int32 c00 = MakeVert(cx, cy, true); - const int32 c10 = MakeVert(cx + 1, cy, true); - const int32 c01 = MakeVert(cx, cy + 1, true); - const int32 c11 = MakeVert(cx + 1, cy + 1, true); - SheetCapTris.Add(c00); SheetCapTris.Add(c10); SheetCapTris.Add(c01); - SheetCapTris.Add(c10); SheetCapTris.Add(c11); SheetCapTris.Add(c01); - } - } - - // JUPES périmètre — mêmes règles que le chemin MC : extrusion le long de −N (vers le solide : - // bas pour le sol, HAUT pour le cap), double face, émises PAR SEAU (héritent le polygroup). - // Entre feuilles voisines les coins coïncident (mêmes échantillons monde) → pas de fissure ; - // la jupe couvre surtout la couture feuille ↔ anneau MC et les décalages de niveau. - if (bGenerateSkirts && (SheetGroundTris.Num() + SheetCapTris.Num()) > 0) - { - const float SkirtDepth = FMath::Max(1.0f, SkirtCells) * (float)StepXY * VOXEL_SIZE; - - auto EmitEdgeSkirt = [&](int32 ax, int32 ay, int32 bx, int32 by, bool bCap, TArray& Tris) - { - if (Col(ax, ay).X == FLT_MAX || Col(bx, by).X == FLT_MAX) return; - const int32 iA = MakeVert(ax, ay, bCap); - const int32 iB = MakeVert(bx, by, bCap); - // COPIES par valeur — les Add ci-dessous réallouent Vertices/Normals/Colors. - const FVector PA = MeshData.Vertices[iA], PB = MeshData.Vertices[iB]; - const FVector NA = MeshData.Normals[iA], NB = MeshData.Normals[iB]; - const FColor CA = MeshData.Colors[iA], CB = MeshData.Colors[iB]; - - const int32 iA2 = MeshData.Vertices.Num(); - MeshData.Vertices.Add(PA - NA * SkirtDepth); - MeshData.Normals.Add(NA); - MeshData.UVs.Add(FVector2D(PA.X / VOXEL_SIZE, PA.Y / VOXEL_SIZE)); - MeshData.Colors.Add(CA); - const int32 iB2 = MeshData.Vertices.Num(); - MeshData.Vertices.Add(PB - NB * SkirtDepth); - MeshData.Normals.Add(NB); - MeshData.UVs.Add(FVector2D(PB.X / VOXEL_SIZE, PB.Y / VOXEL_SIZE)); - MeshData.Colors.Add(CB); - - Tris.Add(iA); Tris.Add(iB); Tris.Add(iB2); - Tris.Add(iA); Tris.Add(iB2); Tris.Add(iA2); - Tris.Add(iA); Tris.Add(iB2); Tris.Add(iB); - Tris.Add(iA); Tris.Add(iA2); Tris.Add(iB2); - }; - - // Une jupe n'est émise que si la cellule de bord adjacente a réellement été maillée - // (pas dans le trou XY) — sinon mur flottant sans surface. - for (int32 c = 0; c < CellsXY; ++c) - { - if (ShouldAbortWork()) return FVoxelMeshData(); - for (int32 Pass = 0; Pass < 2; ++Pass) - { - const bool bCap = (Pass == 1); - TArray& Tris = bCap ? SheetCapTris : SheetGroundTris; - if (!CellInHole(c, 0)) - EmitEdgeSkirt(c, 0, c + 1, 0, bCap, Tris); // bord Y-min - if (!CellInHole(c, CellsXY - 1)) - EmitEdgeSkirt(c, CellsXY, c + 1, CellsXY, bCap, Tris); // bord Y-max - if (!CellInHole(0, c)) - EmitEdgeSkirt(0, c, 0, c + 1, bCap, Tris); // bord X-min - if (!CellInHole(CellsXY - 1, c)) - EmitEdgeSkirt(CellsXY, c, CellsXY, c + 1, bCap, Tris); // bord X-max - } - } - } - - // Concatène sol PUIS cap : un run d'indices contigu par polygroup (contrat F17/BuildTileStreamSet). - MeshData.Triangles.Reserve(SheetGroundTris.Num() + SheetCapTris.Num()); - MeshData.Triangles.Append(SheetGroundTris); - MeshData.Triangles.Append(SheetCapTris); - MeshData.NumCeilingTriangles = SheetCapTris.Num() / 3; - - return MeshData; -} diff --git a/Source/VoxelForge/Private/VoxelWorld.cpp b/Source/VoxelForge/Private/VoxelWorld.cpp index aa8588f..3b16b2e 100644 --- a/Source/VoxelForge/Private/VoxelWorld.cpp +++ b/Source/VoxelForge/Private/VoxelWorld.cpp @@ -59,7 +59,6 @@ #include "Serialization/JsonWriter.h" #include "ProfilingDebugging/CpuProfilerTrace.h" // Unreal Insights scopes (Perf 0) -static int32 VF_MaxMarchingCubesLevel(const UVoxelSettings* Settings); static bool VF_TileOverlapsVoxelBounds(const FVoxelTileKey& Tile, const FVector& BoundsMin, const FVector& BoundsMax); static bool VF_TileFootprintsOverlap(const FVoxelTileKey& A, const FVoxelTileKey& B); @@ -2232,7 +2231,7 @@ void AVoxelWorld::ConfigureHeadlessStreamingTest() void AVoxelWorld::RecordTileHash(const FVoxelTileKey& Tile, const FIntVector& OriginVoxels, int32 Step, int32 Cells, int32 BandChunkLo, int32 BandChunkHi, - bool bSheetTile, const FVoxelMeshData& MeshData) + const FVoxelMeshData& MeshData) { if (!bTileHashDumpEnabled) { @@ -2246,7 +2245,6 @@ void AVoxelWorld::RecordTileHash(const FVoxelTileKey& Tile, const FIntVector& Or Record.Cells = Cells; Record.BandChunkLo = BandChunkLo; Record.BandChunkHi = BandChunkHi; - Record.bSheetTile = bSheetTile; Record.bEmpty = MeshData.IsEmpty(); Record.NumTriangles = MeshData.Triangles.Num() / 3; Record.GeometryHash = VoxelForgeGeometryHash::Compute(MeshData); @@ -2315,7 +2313,8 @@ void AVoxelWorld::WriteTileHashDump() Writer->WriteValue(TEXT("cells"), Record.Cells); Writer->WriteValue(TEXT("band_chunk_lo"), Record.BandChunkLo); Writer->WriteValue(TEXT("band_chunk_hi"), Record.BandChunkHi); - Writer->WriteValue(TEXT("sheet_tile"), Record.bSheetTile); + // The parity harness still compares this field; the runtime has no sheet tiles. + Writer->WriteValue(TEXT("sheet_tile"), false); Writer->WriteValue(TEXT("empty"), Record.bEmpty); Writer->WriteValue(TEXT("triangle_count"), Record.NumTriangles); Writer->WriteValue(TEXT("geometry_hash"), Record.GeometryHash); @@ -4577,12 +4576,11 @@ void AVoxelWorld::Tick(float DeltaTime) const double SpanZ = static_cast(Max.Z - Min.Z + 1) * TileExtentMetres; VoxelForgeStartupTrace::RecordEvent(TEXT("steady_desired_level"), FString::Printf( TEXT("\"level\":%d,\"tiles\":%d,\"min_coord\":[%d,%d,%d],\"max_coord\":[%d,%d,%d]," - "\"tile_extent_m\":%s,\"coverage_extent_m\":[%s,%s,%s],\"sheet\":%d"), + "\"tile_extent_m\":%s,\"coverage_extent_m\":[%s,%s,%s]"), Level, SteadyLevelCounts.FindChecked(Level), Min.X, Min.Y, Min.Z, Max.X, Max.Y, Max.Z, *FString::SanitizeFloat(TileExtentMetres), - *FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ), - Settings && Level > VF_MaxMarchingCubesLevel(Settings) ? 1 : 0)); + *FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ))); VoxelForgeStartupTrace::RecordEvent(TEXT("steady_loaded_level"), FString::Printf( TEXT("\"level\":%d,\"tiles\":%d,\"vertices\":%llu,\"triangles\":%llu,\"geometry_bytes\":%llu"), Level, LoadedLevelCounts.FindRef(Level), @@ -6217,8 +6215,7 @@ void AVoxelWorld::SyncRemeshTile(const FVoxelTileKey& Tile) Result.GenerationStartCycles = GenerateStartCycles; GenerateTileResult(Tile, OriginVoxels, Step, Cells, GenerationEpoch, /*bWantCapture*/ false, BandVoxLo, BandVoxHi, BandChunkLo, BandChunkHi, - /*bSheetTile*/ false, /*SheetChunkZ*/ 0, - /*Hole*/ 0, 0, 0, 0, Result, nullptr); // hole unused (not a sheet tile) + Result, nullptr); Result.GenerationEndCycles = GenerateStartCycles != 0 ? FPlatformTime::Cycles64() : 0; @@ -6471,30 +6468,18 @@ static FORCEINLINE FIntVector VF_FloorDiv(const FIntVector& V, int32 D) return FIntVector(VF_FloorDiv(V.X, D), VF_FloorDiv(V.Y, D), VF_FloorDiv(V.Z, D)); } -// F18 — the outer shell is either the MC render-distance level or the larger sheet ring. When -// the sheet span skips levels, VF_MaxMarchingCubesLevel fills them with MC bridge shells. -// Shared by desired selection and range culling so both use the same outer horizon. +// The outer shell is the MaxClipLevel ring stretched to RenderDistanceChunks. Shared by desired +// selection and range culling so both use the same outer horizon. The selector's far sheet ring +// is not part of the runtime, so it is always switched off here. static FORCEINLINE void VF_OuterShell(const UVoxelSettings* Settings, int32 R, int32 MaxLevel, int32& OutLevel, int32& OutRadius) { VoxelClipmapDesiredTiles::FParameters Parameters; Parameters.RenderDistanceChunks = Settings ? Settings->RenderDistanceChunks : 0; - Parameters.bFarSheetRing = Settings && Settings->bFarSheetRing; - Parameters.FarSheetSpanLevels = Settings ? Settings->FarSheetSpanLevels : 2; + Parameters.bFarSheetRing = false; VoxelClipmapDesiredTiles::OuterShell(Parameters, R, MaxLevel, OutLevel, OutRadius); } -// When an expanded sheet ring skips LOD levels, keep an MC bridge at every intervening level. -static int32 VF_MaxMarchingCubesLevel(const UVoxelSettings* Settings) -{ - const int32 Radius = Settings ? FMath::Max(1, Settings->ClipRadius) : 3; - const int32 MaxLevel = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4; - int32 OuterLevel = MaxLevel, OuterRadius = Radius; - VF_OuterShell(Settings, Radius, MaxLevel, OuterLevel, OuterRadius); - (void)OuterRadius; - return OuterLevel > MaxLevel ? OuterLevel - 1 : MaxLevel; -} - void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& PlayerPosition, APawn* PlayerPawn, const FVector& PlayerHeading, TArray& OutLeavers) @@ -6512,8 +6497,7 @@ void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& Pla const int32 R = Settings ? FMath::Max(1, Settings->ClipRadius) : 3; const int32 MaxLevel = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4; - // Render-distance tiles expand horizontally. The sheet ring retains its configured span; - // intermediate levels are emitted as marching-cubes bridge shells below it. + // Render-distance tiles expand horizontally. // IsTileInClipRange shares the outer-shell calculation so culling sees this same horizon. int32 StrateTopZ = 0, StrateBottomZ = 0; bool bHasStrate = false; @@ -6537,8 +6521,7 @@ void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& Pla TileParameters.ClipRadius = R; TileParameters.MaxClipLevel = MaxLevel; TileParameters.RenderDistanceChunks = Settings ? Settings->RenderDistanceChunks : 0; - TileParameters.bFarSheetRing = Settings && Settings->bFarSheetRing; - TileParameters.FarSheetSpanLevels = Settings ? Settings->FarSheetSpanLevels : 2; + TileParameters.bFarSheetRing = false; VoxelClipmapDesiredTiles::Build(Center, ZLo, ZHi, TileParameters, DesiredSorted); for (const FVoxelTileKey& Key : DesiredSorted) { @@ -6681,10 +6664,10 @@ void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& Pla DesiredTransitionMaxLevel = FMath::Max(DesiredTransitionMaxLevel, Pair.Key.Level); } // A worker from the previous desired epoch can finish late with a component at a level no - // longer present in TileComponents when this index is built. Index through the supported - // maximum sheet level (MaxClipLevel 8 + FarSheetSpanLevels 4) so that such a retired tile still + // longer present in TileComponents when this index is built. Index through the highest + // possible tile level (MaxClipLevel is clamped to 8) so that such a retired tile still // finds all of its desired descendants when the result is reconciled. - constexpr int32 MaxSupportedTileLevel = 12; + constexpr int32 MaxSupportedTileLevel = 8; const int32 DescendantIndexMaxLevel = FMath::Max( DesiredTransitionMaxLevel, MaxSupportedTileLevel); for (const FVoxelTileKey& Key : DesiredSorted) @@ -6727,7 +6710,7 @@ void AVoxelWorld::CancelObsoleteTileWork() } // Fold every registered anchor's small level-0 box into the current desired set (§9.3). Runs inside -// BuildDesiredTiles after the player clipmap + sheet ring, keyed on the same DesiredStamp so the leaver +// BuildDesiredTiles after the player clipmap, keyed on the same DesiredStamp so the leaver // sweep + delta cull handle anchor tiles leaving. Level-0 only (collision lives on level-0 tiles); empty // tiles in the box are ~free (the trivial-tile reject skips gen). Dedup vs the player clipmap by stamp. // §9.4: a tile the player clipmap did NOT stamp (bNew) that only a CollisionOnly anchor wants goes into @@ -6839,7 +6822,7 @@ void AVoxelWorld::UnregisterStreamingAnchor(AActor* Actor) bool AVoxelWorld::IsTileInClipRange(const FVoxelTileKey& Tile, const FIntVector& Center) const { // In range = the tile's centre falls within the OUTERMOST shell (VF_OuterShell — the - // render-distance/sheet-ring level+radius, same as BuildDesiredTiles). A loaded-but-not- + // render-distance level+radius, same as BuildDesiredTiles). A loaded-but-not- // desired tile in range is mid-LOD-transition (wait for its replacement); one out of range // has left the view entirely (cull immediately). const int32 R = Settings ? FMath::Max(1, Settings->ClipRadius) : 3; @@ -7021,13 +7004,13 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw const double SpanZ = static_cast(Summary.Max.Z - Summary.Min.Z + 1) * TileExtentMetres; VoxelForgeStartupTrace::RecordEvent(TEXT("desired_level"), FString::Printf( TEXT("\"level\":%d,\"tiles\":%d,\"min_coord\":[%d,%d,%d],\"max_coord\":[%d,%d,%d]," - "\"tile_extent_m\":%s,\"coverage_extent_m\":[%s,%s,%s],\"sheet\":%d"), + "\"tile_extent_m\":%s,\"coverage_extent_m\":[%s,%s,%s]"), Summary.Level, Summary.Count, Summary.Min.X, Summary.Min.Y, Summary.Min.Z, - Summary.Max.X, Summary.Max.Y, Summary.Max.Z, - *FString::SanitizeFloat(TileExtentMetres), - *FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ), - Settings && Summary.Level > VF_MaxMarchingCubesLevel(Settings) ? 1 : 0)); + Summary.Max.X, Summary.Max.Y, Summary.Max.Z, + *FString::SanitizeFloat(TileExtentMetres), + *FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), + *FString::SanitizeFloat(SpanZ))); } bStartupTraceDesiredRecorded = true; } @@ -7044,13 +7027,8 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw // either way; everything else re-gens in place via BandRemeshQueue (no visual pop). { const int32 CutMin = Settings ? Settings->GetEffectiveStrateContentCutMinLevel() : 9; - // F18 — l'anneau feuille dépend aussi de la bande (sa strate de référence) : on l'arme - // dès que les feuilles sont actives, même si la coupe de contenu MC est désactivée. - const bool bSheetsWantBand = Settings && Settings->bFarSheetRing - && Settings->RenderDistanceChunks > 0; - const int32 TopMC = VF_MaxMarchingCubesLevel(Settings); int32 NewLo = MIN_int32, NewHi = MAX_int32; - if ((CutMin <= 8 || bSheetsWantBand) && StrateManager) + if (CutMin <= 8 && StrateManager) { int32 StrTopZ = 0, StrBotZ = 0; if (StrateManager->GetStrateChunkZBounds(CenterChunk.Z, StrTopZ, StrBotZ)) @@ -7069,8 +7047,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw NewLo, NewHi, MeshBandChunkLo, MeshBandChunkHi, CutMin, CenterChunk.Z); for (const FVoxelTileKey& T : LoadedTiles) { - // Sheets (above the last MC bridge level) always depend on the strate band. - if (T.Level < CutMin && T.Level <= TopMC) continue; + if (T.Level < CutMin) continue; const int32 CLo = T.Coord.Z << T.Level; const int32 CHi = ((T.Coord.Z + 1) << T.Level) - 1; const bool bInOld = CLo >= MeshBandChunkLo && CHi <= MeshBandChunkHi; @@ -7087,44 +7064,6 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw } } - // The sheet XY hole follows the outermost MC bridge level and shrinks by one tile, leaving - // an overlap at the mesh transition. Requeue sheets overlapping either the old or new hole - // when the player crosses a bridge-level tile. - { - int32 NewMinX = MAX_int32, NewMinY = MAX_int32; - int32 NewMaxX = MIN_int32, NewMaxY = MIN_int32; - const int32 TopMCLvl = VF_MaxMarchingCubesLevel(Settings); - if (Settings && Settings->bFarSheetRing && Settings->RenderDistanceChunks > 0) - { - const int32 RClip = FMath::Max(1, Settings->ClipRadius); - const int32 Shrink = FMath::Max(0, RClip - 1); - const int32 ExtM = CHUNK_SIZE << TopMCLvl; // tuile MaxLevel en voxels - const FIntVector CM = VF_FloorDiv(CenterChunk, 1 << TopMCLvl); // tuile MaxLevel du joueur - NewMinX = (CM.X - Shrink) * ExtM; - NewMinY = (CM.Y - Shrink) * ExtM; - NewMaxX = (CM.X + Shrink + 1) * ExtM; // EXCLUSIF - NewMaxY = (CM.Y + Shrink + 1) * ExtM; - } - if (NewMinX != SheetHoleMinXVox || NewMinY != SheetHoleMinYVox - || NewMaxX != SheetHoleMaxXVox || NewMaxY != SheetHoleMaxYVox) - { - for (const FVoxelTileKey& T : LoadedTiles) - { - if (T.Level <= TopMCLvl) continue; // seules les feuilles portent le trou - const int32 Ext = CHUNK_SIZE << T.Level; - const int32 TMinX = T.Coord.X * Ext, TMinY = T.Coord.Y * Ext; - const bool bOldOv = TMinX < SheetHoleMaxXVox && TMinX + Ext > SheetHoleMinXVox - && TMinY < SheetHoleMaxYVox && TMinY + Ext > SheetHoleMinYVox; - const bool bNewOv = TMinX < NewMaxX && TMinX + Ext > NewMinX - && TMinY < NewMaxY && TMinY + Ext > NewMinY; - if ((bOldOv || bNewOv) && IsDesired(T)) BandRemeshQueue.Add(T); - } - SheetHoleMinXVox = NewMinX; SheetHoleMinYVox = NewMinY; - SheetHoleMaxXVox = NewMaxX; SheetHoleMaxYVox = NewMaxY; - bAllChunksLoaded = false; - } - } - // Cull rules — STRICT LOAD-BEFORE-UNLOAD so crossing a shell boundary NEVER leaves a hole: // - out of clip range → left the view entirely, no replacement coming → cull now. // - in range (mid-LOD-transition) → cull ONLY once EVERY desired tile that overlaps its @@ -7391,20 +7330,9 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor const int32 FullRes = Settings ? FMath::Max(1, Settings->FullResClipLevels) : 2; const int32 Extent = CHUNK_SIZE << Tile.Level; - // F18 — sheet-ring keys follow the last MC bridge level and mesh as two heightfields - // (GenerateSheetMesh). Their sampling step matches that MC level; cells grow with sheet extent - // up to 128 per axis, after which the step increases. - const int32 TopMC = VF_MaxMarchingCubesLevel(Settings); - const bool bSheetTile = Tile.Level > TopMC; - - int32 Cells = (Tile.Level < FullRes) + const int32 Cells = (Tile.Level < FullRes) ? CHUNK_SIZE : (Settings ? FMath::Clamp(Settings->CoarseTileCells, 4, CHUNK_SIZE) : 16); - if (bSheetTile) - { - const int32 StepMC = FMath::Max(1, (CHUNK_SIZE << TopMC) / Cells); - Cells = FMath::Clamp(Extent / StepMC, 4, 128); - } const int32 Step = FMath::Max(1, Extent / Cells); const uint32 TaskEpoch = GenerationEpoch; const uint32 TaskDesiredEpoch = DesiredEpoch; @@ -7425,40 +7353,8 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor // below the configured minimum and all LODs in the gap (no band) mesh full. int32 BandVoxLo = INT32_MIN, BandVoxHi = INT32_MAX; int32 BandChunkLo = MIN_int32, BandChunkHi = MAX_int32; - int32 SheetChunkZ = 0; - if (bSheetTile) - { - // F18 — la feuille a besoin de la STRATE de référence (les deux heightfields sont ceux de - // la strate du joueur) : pas de bande armée (gap inter-strates, ou bounds introuvables) - // ⇒ rien à mailler, tuile vide (re-queue automatique via BandRemeshQueue en atterrissant). - if (MeshBandChunkLo == MIN_int32) - { - FChunkResult Empty; - Empty.Tile = Tile; - Empty.Epoch = TaskEpoch; - Empty.DesiredEpoch = TaskDesiredEpoch; - Empty.ModificationEpoch = TaskModificationEpoch; - Empty.RequestStartCycles = RequestStartCycles; - Empty.WorkPriority = WorkPriority; - if (WorkPriority == EVoxelTileWorkPriority::CollisionCritical) - CriticalProcessQueue.Enqueue(MoveTemp(Empty)); - else if (WorkPriority == EVoxelTileWorkPriority::Edited) - EditedProcessQueue.Enqueue(MoveTemp(Empty)); - else if (WorkPriority == EVoxelTileWorkPriority::LOD0) - NearProcessQueue.Enqueue(MoveTemp(Empty)); - else - ProcessQueue.Enqueue(MoveTemp(Empty)); - return; - } - BandChunkLo = MeshBandChunkLo; // pour la résolution matériaux sol/cap dans ApplyMeshToTile - BandChunkHi = MeshBandChunkHi; - SheetChunkZ = MeshBandChunkLo + (MeshBandChunkHi - MeshBandChunkLo) / 2; // chunk au cœur de la strate - } - // F18 — trou XY courant (zone couverte par les coquilles MC, découpée des feuilles). - const int32 HoleMinX = SheetHoleMinXVox, HoleMinY = SheetHoleMinYVox; - const int32 HoleMaxX = SheetHoleMaxXVox, HoleMaxY = SheetHoleMaxYVox; const int32 CutMin = Settings ? Settings->GetEffectiveStrateContentCutMinLevel() : 9; - if (!bSheetTile && Tile.Level >= CutMin && MeshBandChunkLo != MIN_int32) + if (Tile.Level >= CutMin && MeshBandChunkLo != MIN_int32) { BandChunkLo = MeshBandChunkLo; BandChunkHi = MeshBandChunkHi; @@ -7512,7 +7408,6 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor : UE::Tasks::ETaskPriority::BackgroundNormal; UE::Tasks::Launch(TEXT("ChunkGen"), [this, Tile, OriginVoxels, Step, Cells, TaskEpoch, bWantCapture, BandVoxLo, BandVoxHi, BandChunkLo, BandChunkHi, - bSheetTile, SheetChunkZ, HoleMinX, HoleMinY, HoleMaxX, HoleMaxY, RequestStartCycles, TaskDesiredEpoch, TaskModificationEpoch, Cancellation, WorkPriority]() { @@ -7565,7 +7460,6 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor Result.GenerationStartCycles = GenerationStartCycles; GenerateTileResult(Tile, OriginVoxels, Step, Cells, TaskEpoch, bWantCapture, BandVoxLo, BandVoxHi, BandChunkLo, BandChunkHi, - bSheetTile, SheetChunkZ, HoleMinX, HoleMinY, HoleMaxX, HoleMaxY, Result, &Cancellation->bObsolete); Result.GenerationEndCycles = GenerationStartCycles != 0 ? FPlatformTime::Cycles64() : 0; @@ -7611,8 +7505,6 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector& OriginVoxels, int32 Step, int32 Cells, uint32 Epoch, bool bWantCapture, int32 BandVoxLo, int32 BandVoxHi, int32 BandChunkLo, int32 BandChunkHi, - bool bSheetTile, int32 SheetChunkZ, - int32 HoleMinX, int32 HoleMinY, int32 HoleMaxX, int32 HoleMaxY, FChunkResult& Result, const std::atomic* ObsoleteFlag) { @@ -7666,7 +7558,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector / static_cast(WormEligibleSamples) : 0.0; UE_LOG(LogTemp, Display, - TEXT("[VoxelForgeTileProfile] tile=(%d,%d,%d) level=%d step=%d cells=%d sheet=%d aborted=%d empty=%d triangles=%d ceiling_triangles=%d " + TEXT("[VoxelForgeTileProfile] tile=(%d,%d,%d) level=%d step=%d cells=%d aborted=%d empty=%d triangles=%d ceiling_triangles=%d " "band=(%d,%d) " "verdict=%d proof=%d air_proof=%d classify=%.6f mesh=%.6f streams=%.6f seconds=%.6f " "cache_build=%.6f evaluation=%.6f " @@ -7686,7 +7578,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector "worm_eligible=%llu worm_block_proofs=%llu worm_block_skipped=%llu " "worm_skip_rate=%.6f"), Tile.Coord.X, Tile.Coord.Y, Tile.Coord.Z, Tile.Level, Step, Cells, - bSheetTile ? 1 : 0, Result.bAborted ? 1 : 0, + Result.bAborted ? 1 : 0, Result.bEmpty ? 1 : 0, Result.NumTriangles, Result.NumCeilingTriangles, BandChunkLo, BandChunkHi, ClassifyVerdict, Result.bSealedSolidProof ? 1 : 0, @@ -7825,7 +7717,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector // (Gate IsoLevel == 0 : les verdicts du classifieur supposent l'iso MC à zéro exactement.) bool bTrivialEmpty = false; if (GVoxelForgeSealedSolidProof != 0 - && !bSheetTile && !bWantCapture && Generator && Mesher + && !bWantCapture && Generator && Mesher && Mesher->IsoLevel == 0.0f) { TotalSealedSolidProofCandidates.fetch_add(1, std::memory_order_relaxed); @@ -7867,7 +7759,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector } const int32 OuterClassifierMode = FMath::Clamp(GVoxelForgeOuterClassifierMode, 0, 1); if (!bTrivialEmpty && OuterClassifierMode != 0 - && !bSheetTile && !bWantCapture && Generator && Mesher && Mesher->IsoLevel == 0.0f) + && !bWantCapture && Generator && Mesher && Mesher->IsoLevel == 0.0f) { TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_ClassifyTile); INC_DWORD_STAT(STAT_VoxelForgeTilesClassified); @@ -7972,8 +7864,6 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector bTrivialEmpty = (ValidatedVerdict != EVoxelTileClass::Mixed); } - // F18 — feuille : deux heightfields sol/cap échantillonnés par colonne (pas de marching - // cubes, pas de classifieur — la classe de surface est vraie par construction). // `TilesMeshed` peut dépasser `TilesClassified` : les tuiles qui ratent cette porte sont // maillées sans classification. / `TilesMeshed` may exceed `TilesClassified`: tiles that // fail this gate are meshed without classification. @@ -7982,13 +7872,10 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector { TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_GenerateMesh); const double MeshStartSeconds = bMeasureTile ? FPlatformTime::Seconds() : 0.0; - MeshData = bSheetTile - ? Mesher->GenerateSheetMesh(OriginVoxels, Step, Cells, SheetChunkZ, - HoleMinX, HoleMinY, HoleMaxX, HoleMaxY) - : Mesher->GenerateMesh(OriginVoxels, Step, Cells, - bWantCapture ? &Result.CaptureGrid : nullptr, - BandVoxLo, BandVoxHi, - &Result.MesherDensityCalls); + MeshData = Mesher->GenerateMesh(OriginVoxels, Step, Cells, + bWantCapture ? &Result.CaptureGrid : nullptr, + BandVoxLo, BandVoxHi, + &Result.MesherDensityCalls); TotalMesherDensityCalls.fetch_add( static_cast(Result.MesherDensityCalls), std::memory_order_relaxed); MeshSeconds = bMeasureTile ? FPlatformTime::Seconds() - MeshStartSeconds : 0.0; @@ -8041,7 +7928,7 @@ void AVoxelWorld::GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector // Parity instrumentation observes the same FVoxelMeshData that the runtime stream builder // consumes. It is intentionally after the abort fence, so a canceled worker cannot publish a // partial identity, and it records empty/proof tiles as well as visible meshes. - RecordTileHash(Tile, OriginVoxels, Step, Cells, BandChunkLo, BandChunkHi, bSheetTile, MeshData); + RecordTileHash(Tile, OriginVoxels, Step, Cells, BandChunkLo, BandChunkHi, MeshData); Result.ClassifySeconds = ClassifySeconds; Result.MeshSeconds = MeshSeconds; diff --git a/Source/VoxelForge/Public/VoxelMarchingCubesMesher.h b/Source/VoxelForge/Public/VoxelMarchingCubesMesher.h index 098644e..32e2f44 100644 --- a/Source/VoxelForge/Public/VoxelMarchingCubesMesher.h +++ b/Source/VoxelForge/Public/VoxelMarchingCubesMesher.h @@ -78,35 +78,6 @@ public: int32 BandZMinVox = INT32_MIN, int32 BandZMaxVox = INT32_MAX, int64* OutDensitySampleCount = nullptr); - /** - * F18 — FEUILLE de champ lointain (anneau render-distance, cf. UVoxelSettings::bFarSheetRing). - * Dans une strate ouverte (SurfaceWorld) le champ lointain est exactement DEUX heightfields — - * TerrainZ (sol) et CeilSurf (plafond sky-cap), déjà calculés par colonne par l'oracle - * GetSurfaceHeightAt. On construit donc deux grilles déplacées régulières au lieu d'un marching - * cubes 3D : sol = polygroup 0, cap = polygroup 1 (classes vraies PAR CONSTRUCTION — pas de vote, - * pas de sonde de classification), mêmes conventions que GenerateMesh (positions monde cm, UVs - * planaires, masques couleur F6 biome/pente/fondu, normales du gradient de hauteur, jupes - * périmètre par seau, run d'indices sol‖cap + NumCeilingTriangles). - * - * @param OriginVoxels - Coin min de la tuile (voxels). Seul XY est utilisé (les hauteurs sont absolues). - * @param StepXY - Pas d'échantillonnage XY en voxels (aligné sur l'anneau MC pour la continuité). - * @param CellsXY - Cellules par axe XY (extent = CellsXY × StepXY). - * @param StrateChunkZ - Chunk Z DANS la strate de référence (le cœur de la bande) — identifie la - * strate dont on maille sol+cap. Hors SurfaceWorld ⇒ mesh vide. - * @param HoleMin/MaxX/YVox - TROU XY (voxels, Max EXCLUSIF ; sentinelles MAX/MIN = pas de trou) : - * les cellules ENTIÈREMENT dans ce rectangle (la zone couverte par les - * coquilles MC autour du joueur) sont sautées — sinon la feuille recouvre - * le terrain proche avec son échantillonnage grossier. Les cellules à - * cheval restent (anneau de recouvrement au raccord) ; pas de jupe sur - * les bords du trou (le terrain MC remplit derrière). - * Non couvert (accepté, cf. fable-idea F18) : passages/spine/chasms creusés (le heightfield pur ne - * les contient pas), diff layer — invisibles à distance de feuille, l'anneau MC proche les garde. - */ - FVoxelMeshData GenerateSheetMesh(FIntVector OriginVoxels, int32 StepXY, int32 CellsXY, - int32 StrateChunkZ, - int32 HoleMinXVox = INT32_MAX, int32 HoleMinYVox = INT32_MAX, - int32 HoleMaxXVox = INT32_MIN, int32 HoleMaxYVox = INT32_MIN); - //========================================================================= // SERVICES (injectés par AVoxelWorld) //========================================================================= diff --git a/Source/VoxelForge/Public/VoxelSettings.h b/Source/VoxelForge/Public/VoxelSettings.h index d9c5131..3e820c8 100644 --- a/Source/VoxelForge/Public/VoxelSettings.h +++ b/Source/VoxelForge/Public/VoxelSettings.h @@ -183,22 +183,13 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Clipmap", meta = (ClampMin = "0")) int32 RenderDistanceChunks = 768; - // F18 — the render-distance ring streams per-surface SHEETS instead of MC tiles: in an open - // strate the far field is exactly two heightfields (TerrainZ + sky-cap CeilSurf, both already - // computed per column), so each far tile becomes two displaced grids (ground polygroup 0 / - // cap polygroup 1 — same materials), ~3-6× cheaper to generate and far fewer components (one - // sheet spans 2^FarSheetSpanLevels MC-tile footprints per axis). Non-open strates produce - // empty sheets (their far ring was enclosed rock anyway). Carved features (passages, chasms, - // spine) don't show at sheet distance. Needs the strate band armed (StrateContentCutMinLevel - // active); in the inter-strate gap the sheet ring blanks until you land. The ship default is OFF: - // the ring stays real MC tiles at level MaxClipLevel (pre-F18 behaviour). Only matters when - // RenderDistanceChunks > 0. + // UNUSED: the far sheet ring was removed from the runtime; the render-distance ring is always + // marching-cubes tiles at MaxClipLevel. Kept only so saved assets and the test harness's + // `voxel.TestFarSheetRing` switch still load; it has no effect. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Clipmap") bool bFarSheetRing = false; - // Sheet tile size = MaxClipLevel + this many levels (2 → one sheet covers 4×4 MC-tile - // footprints → ~16× fewer far components). Sampling density stays that of the MaxClipLevel - // MC ring (cell count grows instead), capped at 128 cells/axis (beyond, cells coarsen). + // UNUSED (see bFarSheetRing). Kept so saved assets still load; it has no effect. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Voxel|Clipmap", meta = (ClampMin = "1", ClampMax = "4", EditCondition = "bFarSheetRing")) int32 FarSheetSpanLevels = 2; diff --git a/Source/VoxelForge/Public/VoxelStartupTrace.h b/Source/VoxelForge/Public/VoxelStartupTrace.h index 305e286..3f4a921 100644 --- a/Source/VoxelForge/Public/VoxelStartupTrace.h +++ b/Source/VoxelForge/Public/VoxelStartupTrace.h @@ -13,7 +13,7 @@ namespace VoxelForgeStartupTrace int32 TileY = 0; int32 TileZ = 0; int32 Level = -1; - int32 Verdict = -1; // Mixed=0, AllSolid=1, AllAir=2, -1=not classified (sheet/early path) + int32 Verdict = -1; // Mixed=0, AllSolid=1, AllAir=2, -1=not classified (early path) bool bSealedSolidProof = false; bool bEmpty = true; int32 Vertices = 0; diff --git a/Source/VoxelForge/Public/VoxelWorld.h b/Source/VoxelForge/Public/VoxelWorld.h index 3df6cb5..86cbdb0 100644 --- a/Source/VoxelForge/Public/VoxelWorld.h +++ b/Source/VoxelForge/Public/VoxelWorld.h @@ -160,7 +160,6 @@ struct FVoxelTileHashDumpRecord int32 Cells = 0; int32 BandChunkLo = MIN_int32; int32 BandChunkHi = MAX_int32; - bool bSheetTile = false; bool bEmpty = true; int32 NumTriangles = 0; FString GeometryHash; @@ -567,7 +566,7 @@ private: void LogReadyTransitionVisibilityMeasure(); void RecordTileHash(const FVoxelTileKey& Tile, const FIntVector& OriginVoxels, int32 Step, int32 Cells, int32 BandChunkLo, int32 BandChunkHi, - bool bSheetTile, const FVoxelMeshData& MeshData); + const FVoxelMeshData& MeshData); void WriteTileHashDump(); // Packed shader params, recomputed each Tick. ALL meaningful data is in .xyz — a material Vector @@ -761,7 +760,7 @@ public: EVoxelTileWorkPriority WorkPriority = EVoxelTileWorkPriority::Horizon); /** - * Worker-side gen for one tile: classify → GenerateMesh/GenerateSheetMesh → BuildTileStreamSet. + * Worker-side gen for one tile: classify → GenerateMesh → BuildTileStreamSet. * Fills Result (no enqueue, no bookkeeping). Called from the async ChunkGen task AND from the * synchronous carve path (SyncRemeshTile) — reads Generator/Mesher only, so it's safe on either * thread. See LoadTile for how the parameters are derived. @@ -769,8 +768,6 @@ public: void GenerateTileResult(const FVoxelTileKey& Tile, const FIntVector& OriginVoxels, int32 Step, int32 Cells, uint32 Epoch, bool bWantCapture, int32 BandVoxLo, int32 BandVoxHi, int32 BandChunkLo, int32 BandChunkHi, - bool bSheetTile, int32 SheetChunkZ, - int32 HoleMinX, int32 HoleMinY, int32 HoleMaxX, int32 HoleMaxY, FChunkResult& Result, const std::atomic* ObsoleteFlag = nullptr); @@ -933,15 +930,6 @@ public: // result cannot publish and the post-carve result is admitted immediately. TSet DirtyRemeshQueue; - // F18 — TROU XY de l'anneau feuille (voxels ; Max EXCLUSIF ; sentinelles MAX/MIN = pas de - // trou) : la zone couverte par les coquilles MC (boîte niveau-MaxClipLevel autour du joueur, - // rétrécie d'une tuile pour garder un anneau de recouvrement au raccord) est DÉCOUPÉE des - // feuilles — sinon une feuille partiellement couverte recouvre le terrain proche avec son - // échantillonnage grossier. Mis à jour par crossing ; changement ⇒ re-queue des feuilles - // chevauchantes via BandRemeshQueue (re-gen en place). - int32 SheetHoleMinXVox = MAX_int32, SheetHoleMinYVox = MAX_int32; - int32 SheetHoleMaxXVox = MIN_int32, SheetHoleMaxYVox = MIN_int32; - // Set to true during EndPlay — async tasks check this before accessing UObjects std::atomic bShuttingDown{false}; @@ -1018,8 +1006,7 @@ public: TArray ReadyTransitionVisibilitySamples; TArray FarFieldSubmitSamples; - // Clean performance accounting. LOD 0..8 covers every marching-cubes clip level; sheet tiles - // above the configured MC range never enter the outer classifier. + // Clean performance accounting. LOD 0..8 covers every marching-cubes clip level. static constexpr int32 TrackedClassifierLODCount = 9; std::atomic TotalWorkerGenerationCycles{0}; std::atomic TotalWorkerGenerationTasks{0};