Section Groups & Sections
A Realtime Mesh’s geometry lives in a two-level structure inside each LOD: section groups (buffer sets) own the vertex/index streams, and sections draw ranges of those streams with a material and render settings. This page covers how you address them (keys), how you configure them, and the auto-section behavior that most meshes rely on. For where these sit in the overall object model, see Structure.
The API here is shown against URealtimeMeshSimple; the same keys and config types apply to the other Managed meshes.
Keys: addressing groups and sections
Section titled “Keys: addressing groups and sections”Everything is addressed by value-type keys rather than pointers, so the keys are stable, copyable, and safe to store. Keys are scoped to a LOD.
FRealtimeMeshBufferSetKey identifies a buffer set inside a LOD. Create one with:
const FRealtimeMeshLODKey LODKey(0);
// New-style: you supply the slot index explicitly (like a static-mesh material slot).FRealtimeMeshBufferSetKey GroupA = FRealtimeMeshBufferSetKey::Create(LODKey, 0, FName("Terrain"));
// Name-based: a stable slot index is derived from the name's CRC, so old FName-only// code keeps working. This is the form used throughout the examples.FRealtimeMeshBufferSetKey GroupB = FRealtimeMeshBufferSetKey::Create(LODKey, FName("Floor"));
// A guaranteed-unique group when you don't care about the name.FRealtimeMeshBufferSetKey GroupC = FRealtimeMeshBufferSetKey::CreateUnique(LODKey);A group key’s identity is the (LODIndex, SlotIndex) pair; the optional name is friendly metadata and does not participate in equality. (A name-based key and an explicit-index key that hashes to the same slot compare equal — that’s intentional, so legacy and new code interoperate on the same buffer set.)
FRealtimeMeshSectionKey identifies a section inside a LOD:
// From a group + name (legacy-style; records the group slot for back-compat lookups).FRealtimeMeshSectionKey Section = FRealtimeMeshSectionKey::Create(GroupKey, FName("Visible"));
// A unique section within a group.FRealtimeMeshSectionKey Unique = FRealtimeMeshSectionKey::CreateUnique(GroupKey);
// The key for the auto-created section of poly group N (see below).FRealtimeMeshSectionKey PolyGroup0 = FRealtimeMeshSectionKey::CreateForPolyGroup(GroupKey, 0);CreateForPolyGroup is the one you’ll use most, because auto-created sections use exactly these keys — so this is how you reach in and reconfigure them.
Creating a section group
Section titled “Creating a section group”On URealtimeMeshSimple you create a group and hand it the geometry as a FRealtimeMeshStreamSet:
FRealtimeMeshStreamSet StreamSet;// ...build the mesh into StreamSet with a builder (see Key Concepts)...
const FRealtimeMeshBufferSetKey GroupKey = FRealtimeMeshBufferSetKey::Create(FRealtimeMeshLODKey(0), FName("Box"));
RealtimeMesh->CreateBufferSet(GroupKey, StreamSet);CreateBufferSet has overloads taking the stream set by const-ref or by rvalue (MoveTemp(StreamSet) when you’re done with it), plus a config argument and a bShouldAutoCreateSectionsForPolyGroups flag (default true). See Public/RealtimeMeshSimple.h.
For building the
StreamSetitself — streams, builders,AppendBoxMeshand friends — see Key Concepts. This page assumes you already have one.
Section group config
Section titled “Section group config”FRealtimeMeshBufferSetConfig (in Public/Interface/Core/RealtimeMeshBufferSetConfig.h) controls how the group’s buffers are allocated and updated:
struct FRealtimeMeshBufferSetConfig{ ERealtimeMeshSectionDrawType DrawType; // Static (default) or Dynamic bool bComputeWritable; // default false};DrawType is the important one:
Static— lower rendering overhead, but changing the geometry requires recreating the render proxy for every component using the mesh. Best for geometry that rarely (or never) changes after creation.Dynamic— slightly higher overhead, but the buffers can be updated in place without a proxy recreate. Choose this for geometry you animate or edit frequently — it’s what makes the in-place fast paths eligible (see Updating Mesh Data).
bComputeWritable allocates the group’s GPU buffers with unordered-access (UAV) support so a compute pass can write directly into them. It implies dynamic-like behavior (no proxy recreate on change) since the geometry is mutated on the GPU rather than re-uploaded from the CPU. It’s independent of DrawType.
To make a group updatable in place, pass a Dynamic config at creation:
RealtimeMesh->CreateBufferSet( GroupKey, StreamSet, FRealtimeMeshBufferSetConfig(ERealtimeMeshSectionDrawType::Dynamic));(Grounded in ARealtimeMeshExample_Simple_FastUpdate, Source/RealtimeMeshExamples/Private/Simple/RealtimeMeshExample_Simple_FastUpdate.cpp.)
Auto-sections per poly group
Section titled “Auto-sections per poly group”By default (bShouldAutoCreateSectionsForPolyGroups == true), you usually don’t create sections by hand at all. When you create or update a Simple section group, RMC inspects the poly-group stream in your StreamSet and automatically creates one section per poly group, keyed by FRealtimeMeshSectionKey::CreateForPolyGroup(GroupKey, PolyGroupIndex). If the mesh has no poly-group stream, a single section covering the whole buffer is created.
By default each auto-created section is configured with its material slot set to its poly-group index. To point poly group 0 at material slot 0, reconfigure that section:
const FRealtimeMeshBufferSetKey GroupKey = FRealtimeMeshBufferSetKey::Create(0, FName("Box"));RealtimeMesh->CreateBufferSet(GroupKey, StreamSet);
// Reach the auto-created section for poly group 0 and set its config.RealtimeMesh->UpdateSectionConfig( FRealtimeMeshSectionKey::CreateForPolyGroup(GroupKey, 0), FRealtimeMeshSectionConfig(0)); // material slot 0(This exact pattern is used in ARealtimeMeshExample_Simple_LODs and ARealtimeMeshExample_Simple_Collision.)
You can toggle the behavior per group:
RealtimeMesh->SetShouldAutoCreateSectionsForPolyGroups(GroupKey, false);bool bAuto = RealtimeMesh->ShouldAutoCreateSectionsForPolygonGroups(GroupKey);When auto-creation is off, create sections yourself with the Managed CreateSection API described next.
Section config
Section titled “Section config”FRealtimeMeshSectionConfig (in Public/Interface/Core/RealtimeMeshSectionConfig.h) is the per-section render configuration:
struct FRealtimeMeshSectionConfig{ int32 MaterialSlot; // which material slot this section draws with (default 0) bool bIsVisible; // default true bool bCastsShadow; // default true bool bIsMainPassRenderable; // advanced; default true bool bForceOpaque; // advanced; default false};MaterialSlot chooses which of the mesh’s material slots the section renders with — see Materials. The constructor takes the slot index, so FRealtimeMeshSectionConfig(2) is a visible, shadow-casting section on slot 2.
Creating and updating sections manually
Section titled “Creating and updating sections manually”On any Managed mesh (URealtimeMeshManaged, so Simple/Procedural/Dynamic), you can create a section explicitly against a stream range and config:
RealtimeMesh->CreateSection( SectionKey, FRealtimeMeshSectionConfig(0), StreamRange, /*bShouldCreateCollision=*/ false);
RealtimeMesh->UpdateSectionConfig(SectionKey, FRealtimeMeshSectionConfig(1), /*bShouldCreateCollision=*/ false);RealtimeMesh->UpdateSectionRange(SectionKey, NewStreamRange);The bShouldCreateCollision flag marks the section’s triangles for inclusion in complex (per-triangle) collision — see Collision.
Stream ranges
Section titled “Stream ranges”A section draws a sub-range of its group’s buffers, described by FRealtimeMeshStreamRange — a Vertices range and an Indices range, both FInt32Range. Auto-created sections get the full valid range of the buffer set; you only set ranges explicitly when you want a section to draw a subset (for example a shadow-only section over part of the index buffer). Use UpdateSectionRange to change it later.
Visibility and shadow casting
Section titled “Visibility and shadow casting”You can flip visibility and shadow casting without rebuilding the section’s config. These return a TFuture<ERealtimeMeshProxyUpdateStatus> (and have Blueprint overloads that take a completion callback):
RealtimeMesh->SetSectionVisibility(SectionKey, false);RealtimeMesh->SetSectionCastShadow(SectionKey, true);
bool bVisible = RealtimeMesh->IsSectionVisible(SectionKey);bool bShadow = RealtimeMesh->IsSectionCastingShadow(SectionKey);FRealtimeMeshSectionConfig Config = RealtimeMesh->GetSectionConfig(SectionKey);See Updating Mesh Data for what that TFuture return means.
Enumerating and removing
Section titled “Enumerating and removing”TArray<FRealtimeMeshBufferSetKey> Groups = RealtimeMesh->GetBufferSets(FRealtimeMeshLODKey(0));TArray<FRealtimeMeshSectionKey> Sections = RealtimeMesh->GetSectionsInBufferSet(GroupKey);
RealtimeMesh->RemoveSection(SectionKey); // TFuture-returning; also a callback overloadRealtimeMesh->RemoveBufferSet(GroupKey); // removes the group and its streamsGetBufferSets is exactly how the dynamic-update example decides whether to create a group or update the existing one (ARealtimeMeshExample_Simple_DynamicUpdate, Source/RealtimeMeshExamples/Private/Simple/RealtimeMeshExample_Simple_DynamicUpdate.cpp).