wip(assembler): round S1 -- one Core voxel-size source; per-tile feature lists (islands)
AVoxelWorld::CoreVoxelSizeCm (default 25, 32 voxels/tile) flows through plan, field, mesher, content, water, atmosphere, edits and collision. Staged-owner BuildHost passes at 20 cm (SurfaceWorld + islands, W1/W8/W16, anchors, BP edits, collision) with a fixed-25cm negative control; default-size hashes match round 4; Core off stays legacy 12.5 cm. Reusable BuildWorldAssemblyFeatureTileListV1; wired into FloatingIslands only so far. 256-island stress: tile p95 112.5 -> 2.0 ms, 0 mismatches, dropped-feature control fails. Content placement measured (no populated cells): island ground search 7.25 ms/cell vs legacy 0.29 ms -- open. Outside-review evaluation in Round5/REPORT.md. 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
111cf3d262
commit
d6e69420e8
25 files changed
+2136
-250
No files matched your search
@@ -7176,7 +7176,10 @@ FVector AVoxelWorld::WorldToLocalCm(FVector WorldPos) const
|
||||
|
||||
float AVoxelWorld::GetActiveVoxelSizeCm() const
|
||||
{
|
||||
return bUseVoxelForgeCore ? 25.0f : VOXEL_SIZE;
|
||||
if (!bUseVoxelForgeCore) return VOXEL_SIZE;
|
||||
const float Requested = FMath::IsFinite(CoreVoxelSizeCm) ? CoreVoxelSizeCm : 2.0f * VOXEL_SIZE;
|
||||
const float Clamped = FMath::Clamp(Requested, VOXEL_SIZE, 2.0f * VOXEL_SIZE);
|
||||
return static_cast<float>(FMath::RoundToInt(Clamped * 10000.0f)) / 10000.0f;
|
||||
}
|
||||
|
||||
float AVoxelWorld::GetLegacyVoxelToActiveVoxelScale() const
|
||||
@@ -7260,10 +7263,12 @@ bool AVoxelWorld::InitializeVoxelForgeCoreWorld(FString& OutFailureReason)
|
||||
|
||||
const int32 ActiveCoreClipRadius = FMath::Clamp(CoreClipRadius, 1, 64);
|
||||
const int32 ActiveCoreMaxClipLevel = FMath::Clamp(CoreMaxClipLevel, 0, 8);
|
||||
const float ActiveCoreVoxelSizeCm = GetActiveVoxelSizeCm();
|
||||
FString Json;
|
||||
FString ExportError;
|
||||
if (!VoxelForgeCoreAdapter::SerializeResolvedWorld(
|
||||
Settings, StrateManager, ActiveCoreClipRadius, ActiveCoreMaxClipLevel, Json, ExportError))
|
||||
Settings, StrateManager, ActiveCoreClipRadius, ActiveCoreMaxClipLevel,
|
||||
ActiveCoreVoxelSizeCm, Json, ExportError))
|
||||
{
|
||||
OutFailureReason = FString::Printf(TEXT("snapshot export failed: %s"), *ExportError);
|
||||
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeCoreRuntime] %s"), *OutFailureReason);
|
||||
@@ -7310,14 +7315,14 @@ bool AVoxelWorld::InitializeVoxelForgeCoreWorld(FString& OutFailureReason)
|
||||
FVector InitialPlayerPosition = FVector::ZeroVector;
|
||||
if (TryGetPlayerPosition(InitialPlayerPosition))
|
||||
{
|
||||
CameraVoxels = WorldToLocalCm(InitialPlayerPosition) / 25.0f;
|
||||
CameraVoxels = WorldToLocalCm(InitialPlayerPosition) / GetActiveVoxelSizeCm();
|
||||
}
|
||||
else if (State->World->configuration().viewerStartFound)
|
||||
{
|
||||
const VoxelForgeCore::Vec3d Start = State->World->configuration().viewerStartVoxels;
|
||||
CameraVoxels = FVector(Start.x, Start.y, Start.z);
|
||||
}
|
||||
CoreFallbackCenterLocalCm = CameraVoxels * 25.0f;
|
||||
CoreFallbackCenterLocalCm = CameraVoxels * GetActiveVoxelSizeCm();
|
||||
|
||||
const std::vector<VoxelForgeCore::TileKey> InitialDesired = State->World->desiredTiles(
|
||||
{CameraVoxels.X, CameraVoxels.Y, CameraVoxels.Z});
|
||||
@@ -7372,7 +7377,8 @@ bool AVoxelWorld::InitializeVoxelForgeCoreWorld(FString& OutFailureReason)
|
||||
VoxelForgeCoreState = State;
|
||||
ActiveTaskCount.fetch_add(1, std::memory_order_relaxed);
|
||||
UE::Tasks::Launch(TEXT("VoxelForgeCoreCompile"),
|
||||
[this, State, Request, InitialDesired, ActiveCoreClipRadius, ActiveCoreMaxClipLevel]()
|
||||
[this, State, Request, InitialDesired, ActiveCoreClipRadius, ActiveCoreMaxClipLevel,
|
||||
ActiveCoreVoxelSizeCm]()
|
||||
{
|
||||
struct FTaskGuard
|
||||
{
|
||||
@@ -7413,9 +7419,9 @@ bool AVoxelWorld::InitializeVoxelForgeCoreWorld(FString& OutFailureReason)
|
||||
State->bReady.store(true, std::memory_order_release);
|
||||
State->bRebuildDesired.store(true, std::memory_order_release);
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeCoreRuntime] compiled=1 tiles=%d clip_radius=%d max_level=%d voxel_cm=25"),
|
||||
TEXT("[VoxelForgeCoreRuntime] compiled=1 tiles=%d clip_radius=%d max_level=%d voxel_cm=%.4f"),
|
||||
static_cast<int32>(InitialDesired.size()), ActiveCoreClipRadius,
|
||||
ActiveCoreMaxClipLevel);
|
||||
ActiveCoreMaxClipLevel, ActiveCoreVoxelSizeCm);
|
||||
}, UE::Tasks::ETaskPriority::BackgroundNormal);
|
||||
|
||||
UE_LOG(LogTemp, Display,
|
||||
@@ -9866,7 +9872,7 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
|
||||
const TSharedPtr<FVoxelForgeCoreRuntimeState, ESPMode::ThreadSafe> State = VoxelForgeCoreState;
|
||||
if (!State.IsValid() || !State->bReady.load(std::memory_order_acquire)) return;
|
||||
|
||||
const FVector CameraVoxels = WorldToLocalCm(PlayerPosition) / 25.0f;
|
||||
const FVector CameraVoxels = WorldToLocalCm(PlayerPosition) / GetActiveVoxelSizeCm();
|
||||
std::vector<VoxelForgeCore::TileKey> CoreDesired;
|
||||
{
|
||||
FReadScopeLock Lock(State->WorldLock);
|
||||
@@ -12291,16 +12297,27 @@ bool AVoxelWorld::ApplyMeshToTile(FChunkResult& Result)
|
||||
// the cap is by definition the topmost surface in the tile (mid as a gap fallback).
|
||||
// This was the "far cap renders with the ground material" residue: the min-corner lookup
|
||||
// missed the surface strate entirely on tall far tiles.
|
||||
// Core's 25 cm voxel is two legacy 12.5 cm voxels; map only the lookup into the existing
|
||||
// strate material layout, while keeping tile keys and mesh coordinates in Core units.
|
||||
// Le voxel Core de 25 cm vaut deux anciens voxels de 12,5 cm ; seule la recherche de
|
||||
// matériau est convertie vers le layout existant, les clés et maillages restent en Core.
|
||||
const int32 CoreToStrateChunkScale = bUseVoxelForgeCore
|
||||
? FMath::RoundToInt(GetActiveVoxelSizeCm() / VOXEL_SIZE) : 1;
|
||||
const FIntVector MinChunk = Tile.Coord * ((1 << Tile.Level) * CoreToStrateChunkScale);
|
||||
const int32 TileChunks = (1 << Tile.Level) * CoreToStrateChunkScale;
|
||||
const int32 ZLoC = FMath::Max(MinChunk.Z, Result.BandChunkLo);
|
||||
const int32 ZHiC = FMath::Min(MinChunk.Z + TileChunks - 1, Result.BandChunkHi);
|
||||
// Map the physical tile bounds into the existing owner stride layout. Fractional ratios
|
||||
// are valid (for example, 20 cm Core voxels span 1.6 legacy voxels each).
|
||||
// Convertir les bornes physiques de tuile vers les strates owner, y compris les rapports fractionnaires.
|
||||
const double OwnerChunksPerCoreTile = static_cast<double>(GetActiveVoxelSizeCm())
|
||||
/ VOXEL_SIZE;
|
||||
const double TileExtentCoreVoxels = static_cast<double>(CHUNK_SIZE << Tile.Level);
|
||||
const int32 MinOwnerChunkX = FMath::FloorToInt(
|
||||
Tile.Coord.X * TileExtentCoreVoxels * OwnerChunksPerCoreTile / CHUNK_SIZE);
|
||||
const int32 MinOwnerChunkY = FMath::FloorToInt(
|
||||
Tile.Coord.Y * TileExtentCoreVoxels * OwnerChunksPerCoreTile / CHUNK_SIZE);
|
||||
const int32 MinOwnerChunkZ = FMath::FloorToInt(
|
||||
Tile.Coord.Z * TileExtentCoreVoxels * OwnerChunksPerCoreTile / CHUNK_SIZE);
|
||||
const int32 MaxOwnerChunkX = FMath::CeilToInt(
|
||||
(Tile.Coord.X + 1.0) * TileExtentCoreVoxels * OwnerChunksPerCoreTile / CHUNK_SIZE) - 1;
|
||||
const int32 MaxOwnerChunkY = FMath::CeilToInt(
|
||||
(Tile.Coord.Y + 1.0) * TileExtentCoreVoxels * OwnerChunksPerCoreTile / CHUNK_SIZE) - 1;
|
||||
const int32 MaxOwnerChunkZ = FMath::CeilToInt(
|
||||
(Tile.Coord.Z + 1.0) * TileExtentCoreVoxels * OwnerChunksPerCoreTile / CHUNK_SIZE) - 1;
|
||||
const FIntVector MinChunk(MinOwnerChunkX, MinOwnerChunkY, MinOwnerChunkZ);
|
||||
const int32 ZLoC = FMath::Max(MinOwnerChunkZ, Result.BandChunkLo);
|
||||
const int32 ZHiC = FMath::Min(MaxOwnerChunkZ, Result.BandChunkHi);
|
||||
if (UVoxelStrateDefinition* StrateDef =
|
||||
StrateManager->GetStrateForChunk(FIntVector(MinChunk.X, MinChunk.Y, ZLoC)))
|
||||
{
|
||||
@@ -12631,9 +12648,10 @@ bool AVoxelWorld::GetVoxelSurfaceHeightAt(FVector WorldLocation, float& OutSurfa
|
||||
if (!State.IsValid()) return false;
|
||||
|
||||
const FVector LocalCm = WorldToLocalCm(WorldLocation);
|
||||
const double XVoxel = LocalCm.X / 25.0;
|
||||
const double YVoxel = LocalCm.Y / 25.0;
|
||||
const double ZVoxel = LocalCm.Z / 25.0;
|
||||
const double CoreVoxelSize = GetActiveVoxelSizeCm();
|
||||
const double XVoxel = LocalCm.X / CoreVoxelSize;
|
||||
const double YVoxel = LocalCm.Y / CoreVoxelSize;
|
||||
const double ZVoxel = LocalCm.Z / CoreVoxelSize;
|
||||
FReadScopeLock Lock(State->WorldLock);
|
||||
if (!State->World) return false;
|
||||
|
||||
@@ -12684,12 +12702,12 @@ bool AVoxelWorld::GetVoxelSurfaceHeightAt(FVector WorldLocation, float& OutSurfa
|
||||
if (bFoundGround)
|
||||
{
|
||||
OutSurfaceWorldZ = GetActorTransform().TransformPosition(
|
||||
FVector(LocalCm.X, LocalCm.Y, GroundVoxelZ * 25.0)).Z;
|
||||
FVector(LocalCm.X, LocalCm.Y, GroundVoxelZ * CoreVoxelSize)).Z;
|
||||
}
|
||||
if (bFoundCeiling)
|
||||
{
|
||||
OutCeilingWorldZ = GetActorTransform().TransformPosition(
|
||||
FVector(LocalCm.X, LocalCm.Y, CeilingVoxelZ * 25.0)).Z;
|
||||
FVector(LocalCm.X, LocalCm.Y, CeilingVoxelZ * CoreVoxelSize)).Z;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -13384,7 +13402,8 @@ FString AVoxelWorld::GetCurrentSeasonContentHash() const
|
||||
FString SnapshotJson;
|
||||
if (!VoxelForgeCoreAdapter::SerializeResolvedWorld(Settings, StrateManager,
|
||||
FMath::Clamp(CoreClipRadius, 1, 64),
|
||||
FMath::Clamp(CoreMaxClipLevel, 0, 8), SnapshotJson, AssemblyError))
|
||||
FMath::Clamp(CoreMaxClipLevel, 0, 8), GetActiveVoxelSizeCm(),
|
||||
SnapshotJson, AssemblyError))
|
||||
{
|
||||
return FString();
|
||||
}
|
||||
@@ -13406,7 +13425,9 @@ FString AVoxelWorld::GetCurrentSeasonContentHash() const
|
||||
}
|
||||
}
|
||||
const bool bHybridMesher = CoreMesherRecipe != EVoxelForgeCoreMesherRecipe::MarchingCubesV1;
|
||||
if (AssemblyHash.IsEmpty() && !bHybridMesher)
|
||||
const uint32 CoreVoxelSizeMicrons = static_cast<uint32>(
|
||||
FMath::RoundToInt(GetActiveVoxelSizeCm() * 10000.0f));
|
||||
if (AssemblyHash.IsEmpty() && !bHybridMesher && CoreVoxelSizeMicrons == 250000)
|
||||
{
|
||||
return SeasonHash;
|
||||
}
|
||||
@@ -13431,6 +13452,10 @@ FString AVoxelWorld::GetCurrentSeasonContentHash() const
|
||||
Payload += TEXT("|world_assembly=");
|
||||
Payload += AssemblyHash;
|
||||
}
|
||||
if (CoreVoxelSizeMicrons != 250000)
|
||||
{
|
||||
Payload += FString::Printf(TEXT("|core_voxel_size_microns=%u"), CoreVoxelSizeMicrons);
|
||||
}
|
||||
if (CoreMesherRecipe == EVoxelForgeCoreMesherRecipe::WorldAssemblerHybridV1)
|
||||
{
|
||||
Payload += TEXT("|core_mesher=WorldAssemblerHybridV1");
|
||||
|
||||
Reference in new issue
Block a user