Files
VoxelForge/Standalone/Core/API.md
T
Fr0zkaandClaude Opus 5.5 fcb16fd265 wip(assembler): M1 round 2 -- surface recipe closer to legacy; native still slower and visibly buggy
Luna, M1 round 2 of 4: round 1's mismatch was an underfit recipe (two synthetic profiles,
missing large-scale surface terms). Now: biome IDs match 4,096/4,096, mean height offset
-1.366 vox, density MAE 274.04 -> 17.23 vox, sign mismatches 55.2% -> 18.14%. Bound audit
298 boxes / 8,046 points, 0 misses, negative control caught. Hash c5e0371612e927af at
W1/W8/W16. Surface query 8-14 ms / 4,096 points. Matched 3D capture pairs added.
Problems (my review of the captures + her timings):
- matched 120-tile views: full-detail readiness 5.227 s native vs 2.882 s legacy -- SLOWER;
- surface capture shows a rectangular flat-topped raised block with vertical walls
  (tile/patch-level height bug, inferred);
- cliff capture is broken (floating shard, debris trail), not a cliff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
2026-10-09 00:38:55 +02:00

200 lines
11 KiB
Markdown

# VoxelForgeCore API reference
Public header: `Core/include/VoxelForgeCore/VoxelForgeCore.h` (C++20, standard library only).
Build the static library and viewer with `Build.ps1 -Target All`, or only the library with
`Build.ps1 -Target Core`.
The public header uses only standard C++ types and can be included after Unreal's `CoreMinimal.h`.
`Core/verification/UnrealHeaderCoexistence.cpp` is the compile smoke check against the installed
Unreal 5.7 headers. Copied generator and compatibility declarations stay in the private
`vfcore::detail` implementation and do not appear in this API.
## Units and ownership
- `Vec3d` query positions and `Vec3i` voxel coordinates are in **voxels**.
- `TileKey.coordinate` is a tile coordinate; one coordinate step spans `32 << lod` voxels.
- Mesh vertex positions are **centimetres**. UVs, RGBA8 colors, normals and 32-bit indices are
returned per vertex / triangle in owned `std::vector`s.
- `MeshGroups::groundTriangleCount` and `ceilingTriangleCount` describe the contiguous index runs
emitted by the mesher. Ceiling is the final run. `skirtTriangleCount` is a subset of the ground
and ceiling runs. `surfaceVertexCount` ends before skirt vertices.
- A `World` owns its compiled field and edit log. The snapshot can be shared as immutable input.
Serialize compile/edit changes against query and tile-generation calls on that same `World`.
## Load and compile
`ResolvedWorldSnapshot::FromJson` accepts the normalized UTF-8 schema-v1 owner export used by the
standalone loader. It returns `std::nullopt` and fills `error` when parsing or asset resolution
fails. Read `configuration()` for the resolved scalar settings.
Implement `JobScheduler::parallel_for` in the host. It must run each index from zero to `count - 1`
exactly once and return only after all submitted work is complete. The library creates no threads.
`ShapeBuildRequest` supplies the detail and clip bounds in voxels, worker limit, detail variant,
far-world inclusion, and optional tunnel/detail profiles.
```cpp
std::string error;
auto snapshot = VoxelForgeCore::ResolvedWorldSnapshot::FromJson(json, error);
if (!snapshot) { /* report error */ }
VoxelForgeCore::World world(std::move(*snapshot));
VoxelForgeCore::ShapeBuildRequest build;
build.minVoxel = {-256, -768, -384};
build.maxVoxel = { 256, -256, 128};
build.clipMinVoxel = {-57344, -57344, -8192};
build.clipMaxVoxel = { 49152, 49152, 8192};
build.workerLimit = 8;
build.includeFarWorld = true;
if (!world.compile(build, hostScheduler, error)) { /* report error */ }
```
For a streamed shape world, compile the initial camera region once, then add deterministic detail
pages before generating any newly desired fine tile outside that region:
```cpp
const auto entering = world.desiredTiles(newCameraVoxels);
VoxelForgeCore::TileGenerationOptions options;
std::size_t pageCoveredTiles = 0;
if (!world.compileTileRegion(entering, 8, hostScheduler, error, &pageCoveredTiles)) {
/* report error */
}
for (const auto& key : entering) {
if (auto mesh = world.generateTile(key, options, error)) { /* upload and retain */ }
}
world.retainTileRegions(entering);
```
By default, the Core groups missing keys by LOD and builds one analytic primitive/bin region for
each entering LOD slab. The region bounds come from the requested absolute tile coordinates, with
an 8-voxel sampling apron; no dense lattice is allocated for unused parts of the slab. A tile's
samples therefore depend on its world coordinates and the world snapshot, not the camera path or
the order in which tiles arrive. `compileTileRegion` skips LODs at or above
`fullResolutionLodCount`, keys covered by the initial `ShapeBuildRequest`, and keys already
resident. Its optional output counts requested keys that received a new region. After the regions
needed by the next desired set compile, call `retainTileRegions` with that set to release regions
that are no longer needed. The Core owns region lifetime and mesh data; the host keeps still-visible
meshes resident until replacement tiles are generated and uploaded.
Pass `analyticOnly = false` to retain the reference packed-page compiler. Packed pages use absolute
parent-cell coordinates and an 8-voxel apron; each covers a 128-voxel cube or one larger coarse
tile. This path remains available for parity checks and workloads that need the packed lattice.
## World assembler manifest v1 (prototype; evaluator v1 and v2)
`ResolvedWorldSnapshot::FromJson` accepts an optional `world_assembly` object alongside the owner
snapshot. The object is the shipped-plan payload shape: a fixed-scale recipe and finite-strate plan
with hashes, no generated mesh or voxel samples. The current evaluator-v2 review payload is
[`round2/world_assembly.json`](../Research/WorldAssemblerM1/round2/world_assembly.json); the
evaluator-v1 sample remains at [`round1-manifest.json`](../Research/WorldAssemblerM1/round1-manifest.json).
Round 4 still needs to connect this payload to the season asset/hash path.
Every coordinate and scalar uses signed integer units of 1/256 voxel (`units_per_voxel: 256`),
independent of the plugin's 25 cm Core voxel and of tile size. The schema version is 1; evaluator
versions 1 and 2 are accepted, with evaluator 2 used for new recipes. Evaluator 1 retains its
original evaluation and hash semantics. JSON integer fields are canonicalized in declared field
order and hashed as 4- or 8-byte little-endian words with FNV-1a 64. Hashes are emitted as 16
lowercase hexadecimal characters; JSON key order and whitespace do not affect them. The root,
recipe, plan and each stratum carry a content hash. The recipe stores its seed, warped biome-map
settings and one to eight biome profiles; the plan stores finite-strate extents, cap settings,
stable-ID features, fixed-season water and route points. Bounds, feature count and route count are
validated before a manifest is accepted.
Evaluator 2 adds climate-based biome assignment, output-space blending of both ground and cap
profiles, per-biome relief and height warp, beach width, cliff limits, and optional per-biome cap
profiles. Feature types 1, 2 and 3 represent a cliff plane, a bounded 3D overhang box and an authored
cap feature. An overhang feature has a stable ID and a finite AABB clipped to its stratum; intervals
outside the box can use its certified influence bound, while intersecting intervals remain on the
evaluation path. Water surface and fill are separate sample outputs. The season water plane is fixed;
this block does not generate a water mesh.
```cpp
std::string error;
auto manifest = VoxelForgeCore::WorldAssemblyManifest::FromJson(payload, error);
if (!manifest || !manifest->validate(error)) { /* reject the payload */ }
const auto* loaded = snapshot.worldAssembly(); // null when the owner snapshot has no plan
```
`Heightfield2D` is the first field block. `point(xQ, yQ, zQ)` evaluates the biome map and blended
height profiles at fixed-scale coordinates, returning the ground and cap heights, primary and
neighbor biome IDs, Q16 blend weight and signed density. Evaluator 2 also returns the fixed water
surface and water-fill sample values. Negative density is solid. Its contract reads `biome` and
writes `height`, `rock`, `water` and `waterSurface`; route and `surfaceTags` remain declared channels
for later blocks. The detail envelope reports maximum absolute displacement and minimum feature
size. Influence is global in XY and limited to the finite stratum's Z extent, except for the
explicitly bounded evaluator-v2 feature boxes.
`interval(minXQ, minYQ, minZQ, maxXQ, maxYQ, maxZQ)` returns a conservative density range or
`known == false`; callers must keep evaluating when it is unknown. The current heightfield range
uses conservative profile, beach, cliff, cap and bounded-feature envelopes. The public
`AuditHeightfieldBounds` samples points in randomized boxes and targeted biome-border, cliff, cap,
negative-coordinate and overhang boxes, and includes a deliberately false one-sided range as a
negative control. A pass means no sampled point escaped and the negative control was rejected; it
is an audit of this block implementation, not a proof for future blocks.
## Queries and tiles
`densityAt(position)` returns signed density; negative is solid and nonnegative is air.
`isSolidAt` wraps that sign test. `isSolidAlongSegment(start, end, spacing)` samples evenly along
the segment with no interval wider than `spacing` voxels; it returns true if any sample is solid.
`classifyBox(origin, step, cells)` returns `allSolid`, `allAir` or `mixed` for mesher tile
classification.
`desiredTiles(cameraVoxels)` returns the snapshot's clipmap set. Pass it to
`prioritizeTiles(tiles, centerChunk)` when submitting work. Generate independent keys concurrently
on host workers:
```cpp
VoxelForgeCore::TileGenerationOptions options;
auto mesh = world.generateTile(key, options, error);
if (!mesh) { /* report error */ }
// mesh->vertices, mesh->indices and mesh->groups are owned by this result.
```
The optional `hashDensity` flag fills deterministic density, viewer-mesh, payload and topology
hashes. `captureDensitySamples` is a diagnostic option and retains the sampled lattice values.
## Deterministic edits
Build an `EditTransaction` with a monotonically increasing authority sequence and an ordered brush
array (`sphere`, `capsule`, `roundedBox`; `carve`, `addRock`, `densityOffset`). `carve` and
`addRock` apply hard signed-distance CSG. `densityOffset` applies `strength` inside a sphere or
inside/around a capsule or box with its `falloff` band; negative strength carves and positive
strength adds rock. This operation maps the plugin's soft `FVoxelModification` brushes into the
shared field. Apply the transaction against the currently desired keys:
```cpp
VoxelForgeCore::EditTransaction edit;
edit.sequence = 12;
VoxelForgeCore::EditBrush brush;
brush.shape = VoxelForgeCore::EditBrush::Shape::capsule;
brush.operation = VoxelForgeCore::EditBrush::Operation::densityOffset;
brush.a = {0.0, 0.0, 0.0};
brush.b = {12.0, 0.0, 0.0};
brush.radius = 3.0;
brush.strength = -10.0f;
brush.falloff = 2.0f;
edit.brushes.push_back(brush);
const auto affected = world.applyEditTransaction(edit, currentTiles, error);
if (affected) {
for (const auto& lodTiles : affected->affectedByLod)
for (const auto& key : lodTiles)
submitHostJob([&, key] {
std::string tileError;
return world.generateTile(key, options, tileError);
});
}
```
The transaction digest covers the sequence and each brush field in order. Replaying the same
sequence and values returns the original result; reusing a sequence with different values or
applying an older sequence is rejected. Each client must deserialize identical brush values and
apply transactions in the same sequence. `affectedByLod` is limited to the desired keys passed to
the call.
## Other outputs
`farConnectorSegments()` returns owned connector geometry, while `farConnectorCandidates(min,max)`
returns candidate indices overlapping a voxel-space box. The audit methods expose shape detail,
surface-family and camera-look checks for host diagnostics. All returned values are standard C++;
the host owns conversion to engine mesh, collision or renderer objects.