fix(world): the voxel field is in ACTOR space -- make every entry point agree
The city's hole is not at world (0,0), so the AVoxelWorld actor has to move.
It couldn't: the plugin was only HALF actor-relative, and had been for a long
time without symptoms because the actor always sat at the origin.
Already correct: GetBiomeAtWorldLocation, GetVoxelSurfaceHeightAt,
UpdateDecorations, UpdateLandmarks, UpdateWater, UVoxelDensityVolume::Update,
the passage debug draw, the clipmap material.
Not correct: the streaming centre, the streaming anchors, all six carve/fill
entry points, GetStrateAtPosition, and UVoxelAtmosphereManager::UpdateForPlayer
-- whose own comment documented the assumption out loud ("actor at
origin/identity"). Carving would have landed offset; the strate lookup would
have been quietly wrong by the actor's Z.
The trap worth recording: because the content managers already convert
internally, converting PlayerLastPos once at the source would have DOUBLE-
converted four call sites. The fix has to be per-boundary. That was only
visible after reading each consumer -- the estimate before that read was wrong
in both directions.
WorldToLocalCm / WorldToLocalVoxel / LocalVoxelToWorld are now declared as the
only sanctioned boundary between Unreal coordinates and voxel coordinates, and
the real deliverable is the invariant next to them: no `/ VOXEL_SIZE` applied
to a parameter named `World*` outside those three functions. A grep can check
that. The risk was never a missed site among the ones found -- it is the next
one nobody notices.
Also adds a translation-only guard in BeginPlay. Tiles, ClassifyBox verdicts,
the clipmap window, culling and streaming distance all assume world-axis-
aligned boxes; a rotation or non-unit scale breaks that structurally rather
than gracefully, so it logs an Error naming what was set.
With the actor at the origin every conversion is identity, so this is a no-op
until the actor actually moves. Built and confirmed working.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPUuCtn5zTLui6WybLbkNb
This commit is contained in:
1 parent
dfa1d5f5b1
commit
302cf16681
5 files changed
+608
-21
No files matched your search
@@ -318,6 +318,41 @@ public:
|
||||
* @param WorldPosition - Position in world space (Unreal units)
|
||||
* @return Strate index (0 = topmost), or -1 if outside all strates
|
||||
*/
|
||||
//=========================================================================
|
||||
// ESPACE MONDE <-> ESPACE ACTEUR / WORLD <-> ACTOR SPACE
|
||||
//=========================================================================
|
||||
// Le champ de densite est defini en espace ACTEUR : (0,0) est l origine de CET acteur, pas
|
||||
// celle du monde Unreal. Tout point venant d Unreal (position du pion, hit de trace, ancre de
|
||||
// streaming) DOIT passer par ces helpers avant de toucher quoi que ce soit cote voxel.
|
||||
//
|
||||
// The density field is authored in ACTOR space: (0,0) is THIS actor s origin, not Unreal s
|
||||
// world origin. Any point arriving from Unreal (pawn position, trace hit, streaming anchor)
|
||||
// MUST go through these helpers before touching anything voxel-side.
|
||||
//
|
||||
// INVARIANT VERIFIABLE PAR GREP / GREP-CHECKABLE INVARIANT:
|
||||
// aucun `/ VOXEL_SIZE` applique a un parametre nomme `World*` hors de ces fonctions.
|
||||
// no `/ VOXEL_SIZE` applied to a parameter named `World*` outside these functions.
|
||||
// C est la vraie garantie : le risque n est pas un site rate parmi ceux deja trouves, c est
|
||||
// le SITE SUIVANT que personne ne verra. The risk is not a missed site among those already
|
||||
// found - it is the NEXT one nobody notices.
|
||||
//
|
||||
// La racine est Static (voir BeginPlay) => la transform ne bouge pas en jeu, donc la relire a
|
||||
// chaque appel est gratuit et ne demande aucune invalidation.
|
||||
// The root is Static (see BeginPlay), so the transform cannot change during play: re-reading
|
||||
// it per call is free and needs no invalidation.
|
||||
|
||||
/** World cm -> actor-local cm. */
|
||||
UFUNCTION(BlueprintPure, Category = "Voxel World|Space")
|
||||
FVector WorldToLocalCm(FVector WorldPos) const;
|
||||
|
||||
/** World cm -> actor-local VOXEL coords (what every density / diff-layer API expects). */
|
||||
UFUNCTION(BlueprintPure, Category = "Voxel World|Space")
|
||||
FVector WorldToLocalVoxel(FVector WorldPos) const;
|
||||
|
||||
/** Actor-local VOXEL coords -> world cm (placing actors, debug draws, UI markers). */
|
||||
UFUNCTION(BlueprintPure, Category = "Voxel World|Space")
|
||||
FVector LocalVoxelToWorld(FVector VoxelPos) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Voxel World|Strate")
|
||||
int32 GetStrateAtPosition(FVector WorldPosition) const;
|
||||
|
||||
|
||||
Reference in new issue
Block a user