standalone: speed round 2 -- far biome colour grid (payload -365 ms), whole view 1.90 s @8w full payload
- Per-vertex biome lookup was the payload cost (~365 ms); far tiles now take the biome palette from a per-tile grid. Same channels (palette, slope, border blend, UV) and ceiling/ground sections. - Opt-in --max-clip-level=8: 6,498 -> 2,226 tiles, stream 0.876 -> 0.428 s, 1.451 s process wall. Kept opt-in: six fixed views cannot prove every distant thin stratum survives. - W1/W8 hashes equal across 11 outputs; routes 5642/5642; five captures pixel-identical, passage 382 px differ (max delta 16). - Rejected with measurements: LOD6 empty-block proof (-21% samples, no wall gain), far supertiles (no complete groups exist). Remaining long pole: shape compile 0.854 s. 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
6ec4a8f856
commit
a3cb26b5c8
5 files changed
+212
-18
No files matched your search
@@ -392,6 +392,7 @@ namespace
|
||||
int32 Seed=0;
|
||||
int32 WorkerCount=8;
|
||||
int32 ClipRadius=3;
|
||||
int32 MaxClipLevelOverride=-1;
|
||||
int32 Width=1280,Height=800;
|
||||
float Yaw=0.0f,Pitch=0.0f,MoveSpeed=8.0f;
|
||||
V3 Position{};
|
||||
@@ -645,6 +646,13 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
if(!PrepareStandaloneDensityWorld(*World,Seed,bRoundTunnels,
|
||||
bRoundTunnelEnhanced,Error))return false;
|
||||
if(MaxClipLevelOverride>=0)
|
||||
{
|
||||
World->MaxClipLevel=MaxClipLevelOverride;
|
||||
World->Settings->MaxClipLevel=MaxClipLevelOverride;
|
||||
std::printf("Standalone max clip level override applied after world reload: max_level=%d.\n",
|
||||
MaxClipLevelOverride);
|
||||
}
|
||||
if(bShapeWorld&&!BuildShapeWorldForCamera(Error))return false;
|
||||
LoadMeshCache();
|
||||
return true;
|
||||
@@ -1705,6 +1713,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
int32 WorkerCount,int32 MaxLevel,bool bRoundTunnels,
|
||||
bool bEnhancedWalls,const FStandaloneMeshCache* Cache,
|
||||
bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,
|
||||
bool bSkipUV,bool bSkipColors,
|
||||
bool bShardAudit,float CameraYaw,float CameraPitch,
|
||||
const std::string& BakeCachePath,
|
||||
const FStandaloneMeshCacheMetadata& CacheMetadata)
|
||||
@@ -1749,15 +1758,17 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
const auto Start=std::chrono::steady_clock::now();
|
||||
FStandaloneStreamingGenerator Streamer(World,WorkerCount,
|
||||
bHashDensity||!BakeCachePath.empty(),Cache,MaxLevel,
|
||||
bSkipUvAndColors,bSkipMaterialGroups);
|
||||
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors);
|
||||
const FStandaloneStreamingUpdate Update=Streamer.Start(CameraPositionVoxels);
|
||||
const double LOD0Width=static_cast<double>(2*World.ClipRadius+2)
|
||||
*CHUNK_SIZE*VOXEL_SIZE/100.0;
|
||||
std::printf("[StreamBenchmarkConfig] clip_radius=%d lod0_cube=%.0fm voxel=25cm fullres_levels=%d max_level_filter=%d workers=%d full_detail_tiles=%d desired_tiles=%d variant=%s uv_colors=%s material_groups=%s hash=%s\n",
|
||||
std::printf("[StreamBenchmarkConfig] clip_radius=%d lod0_cube=%.0fm voxel=25cm fullres_levels=%d max_level_filter=%d workers=%d full_detail_tiles=%d desired_tiles=%d variant=%s uv=%s colors=%s material_groups=%s hash=%s\n",
|
||||
World.ClipRadius,LOD0Width,World.FullResClipLevels,MaxLevel<0?World.MaxClipLevel:MaxLevel,
|
||||
Streamer.GetWorkerCount(),FullDetailExpected,Update.DesiredTiles,
|
||||
bRoundTunnels?(bEnhancedWalls?"round-detailed":"round-legacy"):"base",
|
||||
bSkipUvAndColors?"skipped":"full",bSkipMaterialGroups?"skipped":"full",
|
||||
(bSkipUvAndColors||bSkipUV)?"skipped":"full",
|
||||
(bSkipUvAndColors||bSkipColors)?"skipped":"full",
|
||||
bSkipMaterialGroups?"skipped":"full",
|
||||
(bHashDensity||!BakeCachePath.empty())?"on":"off");
|
||||
std::fflush(stdout);
|
||||
int32 Finished=0,FullDetailFinished=0;
|
||||
@@ -2033,11 +2044,14 @@ int main(int Argc,char** Argv)
|
||||
{if(!JoinedCommandLine.empty())JoinedCommandLine.push_back(' ');JoinedCommandLine+=Argv[I];}
|
||||
FCommandLine::Set(JoinedCommandLine);
|
||||
int32 BenchmarkLevel=-1,BenchmarkCount=64,StreamBenchmarkMaxLevel=-1;
|
||||
int32 MaxClipLevelOverride=-1;
|
||||
int32 ShapeCompareLevel=-1,ShapeCompareTileLimit=0;
|
||||
bool bStreamBenchmark=false;
|
||||
bool bShardAudit=false;
|
||||
bool bStreamHash=false;
|
||||
bool bSkipUvAndColors=false;
|
||||
bool bSkipUV=false;
|
||||
bool bSkipColors=false;
|
||||
bool bSkipMaterialGroups=false;
|
||||
bool bEditBenchmark=false;
|
||||
bool bRoundWallCompare=false;
|
||||
@@ -2073,6 +2087,8 @@ int main(int Argc,char** Argv)
|
||||
{bEditBenchmark=true;bStreamBenchmark=true;App.bShapeWorld=true;}
|
||||
else if(Arg=="--stream-hash")bStreamHash=true;
|
||||
else if(Arg=="--skip-uv-colors")bSkipUvAndColors=true;
|
||||
else if(Arg=="--skip-uv")bSkipUV=true;
|
||||
else if(Arg=="--skip-colors")bSkipColors=true;
|
||||
else if(Arg=="--skip-material-groups")bSkipMaterialGroups=true;
|
||||
else if(Arg=="--shard-audit")bShardAudit=true;
|
||||
else if(Arg=="--compare-round-walls")
|
||||
@@ -2084,6 +2100,9 @@ int main(int Argc,char** Argv)
|
||||
{BakeMeshCachePath=std::string(Arg.substr(18));App.bForceGenerate=true;}
|
||||
else if(Arg.starts_with("--stream-max-level="))
|
||||
StreamBenchmarkMaxLevel=std::atoi(std::string(Arg.substr(19)).c_str());
|
||||
else if(Arg.starts_with("--max-clip-level="))
|
||||
MaxClipLevelOverride=std::clamp(
|
||||
std::atoi(std::string(Arg.substr(17)).c_str()),0,8);
|
||||
else if(Arg=="--test-one-chunk-crossing")App.bTestOneChunkCrossing=true;
|
||||
else if(Arg=="--capture-after-clipmap")App.bCaptureAfterClipmap=true;
|
||||
else if(Arg=="--quit-after-clipmap")App.bQuitAfterClipmap=true;
|
||||
@@ -2125,11 +2144,20 @@ int main(int Argc,char** Argv)
|
||||
static_cast<float>(App.World->ViewerStartVoxels.Y*0.25),static_cast<float>(App.World->ViewerStartVoxels.Z*0.25)};
|
||||
if(App.bHasCameraOverride){App.Position=App.CameraPositionOverride;App.Yaw=App.CameraYawOverride;App.Pitch=App.CameraPitchOverride;}
|
||||
const int32 ExportClipRadius=App.World->ClipRadius;
|
||||
const int32 ExportMaxClipLevel=App.World->MaxClipLevel;
|
||||
App.World->ClipRadius=App.ClipRadius;
|
||||
App.World->Settings->ClipRadius=App.ClipRadius;
|
||||
if(App.bRoundTunnels&&!PrepareStandaloneDensityWorld(*App.World,App.Seed,
|
||||
App.bRoundTunnels,App.bRoundTunnelEnhanced,Error))
|
||||
{std::fprintf(stderr,"Standalone world setup failed: %s\n",Error.c_str());return 2;}
|
||||
if(MaxClipLevelOverride>=0)
|
||||
{
|
||||
App.MaxClipLevelOverride=MaxClipLevelOverride;
|
||||
App.World->MaxClipLevel=MaxClipLevelOverride;
|
||||
App.World->Settings->MaxClipLevel=MaxClipLevelOverride;
|
||||
std::printf("Standalone max clip level override: exported=%d -> max_level=%d.\n",
|
||||
ExportMaxClipLevel,MaxClipLevelOverride);
|
||||
}
|
||||
const bool bNeedFarShapeWorld=bStreamBenchmark
|
||||
?(StreamBenchmarkMaxLevel<0||StreamBenchmarkMaxLevel>=App.World->FullResClipLevels)
|
||||
:(App.bShapeCompare?ShapeCompareLevel>=App.World->FullResClipLevels
|
||||
@@ -2162,7 +2190,7 @@ int main(int Argc,char** Argv)
|
||||
FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0),
|
||||
App.WorkerCount,StreamBenchmarkMaxLevel,App.bRoundTunnels,
|
||||
App.bRoundTunnelEnhanced,(!App.bShapeWorld&&App.MeshCache.IsLoaded())?&App.MeshCache:nullptr,
|
||||
bStreamHash,bSkipUvAndColors,bSkipMaterialGroups,bShardAudit,
|
||||
bStreamHash,bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,bShardAudit,
|
||||
App.Yaw,App.Pitch,BakeMeshCachePath,App.MakeMeshCacheMetadata());
|
||||
}
|
||||
if(BenchmarkLevel>=0)
|
||||
|
||||
@@ -397,10 +397,13 @@ public:
|
||||
const FStandaloneMeshCache* InMeshCache=nullptr,
|
||||
int32 InMaxLevelFilter=-1,
|
||||
bool bInSkipUvAndColors=false,
|
||||
bool bInSkipMaterialGroups=false)
|
||||
bool bInSkipMaterialGroups=false,
|
||||
bool bInSkipUV=false,
|
||||
bool bInSkipColors=false)
|
||||
:World(&InWorld),WorkerCount(FMath::Clamp(InWorkerCount,1,16)),bHashDensity(bInHashDensity),
|
||||
MeshCache(InMeshCache),MaxLevelFilter(InMaxLevelFilter),
|
||||
bSkipUvAndColors(bInSkipUvAndColors),bSkipMaterialGroups(bInSkipMaterialGroups)
|
||||
bSkipUvAndColors(bInSkipUvAndColors),bSkipMaterialGroups(bInSkipMaterialGroups),
|
||||
bSkipUV(bInSkipUV),bSkipColors(bInSkipColors)
|
||||
{
|
||||
VoxelGenLOD::InitializeConsoleSwitches();
|
||||
UVoxelMarchingCubesMesher::InitializeConsoleSwitches();
|
||||
@@ -543,6 +546,8 @@ private:
|
||||
UVoxelMarchingCubesMesher Mesher;
|
||||
Mesher.SetGenerator(World->Generator.get());
|
||||
Mesher.bStandaloneSkipUvAndColors=bSkipUvAndColors;
|
||||
Mesher.bStandaloneSkipUV=bSkipUV;
|
||||
Mesher.bStandaloneSkipColors=bSkipColors;
|
||||
Mesher.bStandaloneSkipMaterialGroups=bSkipMaterialGroups;
|
||||
Mesher.bGenerateSkirts=World->bGenerateSkirts;
|
||||
Mesher.SkirtCells=static_cast<float>(World->SkirtCells);
|
||||
@@ -635,6 +640,8 @@ private:
|
||||
int32 MaxLevelFilter=-1;
|
||||
bool bSkipUvAndColors=false;
|
||||
bool bSkipMaterialGroups=false;
|
||||
bool bSkipUV=false;
|
||||
bool bSkipColors=false;
|
||||
std::atomic<uint64> CacheHitCount{0};
|
||||
mutable std::mutex Mutex;
|
||||
std::condition_variable Wake;
|
||||
|
||||
@@ -113,6 +113,9 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
if (OutDensitySampleCount) { *OutDensitySampleCount = 0; }
|
||||
if (OutDebugDensitySamples) { OutDebugDensitySamples->clear(); }
|
||||
if (!Generator) return MeshData;
|
||||
const bool bEmitUV = !bStandaloneSkipUvAndColors && !bStandaloneSkipUV;
|
||||
const bool bEmitColors = !bStandaloneSkipUvAndColors && !bStandaloneSkipColors;
|
||||
const bool bUseCoarseFarBiomeGrid = Step >= 64;
|
||||
VoxelDensityProfile::FScopedTimer MesherProfileTimer(
|
||||
VoxelDensityProfile::EBucket::MesherGenerateMesh);
|
||||
VoxelDensityProfile::FScopedTimer MesherSetupTimer(
|
||||
@@ -166,6 +169,49 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
SurfColMemo.Reset();
|
||||
}
|
||||
|
||||
struct FBiomeGridSample
|
||||
{
|
||||
int32 Dominant = 0;
|
||||
int32 Neighbor = 0;
|
||||
float Blend = 0.0f;
|
||||
};
|
||||
struct FBiomeTileGridSamples
|
||||
{
|
||||
FBiomeGridSample Corners[4];
|
||||
};
|
||||
static thread_local TMap<int32, FBiomeTileGridSamples> BiomeTileGridMemo;
|
||||
const int32 BiomeGridSpacing = bUseCoarseFarBiomeGrid
|
||||
? FMath::Clamp(InCellsPerAxis, 2, CHUNK_SIZE) * Step : 1;
|
||||
if (bUseCoarseFarBiomeGrid && bEmitColors)
|
||||
{
|
||||
BiomeTileGridMemo.Reset();
|
||||
}
|
||||
|
||||
auto GetBiomeTileGridSamples = [&](int32 ChunkZ) -> FBiomeTileGridSamples
|
||||
{
|
||||
if (const FBiomeTileGridSamples* Existing = BiomeTileGridMemo.Find(ChunkZ))
|
||||
{
|
||||
return *Existing;
|
||||
}
|
||||
FBiomeTileGridSamples Samples;
|
||||
const float SampleZ = static_cast<float>(ChunkZ * CHUNK_SIZE + CHUNK_SIZE / 2);
|
||||
const int32 TileMaxX = OriginVoxels.X + BiomeGridSpacing;
|
||||
const int32 TileMaxY = OriginVoxels.Y + BiomeGridSpacing;
|
||||
Generator->GetBiomeMaterialAt(static_cast<float>(OriginVoxels.X),
|
||||
static_cast<float>(OriginVoxels.Y), SampleZ,
|
||||
Samples.Corners[0].Dominant, Samples.Corners[0].Neighbor, Samples.Corners[0].Blend);
|
||||
Generator->GetBiomeMaterialAt(static_cast<float>(TileMaxX),
|
||||
static_cast<float>(OriginVoxels.Y), SampleZ,
|
||||
Samples.Corners[1].Dominant, Samples.Corners[1].Neighbor, Samples.Corners[1].Blend);
|
||||
Generator->GetBiomeMaterialAt(static_cast<float>(OriginVoxels.X),
|
||||
static_cast<float>(TileMaxY), SampleZ,
|
||||
Samples.Corners[2].Dominant, Samples.Corners[2].Neighbor, Samples.Corners[2].Blend);
|
||||
Generator->GetBiomeMaterialAt(static_cast<float>(TileMaxX),
|
||||
static_cast<float>(TileMaxY), SampleZ,
|
||||
Samples.Corners[3].Dominant, Samples.Corners[3].Neighbor, Samples.Corners[3].Blend);
|
||||
return BiomeTileGridMemo.Add(ChunkZ, Samples);
|
||||
};
|
||||
|
||||
// Normale fournie par l'appelant (gradient lu dans la grille de densité, T1.b) —
|
||||
// plus d'échantillonnage de densité par vertex. RawNormal pointe solide→air ; on la
|
||||
// normalise ici (fallback up si dégénérée).
|
||||
@@ -194,16 +240,56 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
}
|
||||
MeshData.Normals.Add(Normal);
|
||||
|
||||
if (!bStandaloneSkipUvAndColors)
|
||||
if (bEmitUV)
|
||||
{
|
||||
// UVs planaires — le triplanar mapping se fait dans le matériau.
|
||||
MeshData.UVs.Add(FVector2f(WorldPos.X / VOXEL_SIZE, WorldPos.Y / VOXEL_SIZE));
|
||||
}
|
||||
|
||||
if (bEmitColors)
|
||||
{
|
||||
//-----------------------------------------------------------------
|
||||
// VERTEX COLOUR — masks for biome palette, slope and border blend.
|
||||
int32 PalD = 0, PalN = 0; float BlendW = 0.0f;
|
||||
Generator->GetBiomeMaterialAt(WorldPos.X / VOXEL_SIZE, WorldPos.Y / VOXEL_SIZE,
|
||||
WorldPos.Z / VOXEL_SIZE, PalD, PalN, BlendW);
|
||||
if (bUseCoarseFarBiomeGrid)
|
||||
{
|
||||
const float VoxelX = WorldPos.X / VOXEL_SIZE;
|
||||
const float VoxelY = WorldPos.Y / VOXEL_SIZE;
|
||||
const float VoxelZ = WorldPos.Z / VOXEL_SIZE;
|
||||
const float TX = FMath::Clamp(
|
||||
(VoxelX - static_cast<float>(OriginVoxels.X))
|
||||
/ static_cast<float>(BiomeGridSpacing), 0.0f, 1.0f);
|
||||
const float TY = FMath::Clamp(
|
||||
(VoxelY - static_cast<float>(OriginVoxels.Y))
|
||||
/ static_cast<float>(BiomeGridSpacing), 0.0f, 1.0f);
|
||||
const int32 ChunkZ = FMath::FloorToInt(VoxelZ / static_cast<float>(CHUNK_SIZE));
|
||||
const FBiomeTileGridSamples TileSamples = GetBiomeTileGridSamples(ChunkZ);
|
||||
const FBiomeGridSample& S00 = TileSamples.Corners[0];
|
||||
const FBiomeGridSample& S10 = TileSamples.Corners[1];
|
||||
const FBiomeGridSample& S01 = TileSamples.Corners[2];
|
||||
const FBiomeGridSample& S11 = TileSamples.Corners[3];
|
||||
|
||||
const FBiomeGridSample* Nearest = &S00;
|
||||
if (TX >= 0.5f) Nearest = TY >= 0.5f ? &S11 : &S10;
|
||||
else if (TY >= 0.5f) Nearest = &S01;
|
||||
PalD = Nearest->Dominant;
|
||||
PalN = Nearest->Neighbor;
|
||||
BlendW = Nearest->Blend;
|
||||
if (S00.Dominant == PalD && S00.Neighbor == PalN
|
||||
&& S10.Dominant == PalD && S10.Neighbor == PalN
|
||||
&& S01.Dominant == PalD && S01.Neighbor == PalN
|
||||
&& S11.Dominant == PalD && S11.Neighbor == PalN)
|
||||
{
|
||||
const float B0 = FMath::Lerp(S00.Blend, S10.Blend, TX);
|
||||
const float B1 = FMath::Lerp(S01.Blend, S11.Blend, TX);
|
||||
BlendW = FMath::Lerp(B0, B1, TY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Generator->GetBiomeMaterialAt(WorldPos.X / VOXEL_SIZE, WorldPos.Y / VOXEL_SIZE,
|
||||
WorldPos.Z / VOXEL_SIZE, PalD, PalN, BlendW);
|
||||
}
|
||||
const uint8 R = (uint8)FMath::Clamp(PalD, 0, 255);
|
||||
const uint8 A = (uint8)FMath::Clamp(PalN, 0, 255);
|
||||
const uint8 G = (uint8)FMath::Clamp(FMath::RoundToInt((1.0f - FMath::Abs((float)Normal.Z)) * 255.0f), 0, 255);
|
||||
@@ -1314,9 +1400,12 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
const int32 Idx = MeshData.Vertices.Num();
|
||||
MeshData.Vertices.Add(Pos);
|
||||
MeshData.Normals.Add(Nrm);
|
||||
if (!bStandaloneSkipUvAndColors)
|
||||
if (bEmitUV)
|
||||
{
|
||||
MeshData.UVs.Add(FVector2f(Pos.X / VOXEL_SIZE, Pos.Y / VOXEL_SIZE));
|
||||
}
|
||||
if (bEmitColors)
|
||||
{
|
||||
MeshData.Colors.Add(Col); // parallel with the other vertex arrays
|
||||
}
|
||||
return Idx;
|
||||
@@ -1342,8 +1431,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
|
||||
const FVector NA = MeshData.Normals[iA];
|
||||
const FVector NB = MeshData.Normals[iB];
|
||||
const FColor CA = bStandaloneSkipUvAndColors ? FColor::White : MeshData.Colors[iA];
|
||||
const FColor CB = bStandaloneSkipUvAndColors ? FColor::White : MeshData.Colors[iB];
|
||||
const FColor CA = bEmitColors ? MeshData.Colors[iA] : FColor::White;
|
||||
const FColor CB = bEmitColors ? MeshData.Colors[iB] : FColor::White;
|
||||
const int32 iA2 = AddSkirtVert(PA - NA * SkirtDepth, NA, CA);
|
||||
const int32 iB2 = AddSkirtVert(PB - NB * SkirtDepth, NB, CB);
|
||||
|
||||
|
||||
@@ -116,9 +116,11 @@ public:
|
||||
// SETTINGS
|
||||
//=========================================================================
|
||||
|
||||
// Optional standalone benchmark switches. Runtime callers leave both false and retain the
|
||||
// Optional standalone benchmark switches. Runtime callers leave all false and retain the
|
||||
// complete FVoxelMeshData contract consumed by the game materials and section setup.
|
||||
bool bStandaloneSkipUvAndColors = false;
|
||||
bool bStandaloneSkipUV = false;
|
||||
bool bStandaloneSkipColors = false;
|
||||
bool bStandaloneSkipMaterialGroups = false;
|
||||
|
||||
// Seuil de l'isosurface dans le champ de densité.
|
||||
|
||||
Reference in new issue
Block a user