Distance Fields
A mesh distance field (MDF) is a signed distance field baked into a sparse volume texture. The engine uses it for Lumen global illumination, distance-field soft shadows, and distance-field ambient occlusion (DFAO). Static meshes get theirs at cook time; a RealtimeMesh has to generate one at runtime, from whatever geometry it currently holds.
RMC generates distance fields with the standalone RealtimeMeshSDF module (a self-contained GPU/CPU mesh→SDF generator) and applies them through RealtimeMeshExt. There are three entry points, from highest-level to lowest.
Requirements
Section titled “Requirements”- The project setting Generate Mesh Distance Fields must be enabled (Project Settings → Engine → Rendering). Without it the engine allocates no distance-field atlas and an applied field is ignored.
- The GPU generation path needs a real RHI — it does not run under
-NullRHI. A CPU path is available for headless or background use.
Recommended path: URealtimeMeshSDFLibrary
Section titled “Recommended path: URealtimeMeshSDFLibrary”URealtimeMeshSDFLibrary (in RealtimeMeshExt, header RealtimeMeshSDFLibrary.h) is the one-call bridge: it reads a section group’s geometry, generates the field on the GPU, packs it into the engine’s sparse-brick format, and applies it to the mesh via the standard SetDistanceField path — so Lumen / DF shadows / DFAO consume it. Generation is explicit and on-demand.
It operates on a section group, identified by a FRealtimeMeshBufferSetKey. Every entry point is available as a C++ Async function returning a TFuture, and as a Blueprint-callable function reporting completion through a callback.
#include "RealtimeMeshSDFLibrary.h"
// Mesh is a URealtimeMeshSimple*; Key identifies the section group to convert.URealtimeMeshSDFLibrary::GenerateAndApplyDistanceFieldAsync(Mesh, Key, /*ResolutionScale*/ 1.0f) .Next([](ERealtimeMeshProxyUpdateStatus Status) { UE_LOG(LogTemp, Log, TEXT("Distance field applied (status %d)."), static_cast<int32>(Status)); });ResolutionScale is the engine’s DistanceFieldResolutionScale (1 = default detail, higher = finer). The generated field is sized the UE way and gets the exterior band added automatically, so it matches a baked static-mesh distance field at the same scale.
From resident GPU buffers
Section titled “From resident GPU buffers”If the mesh has already rendered, the ...FromResident variants skip the CPU read-back and geometry re-upload entirely — the field builds straight from the vertex/index buffers already resident on the GPU:
URealtimeMeshSDFLibrary::GenerateAndApplyDistanceFieldFromResidentAsync(Mesh, Key, 1.0f);This requires the mesh’s render proxy to exist (it must have been rendered) and manual-vertex-fetch support (the position SRV). It uses the mesh’s local bounds plus BoundsPadding.
Both variants also have Blueprint-callable and non-Async forms (GenerateAndApplyDistanceField, GenerateAndApplyDistanceFieldFromResident) that report completion through a FRealtimeMeshManagedCompletionCallback.
Direct data path
Section titled “Direct data path”If you already have a distance-field volume (from your own pipeline, or from the low-level generator below), apply it directly. On URealtimeMeshSimple:
FRealtimeMeshDistanceField DistanceField(VolumeData); // from an FDistanceFieldVolumeDataMesh->SetDistanceField(MoveTemp(DistanceField));// ...or Mesh->ClearDistanceField(); to remove it.FRealtimeMeshDistanceField (header Mesh/RealtimeMeshDistanceField.h) is RMC’s serializable wrapper around the engine’s sparse distance-field volume; it constructs from an FDistanceFieldVolumeData and can hand back rendering data. URealtimeMeshSimple::SetDistanceField returns a TFuture<ERealtimeMeshProxyUpdateStatus> (there is also an overload taking a completion callback), and there is a matching ClearDistanceField.
Low-level core: RealtimeMesh::SDF
Section titled “Low-level core: RealtimeMesh::SDF”The RealtimeMeshSDF module generates the raw volume, decoupled from any RealtimeMesh. Its public headers (RealtimeMeshSDFGenerator.h, RealtimeMeshSDFGenerate.h, …) are façades that alias the shared core into the RealtimeMesh::SDF namespace — always write the RealtimeMesh::SDF:: spelling (examples do using namespace RealtimeMesh; then SDF::).
You feed it a FSdfMeshInputCPU (positions + a flat uint32 index list) and a FSdfBuildParams, and get back a FSdfVolume:
#include "RealtimeMeshSDFGenerator.h"
using namespace RealtimeMesh;
SDF::FSdfBuildParams Params;Params.ResolutionMode = SDF::ESdfResolutionMode::Auto; // engine-matching sizing + exterior bandParams.ResolutionScale = 1.0f; // Auto mode: the DistanceFieldResolutionScaleParams.bComputeSign = true; // false => unsigned distance fieldParams.Precision = SDF::ESdfPrecision::Float32;
SDF::FSdfMeshInputCPU Input;Input.Positions = Positions; // TArrayView<const FVector3f>Input.Indices = Indices; // TArrayView<const uint32>, 3 per triangle
// GPU path: returns immediately, future fulfilled after readback.SDF::GenerateDistanceField(Input, Params).Next([](SDF::FSdfVolume Volume){ if (Volume.IsValidVolume()) { /* pack + apply, or inspect */ }});The generation entry points (in RealtimeMesh::SDF):
GenerateDistanceField(FSdfMeshInputCPU, FSdfBuildParams)— GPU path; returns aTFuture<FSdfVolume>. The portable choice for any mesh source.GenerateDistanceFieldCPU(...)— runs entirely on the CPU (no RHI), synchronous; call it from a worker thread for background/asset-load use.GenerateDistanceFieldCPUAsync(...)wraps it on the thread pool.GenerateDistanceField(FSdfMeshInputGPU, ...)— build from already-resident GPU buffers, no re-upload.Generate(FSdfMeshInputCPU, FSdfGenerateRequest)(headerRealtimeMeshSDFGenerate.h) — the unified request: ask for a distance field and/or cards in one call, choosing CPU or GPU; when both are requested the SDF volume is built once and shared.
On failure every variant still completes, but with an invalid volume — check FSdfVolume::IsValidVolume().
FSdfBuildParams options that matter
Section titled “FSdfBuildParams options that matter”ResolutionMode—Auto(default) derives resolution from mesh size the UE way and adds the exterior band;Explicituses your exactResolutionandBounds.ResolutionScale/VoxelDensity/MaxResolution— the Auto-mode sizing knobs (ResolutionScaleis the engine’sDistanceFieldResolutionScale).Resolution— the exact voxel grid dimensions, used only inExplicitmode.Bounds/BoundsPadding— supply explicit world-space bounds, or leaveBoundsinvalid to auto-fit and pad.bComputeSign— set false for an unsigned field.Precision—Float32(default) orFloat16storage.
Once you have a volume, pack it into engine data with SDF::PackToDistanceFieldVolumeData(Volume, MeshBounds, OutData) (header RealtimeMeshSDFPacker.h), wrap it in a FRealtimeMeshDistanceField, and apply it via the direct data path above. The URealtimeMeshSDFLibrary calls do all of this for you.
GPU vs CPU
Section titled “GPU vs CPU”- GPU (
GenerateDistanceField) is the fastest for interactive/runtime use, but needs a real RHI and can’t run under-NullRHI. - CPU (
GenerateDistanceFieldCPU) is self-contained and RHI-free — ideal for background threads and asset loading. It builds an LBVH and uses a band-limited Fast Winding Number for the sign; it is far faster than a naive per-voxel generator, but still heavier than the GPU path for large volumes.
Deprecated API
Section titled “Deprecated API”The old URealtimeMeshDistanceFieldGeneration API (RealtimeMeshDistanceFieldGenerator.h) has been removed. Use URealtimeMeshSDFLibrary::GenerateAndApplyDistanceField[Async], or RealtimeMesh::SDF::GenerateDistanceFieldCPU + PackToDistanceFieldVolumeData if you need the raw path. The output is engine-equivalent to the old generator but not bit-identical.
Examples
Section titled “Examples”ARealtimeMeshExample_Simple_DistanceField(Source/RealtimeMeshExamples/Private/Simple/) — builds a box, generates a GPU distance field with the low-levelSDF::GenerateDistanceField, draws a color-coded slice (red inside, green outside), and can apply the field / cards / full Lumen path to the mesh viaURealtimeMeshSDFLibrary.ARealtimeMeshExample_Simple_DistanceFieldProfile— sweeps grid resolutions and profiles CPU vs GPU generation time usingSDF::GenerateDistanceFieldCPUandSDF::GenerateDistanceField.