research(step2f): coherent caves pass every gate, worst 572 ms idle -- look still to be judged in game
Editor-only, default off (voxel.ResearchParameterizedCave 1; the live skip proofs now decline automatically). Jittered elliptical chambers of varied size and height with rock between them, narrow tunnels, capped shafts, occasional pillars/ledges/stalactites/stalagmites/hanging masses; detail bands at 48/24/12 samples (shortest 3 m), bound 3.822. Gates, step 2e -> step 2f R29 (worst of 8 profiles), each rejecting 2e: crumbs < 1 m^3 2,290 -> 0; dihedral >45 deg 40.7% -> 2.2%; lattice detail energy 0.83 -> 0.007 (RMS floor kept: 0.484 >= 0.40); LOD1 distance p95 0.709 -> 0.377 samples; grid autocorrelation 0.667 -> 0.348; solid share 2.7% -> 79-82%; roof/floor openings 26,657 -> 0. Speed, 259^3 ring, six workers, idle machine (20 GB free): 527-572 ms, worst TerracedBasin 572.3 ms (R27 591 ms, R28 603 ms: run-to-run spread is ~5%). Proof audit 0 violations, undersized control caught; seams pass; 1 vs 6 worker hash 876069a813c83cee; TraversalSeeds pass. Captures are UNLIT (lit runs showed only sky; three D3D12 device-removed crashes): they show the material's tiling, not the cave forms, so the look is not yet judged. 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
d6555df5fa
commit
ca78352e43
16 files changed
+8070
-80
No files matched your search
@@ -51,6 +51,7 @@
|
||||
#include "Engine/GameViewportClient.h"
|
||||
#include "Slate/SceneViewport.h"
|
||||
#include "Camera/CameraActor.h"
|
||||
#include "Components/PointLightComponent.h"
|
||||
#include "VoxelAtmosphereManager.h"
|
||||
#include "DrawDebugHelpers.h"
|
||||
#include "IImageWrapper.h"
|
||||
@@ -1760,6 +1761,21 @@ void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
|
||||
void AVoxelWorld::BeginPlay()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
int32 ResearchParameterizedCave = 0;
|
||||
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.ResearchParameterizedCave="),
|
||||
ResearchParameterizedCave))
|
||||
{
|
||||
VoxelForgeRedefinedDensityField::SetParameterizedEnabled(
|
||||
ResearchParameterizedCave != 0);
|
||||
}
|
||||
int32 ResearchParameterizedCaveSet = -1;
|
||||
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.ResearchParameterizedCaveSet="),
|
||||
ResearchParameterizedCaveSet))
|
||||
{
|
||||
VoxelForgeRedefinedDensityField::SetParameterSet(ResearchParameterizedCaveSet);
|
||||
}
|
||||
#endif
|
||||
VoxelForgeStartupTrace::BeginFromCommandLine();
|
||||
VoxelForgeStartupTrace::FStageScope StartupTraceStage(TEXT("BeginPlay"));
|
||||
Super::BeginPlay();
|
||||
@@ -2059,6 +2075,7 @@ void AVoxelWorld::BeginPlay()
|
||||
}
|
||||
|
||||
int32 TestCeilingView = 0;
|
||||
int32 TestCeilingWallCloseup = 0;
|
||||
FParse::Value(FCommandLine::Get(), TEXT("voxel.TestCeilingView="), TestCeilingView);
|
||||
bTestCeilingViewEnabled = TestCeilingView != 0;
|
||||
if (bTestCeilingViewEnabled)
|
||||
@@ -2078,6 +2095,8 @@ void AVoxelWorld::BeginPlay()
|
||||
FParse::Value(FCommandLine::Get(), TEXT("voxel.TestCeilingCaptureDelaySeconds="),
|
||||
TestCeilingCaptureDelaySeconds);
|
||||
TestCeilingCaptureDelaySeconds = FMath::Max(TestCeilingCaptureDelaySeconds, 1.0f);
|
||||
FParse::Value(FCommandLine::Get(), TEXT("voxel.TestCeilingWallCloseup="),
|
||||
TestCeilingWallCloseup);
|
||||
TestCeilingViewBeginSeconds = FPlatformTime::Seconds();
|
||||
bHeadlessStreamingTestCenterOverride = true;
|
||||
HeadlessStreamingTestCenterVoxel = WorldToLocalVoxel(TestCeilingCameraWorldPosition);
|
||||
@@ -2255,6 +2274,138 @@ void AVoxelWorld::BeginPlay()
|
||||
DiffLayer->SetBudget(Settings->MaxModifications, Settings->MaxBrushRadius, Settings->MaxTotalVolume);
|
||||
Generator->SetDiffLayer(DiffLayer);
|
||||
|
||||
if (bTestCeilingViewEnabled && IsParameterizedResearchFieldActive())
|
||||
{
|
||||
const FVector RequestedCenter = HeadlessStreamingTestCenterVoxel;
|
||||
FVector BestAirPoint = RequestedCenter;
|
||||
float BestAirDensity = Generator->GetDensityAt(
|
||||
RequestedCenter.X, RequestedCenter.Y, RequestedCenter.Z);
|
||||
TArray<int32> SearchZValues;
|
||||
constexpr int32 SearchZMargin = 8;
|
||||
constexpr int32 SearchZStep = 16;
|
||||
if (StrateManager != nullptr)
|
||||
{
|
||||
for (const FStrateSlot& Slot : StrateManager->GetLayout())
|
||||
{
|
||||
const int32 MinChunkZ = FMath::Min(Slot.TopChunkZ, Slot.BottomChunkZ);
|
||||
const int32 MaxChunkZ = FMath::Max(Slot.TopChunkZ, Slot.BottomChunkZ);
|
||||
const int32 MinZ = MinChunkZ * CHUNK_SIZE + SearchZMargin;
|
||||
const int32 MaxZ = (MaxChunkZ + 1) * CHUNK_SIZE - SearchZMargin;
|
||||
for (int32 Z = MinZ; Z <= MaxZ; Z += SearchZStep)
|
||||
{
|
||||
SearchZValues.Add(Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SearchZValues.IsEmpty())
|
||||
{
|
||||
constexpr int32 SearchRadiusZ = 256;
|
||||
for (int32 Z = FMath::FloorToInt(RequestedCenter.Z) - SearchRadiusZ;
|
||||
Z <= FMath::FloorToInt(RequestedCenter.Z) + SearchRadiusZ;
|
||||
Z += SearchZStep)
|
||||
{
|
||||
SearchZValues.Add(Z);
|
||||
}
|
||||
}
|
||||
constexpr int32 SearchRadiusXY = 256;
|
||||
constexpr int32 SearchStepXY = 16;
|
||||
for (const int32 Z : SearchZValues)
|
||||
for (int32 DY = -SearchRadiusXY; DY <= SearchRadiusXY; DY += SearchStepXY)
|
||||
for (int32 DX = -SearchRadiusXY; DX <= SearchRadiusXY; DX += SearchStepXY)
|
||||
{
|
||||
const FVector Candidate(RequestedCenter.X + DX,
|
||||
RequestedCenter.Y + DY, static_cast<float>(Z));
|
||||
const float Density = Generator->GetDensityAt(
|
||||
Candidate.X, Candidate.Y, Candidate.Z);
|
||||
if (Density > BestAirDensity)
|
||||
{
|
||||
BestAirDensity = Density;
|
||||
BestAirPoint = Candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (BestAirDensity > 0.0f)
|
||||
{
|
||||
// Frame the capture from a plausible player-height point in the same chamber, rather
|
||||
// than directly at its maximum-clearance center. This brings the floor into view while
|
||||
// retaining a generous air margin and does not affect normal gameplay or generation.
|
||||
constexpr float CaptureEyeDropVoxels = 32.0f;
|
||||
const FVector LowerCapturePoint = BestAirPoint
|
||||
+ FVector(0.0f, 0.0f, -CaptureEyeDropVoxels);
|
||||
const float LowerCaptureDensity = Generator->GetDensityAt(
|
||||
LowerCapturePoint.X, LowerCapturePoint.Y, LowerCapturePoint.Z);
|
||||
if (LowerCaptureDensity > 12.0f)
|
||||
{
|
||||
BestAirPoint = LowerCapturePoint;
|
||||
BestAirDensity = LowerCaptureDensity;
|
||||
}
|
||||
|
||||
FVector BestViewDirection = FVector(1.0f, 0.0f, 0.0f);
|
||||
float BestViewWallDistance = 0.0f;
|
||||
float BestViewScore = -FLT_MAX;
|
||||
for (int32 DZ = -1; DZ <= 1; ++DZ)
|
||||
for (int32 DY = -1; DY <= 1; ++DY)
|
||||
for (int32 DX = -1; DX <= 1; ++DX)
|
||||
{
|
||||
if (TestCeilingWallCloseup == 0 && DZ != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const FVector Direction(static_cast<float>(DX),
|
||||
static_cast<float>(DY), static_cast<float>(DZ));
|
||||
if (Direction.IsNearlyZero())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const FVector NormalizedDirection = Direction.GetSafeNormal();
|
||||
for (float Distance = 4.0f; Distance <= 256.0f; Distance += 4.0f)
|
||||
{
|
||||
const FVector Probe = BestAirPoint + NormalizedDirection * Distance;
|
||||
if (Generator->GetDensityAt(Probe.X, Probe.Y, Probe.Z) <= 0.0f)
|
||||
{
|
||||
const float TargetDistance = TestCeilingWallCloseup != 0
|
||||
? 24.0f : 64.0f;
|
||||
const float Score = -FMath::Abs(Distance - TargetDistance);
|
||||
if (Score > BestViewScore)
|
||||
{
|
||||
BestViewScore = Score;
|
||||
BestViewDirection = NormalizedDirection;
|
||||
BestViewWallDistance = Distance;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BestViewWallDistance > 0.0f)
|
||||
{
|
||||
TestCeilingCameraRotation = BestViewDirection.Rotation();
|
||||
if (TestCeilingWallCloseup != 0)
|
||||
{
|
||||
constexpr float WallInset = 8.0f;
|
||||
BestAirPoint += BestViewDirection * FMath::Max(
|
||||
0.0f, BestViewWallDistance - WallInset);
|
||||
}
|
||||
}
|
||||
TestCeilingCameraWorldPosition = LocalVoxelToWorld(BestAirPoint);
|
||||
HeadlessStreamingTestCenterVoxel = BestAirPoint;
|
||||
const FVector WallProbe = BestAirPoint + BestViewDirection
|
||||
* (TestCeilingWallCloseup != 0 ? 8.0f : BestViewWallDistance);
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTestCeiling] view_ray=(%.3f,%.3f,%.3f) wall_distance_vox=%.1f "
|
||||
"wall_probe_density=%.3f"),
|
||||
BestViewDirection.X, BestViewDirection.Y, BestViewDirection.Z,
|
||||
BestViewWallDistance,
|
||||
Generator->GetDensityAt(WallProbe.X, WallProbe.Y, WallProbe.Z));
|
||||
}
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTestCeiling] research_air_search=1 requested_local=(%.1f,%.1f,%.1f) "
|
||||
"selected_local=(%.1f,%.1f,%.1f) selected_density=%.3f wall_closeup=%d"),
|
||||
RequestedCenter.X, RequestedCenter.Y, RequestedCenter.Z,
|
||||
BestAirPoint.X, BestAirPoint.Y, BestAirPoint.Z, BestAirDensity,
|
||||
TestCeilingWallCloseup != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
// Content manager — distance-based decoration grid (no LOD pop) + level-0 water planes.
|
||||
ContentManager = NewObject<UVoxelContentManager>(this);
|
||||
ContentManager->Initialize(
|
||||
@@ -2266,6 +2417,11 @@ void AVoxelWorld::BeginPlay()
|
||||
AtmosphereManager = NewObject<UVoxelAtmosphereManager>(this);
|
||||
AtmosphereManager->Initialize(this, StrateManager, Generator);
|
||||
}
|
||||
else if (bTestCeilingViewEnabled)
|
||||
{
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTestCeiling] atmosphere=disabled_by_world_setting"));
|
||||
}
|
||||
|
||||
// Density volume — player-centred clipmap streamed to the GPU for mini-sun raymarched shadows.
|
||||
if (Settings->bEnableDensityVolume)
|
||||
@@ -6547,6 +6703,23 @@ void AVoxelWorld::Tick(float DeltaTime)
|
||||
{
|
||||
TestCeilingCamera = Camera;
|
||||
PC->SetViewTarget(Camera);
|
||||
UPointLightComponent* CaptureHeadlamp = NewObject<UPointLightComponent>(Camera);
|
||||
if (IsValid(CaptureHeadlamp))
|
||||
{
|
||||
Camera->AddInstanceComponent(CaptureHeadlamp);
|
||||
CaptureHeadlamp->SetupAttachment(Camera->GetRootComponent());
|
||||
CaptureHeadlamp->SetMobility(EComponentMobility::Movable);
|
||||
CaptureHeadlamp->SetIntensity(80000.0f);
|
||||
CaptureHeadlamp->SetAttenuationRadius(10000.0f);
|
||||
CaptureHeadlamp->SetUseInverseSquaredFalloff(false);
|
||||
CaptureHeadlamp->SetLightFalloffExponent(0.0f);
|
||||
CaptureHeadlamp->SetLightColor(FLinearColor(1.0f, 0.88f, 0.72f));
|
||||
CaptureHeadlamp->SetCastShadows(false);
|
||||
CaptureHeadlamp->RegisterComponent();
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTestCeiling] camera_headlamp=1 intensity=80000 radius_cm=10000 "
|
||||
"inverse_square=0 falloff_exponent=0"));
|
||||
}
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTestCeiling] camera_installed=1 applied_visible_tiles=%llu"),
|
||||
static_cast<unsigned long long>(AppliedVisibleTileCount));
|
||||
@@ -6559,6 +6732,27 @@ void AVoxelWorld::Tick(float DeltaTime)
|
||||
>= static_cast<double>(TestCeilingCaptureDelaySeconds))
|
||||
{
|
||||
bTestCeilingCaptureRequested = true;
|
||||
FVector ActiveViewWorldPosition = FVector::ZeroVector;
|
||||
FRotator ActiveViewRotation = FRotator::ZeroRotator;
|
||||
PC->GetPlayerViewPoint(ActiveViewWorldPosition, ActiveViewRotation);
|
||||
const FVector ActiveViewVoxel = WorldToLocalVoxel(ActiveViewWorldPosition);
|
||||
const float ActiveViewDensity = Generator != nullptr
|
||||
? Generator->GetDensityAt(ActiveViewVoxel.X, ActiveViewVoxel.Y, ActiveViewVoxel.Z)
|
||||
: 0.0f;
|
||||
int32 ActiveResearchEnabled = 0;
|
||||
int32 ActiveResearchProfile = -1;
|
||||
#if WITH_EDITOR
|
||||
ActiveResearchEnabled = VoxelForgeRedefinedDensityField::IsParameterizedEnabled() ? 1 : 0;
|
||||
ActiveResearchProfile = VoxelForgeRedefinedDensityField::GetParameterSet();
|
||||
#endif
|
||||
UE_LOG(LogTemp, Display,
|
||||
TEXT("[VoxelForgeTestCeiling] active_view_target=%s active_view_world_cm=(%.3f,%.3f,%.3f) "
|
||||
"rotation=(%.3f,%.3f,%.3f) local_vox=(%.3f,%.3f,%.3f) density=%.3f research=%d profile=%d"),
|
||||
*GetNameSafe(PC->GetViewTarget()),
|
||||
ActiveViewWorldPosition.X, ActiveViewWorldPosition.Y, ActiveViewWorldPosition.Z,
|
||||
ActiveViewRotation.Pitch, ActiveViewRotation.Yaw, ActiveViewRotation.Roll,
|
||||
ActiveViewVoxel.X, ActiveViewVoxel.Y, ActiveViewVoxel.Z, ActiveViewDensity,
|
||||
ActiveResearchEnabled, ActiveResearchProfile);
|
||||
// UEngine::Exec is not routed through the game viewport in the command-line game
|
||||
// target, so HighResShot returns false there even with a live render viewport. Call
|
||||
// the viewport API directly; it schedules the same one-frame high-res capture.
|
||||
|
||||
Reference in new issue
Block a user