RealtimeMesh Procedural
URealtimeMeshProcedural mirrors UProceduralMeshComponent’s (PMC’s) Blueprint surface so an existing PMC
project can move onto RMC with mostly find-and-replace changes. You supply geometry as parallel TArrays —
positions, triangles, normals, UVs, colors, tangents — through CreateMeshSection / UpdateMeshSection,
exactly as with PMC. Under the hood each PMC section index maps to its own section group with a single
section and independent buffers, matching PMC’s “an update is local to one section” semantics.
Header: Source/RealtimeMeshComponent/Public/RealtimeMeshProcedural.h.
Once you’re running, consider adopting
URealtimeMeshSimplefor the sections that need polymorphic stream layouts, polygroup auto-sectioning, or minimum-copy per-frame updates — Procedural trades those away for PMC parity.
Initializing
Section titled “Initializing”#include "RealtimeMeshProcedural.h"
URealtimeMeshProcedural* RealtimeMesh = Component->InitializeRealtimeMesh<URealtimeMeshProcedural>();In Blueprint, use the static InitializeRealtimeMeshProcedural(Owner) node.
Creating a section
Section titled “Creating a section”CreateMeshSection takes the familiar PMC parameter list. It replaces any existing section at the same
index:
TArray<FVector> Vertices;TArray<int32> Triangles;TArray<FVector> Normals;TArray<FVector2D> UV0;TArray<FColor> VertexColors;TArray<FRealtimeMeshProceduralTangent> Tangents;// ... fill the arrays ...
RealtimeMesh->CreateMeshSection( /*SectionIndex*/ 0, Vertices, Triangles, Normals, UV0, VertexColors, Tangents, /*bCreateCollision*/ true);The ARealtimeMeshExample_Procedural_Basic example
(Source/RealtimeMeshExamples/Private/Procedural/RealtimeMeshExample_Procedural_Basic.cpp) builds a box
this way (using URealtimeMeshProceduralMeshLibrary::GenerateBoxMesh to fill the arrays, mirroring PMC’s
UKismetProceduralMeshLibrary).
The _LinearColor variant
Section titled “The _LinearColor variant”CreateMeshSection_LinearColor mirrors PMC’s linear-color overload: it takes FLinearColor vertex colors
and up to four UV channels (UV0–UV3):
RealtimeMesh->CreateMeshSection_LinearColor( 0, Vertices, Triangles, Normals, UV0, UV1, UV2, UV3, LinearVertexColors, Tangents, /*bCreateCollision*/ false, /*bSRGBConversion*/ false);bSRGBConversion controls how the FLinearColor inputs pack into the FColor vertex stream. It defaults
to false (no conversion) so the values round-trip faithfully to the material’s Vertex Color node; pass
true if you instead want the stored color to match the swatch as displayed.
Updating a section
Section titled “Updating a section”UpdateMeshSection updates vertex attributes on an existing section without changing topology — the index
count must match the original CreateMeshSection. Any optional array may be left empty to leave that
stream unchanged, which is how you cheaply animate just positions:
// Positions only — pass empty arrays for the streams you're not touching.const TArray<FVector> EmptyNormals;const TArray<FVector2D> EmptyUVs;const TArray<FColor> EmptyColors;const TArray<FRealtimeMeshProceduralTangent> EmptyTangents;
RealtimeMesh->UpdateMeshSection(0, NewVertices, EmptyNormals, EmptyUVs, EmptyColors, EmptyTangents);There is a matching UpdateMeshSection_LinearColor for the four-UV / linear-color layout. The
ARealtimeMeshExample_Procedural_Update example
(Source/RealtimeMeshExamples/Private/Procedural/RealtimeMeshExample_Procedural_Update.cpp) creates a grid
once, then animates only its vertex positions each tick this way.
Reading, clearing, and visibility
Section titled “Reading, clearing, and visibility”GetMeshSection(Index, Vertices, Triangles, Normals, UV0..UV3, VertexColors, Tangents)reads a section back out into CPU arrays; returnsfalseif no section exists at that index. (Tangents come back withbFlipTangentY = false— the flip bit is baked into the stored basis at write time and can’t be recovered.)ClearMeshSection(Index)removes one section;ClearAllMeshSections()removes them all. The index space is not compacted — cleared indices become holes.SetMeshSectionVisible(Index, bVisible)/IsMeshSectionVisible(Index)toggle rendering.GetNumSections()returns the highest-ever-allocated index plus one (including holes), matching PMC.
Collision
Section titled “Collision”CreateMeshSection’sbCreateCollisionflag gives that section per-poly (complex) collision, as in PMC.AddCollisionConvexMesh(ConvexVerts)appends a convex hull to the simple-collision shapes;ClearCollisionConvexMeshes()removes them.GetUseComplexAsSimpleCollision()/SetUseComplexAsSimpleCollision(bool)mirror PMC’sbUseComplexAsSimpleCollision. Set it tofalseif you give the mesh simple shapes and want it simulated.
See Collision for the broader collision model.
Migrating from ProceduralMeshComponent
Section titled “Migrating from ProceduralMeshComponent”A practical checklist:
- Swap the component. Replace
UProceduralMeshComponentwithURealtimeMeshComponent, then create the mesh withInitializeRealtimeMesh<URealtimeMeshProcedural>()(C++) or theInitializeRealtimeMeshProceduralnode (Blueprint). Section calls go on the returnedURealtimeMeshProcedural, not the component. - Swap the tangent type. Replace
FProcMeshTangentwithFRealtimeMeshProceduralTangent— it has the sameTangentX+bFlipTangentYfields and constructors, so this is a type-name change only. (RMC defines its own so it doesn’t depend on the ProceduralMeshComponent module.) - Keep your
CreateMeshSection/UpdateMeshSectioncalls — the parameter order and the “empty array leaves the stream as-is” update semantics match PMC. The_LinearColoroverloads keep the four-UV layout. - Check vertex-color color space. RMC’s
bSRGBConversiondefaults tofalse(values round-trip to the material). If your PMC content relied on the engine’s sRGB packing, passbSRGBConversion = true. - Move collision setup over.
bCreateCollision,AddCollisionConvexMesh/ClearCollisionConvexMeshes, andGet/SetUseComplexAsSimpleCollisionmap one-to-one. - Swap the mesh-generation helper. Use
URealtimeMeshProceduralMeshLibrarywhere you usedUKismetProceduralMeshLibrary.
Unsupported PMC extras (secondary buffers, custom render paths, etc.) aren’t exposed here — if you relied
on them, that content belongs on URealtimeMeshSimple instead.