Skip to content
PRODUCT GITHUB  ↗

Stream Linkage

A stream linkage (FRealtimeMeshStreamLinkage) ties multiple streams together so that operations affecting the size of one stream affect them all. This keeps secondary vertex streams the same length as the primary one, so you can add a vertex once and then set only the streams you care about.

A linkage holds raw pointers to the streams it binds, so the streams must outlive the linkage. It is also non-copyable and non-movable — bind it in place. When the linkage is destroyed it unbinds every stream it holds.

The local mesh builder uses linkages internally to keep its position, tangents, texcoords, and color streams locked together, so you often don’t need to manage one by hand. When you do want the behavior with your own streams, use it directly:


using namespace RealtimeMesh;
// Create our position stream.
FRealtimeMeshStream PositionStream = FRealtimeMeshStream::Create<FVector3f>(FRealtimeMeshStreams::Position);
// Create our tangents stream, stored at normal precision.
FRealtimeMeshStream TangentsStream =
FRealtimeMeshStream::Create<FRealtimeMeshTangentsNormalPrecision>(FRealtimeMeshStreams::Tangents);
// Create the linkage we'll use to bind the vertex streams together.
FRealtimeMeshStreamLinkage VerticesLinkage;
// Bind the position stream with a default row value of the zero vector.
// We can build the default value directly because we know the type.
VerticesLinkage.BindStream(PositionStream, FRealtimeMeshStreamDefaultRowValue::Create(FVector3f::ZeroVector));
// Bind the tangents stream. We pass the value we want plus the stream's final layout, so the conversion
// happens once and the packed result is then blitted into each new row.
VerticesLinkage.BindStream(TangentsStream, FRealtimeMeshStreamDefaultRowValue::Create(
FRealtimeMeshTangentsNormalPrecision(FVector3f::ZAxisVector, FVector3f::XAxisVector),
TangentsStream.GetLayout()));
// Set up builders to make working with the streams easier.
TRealtimeMeshStreamBuilder<FVector3f> PositionBuilder(PositionStream);
TRealtimeMeshStreamBuilder<FRealtimeMeshTangentsHighPrecision, FRealtimeMeshTangentsNormalPrecision> TangentsBuilder(TangentsStream);
// Adding to the position stream also grows the tangents stream to match and fills it with the default value.
// It doesn't matter which linked stream you call Add on — they all resize together.
int32 Index = PositionBuilder.Add(FVector3f(1, 0, 0));
// Now just set the tangent for this row via indexed assignment.
// Do NOT call Add again on the secondary stream to set the value — that would add a second row to every
// linked stream instead of filling the existing one.
TangentsBuilder[Index] = FRealtimeMeshTangentsHighPrecision(FVector3f(0, 1, 0), FVector3f(0, 0, 1));

When you know up front how many rows you want to add across every linked stream, the linkage’s batch API is dramatically cheaper than repeated single-row adds — it does the growth math once and applies it to every member in a single pass:

// Add 100 rows to every linked stream, filling them with each stream's default value.
// Returns the starting row index.
int32 Start = VerticesLinkage.AddRowsZeroed(100);
// Or add 100 uninitialized rows if you're going to write every one immediately.
int32 StartRaw = VerticesLinkage.AddRowsUninitialized(100);
// Force every linked stream to an exact row count, growing (with defaults) or shrinking as needed.
VerticesLinkage.SetNumRows(64);
// Remove a run of rows from every linked stream at once.
VerticesLinkage.RemoveRows(/* StartIdx */ 10, /* Count */ 5);
// Preallocate capacity across every linked stream.
VerticesLinkage.ReserveRows(256);