My procedural maze generator eventually hit an architectural limit: tens of thousands of modular elements, with significant variation, concentrated in a relatively small area. Culling, streaming, World Partition, and HLOD are all valid optimization layers — but my first goal was to improve the underlying representation of the generated content, not to paper over it downstream.
Houdini Engine already supports native ISM/HISM output. My problem was slightly different.
For gameplay modules, I still needed independent Blueprint Actors — chests, doors, enemies, anything with its own logic. But structural modules (ground, walls, caps) did not need separate Actor-level logic at all. What I wanted was for Houdini points to target specific HISM components inside one Unreal-owned Blueprint container:
BP_StructuralContainer
├─ HISM_Ground_I
├─ HISM_Ground_L
├─ HISM_Wall_Straight
└─ HISM_Wall_Corner
Native Houdini Engine ISM/HISM output instantiates by asset path — it doesn't have a concept of "this point belongs on the third named component inside an artist-authored container." Getting there meant building a typed integration layer on top of the Houdini Engine public API, not just consuming its default output.
The HDA now assigns one of two representation modes per point:
Instead of telling Unreal which mesh to instantiate directly, Houdini sends a semantic assignment. Unreal remains responsible for the meshes, materials, collision settings, and component configuration — the HDA never reaches into that; it only says which named target a given transform belongs to.
The bridge reads named PCG outputs and typed point metadata from the cooked HDA, then routes every resolved assignment to either an Actor or a specific HISM component. That gives the procedural system two clean options: Actors where independent logic is required, HISM containers where scale and editor performance matter.
On the Houdini asset, each structural module in the registry gets a structural_type, a topology_type, and — for the instanced path — a hism_component_name. The registry resolves those into the container path and component name the Unreal side will look for:
record = {
"registry_index": registry_index,
"representation_mode": "instanced",
"structural_type": structural_type,
"topology_type": topology_type,
"container_blueprint_name": blueprint_name,
"container_blueprint_path": _join_unreal_content_path(
container_root,
blueprint_name,
),
"hism_component_name": hism_component_name,
"static_mesh_name": static_mesh_name,
"static_mesh_path": _join_unreal_content_path(
mesh_root,
static_mesh_name,
),
}
This record is Houdini's entire opinion on the matter: a container path and a component name, both strings. It never touches a mesh reference, a material, or a collision setting — those stay entirely on the Unreal side, authored once on the container Blueprint itself.
The container Blueprint is an ordinary self-contained Actor with one HISM component per module variant, each given a meaningful component name:
On the C++ side, resolving a hism_component_name against a spawned or reused container Actor is a plain component lookup by name, cast to the expected type:
UHierarchicalInstancedStaticMeshComponent* FindNamedHism(AActor* ContainerActor, const FString& ComponentName, FString& OutError)
{
TInlineComponentArray Components;
ContainerActor->GetComponents(Components);
for (UActorComponent* Component : Components)
{
if (Component->GetName() == ComponentName)
{
if (UHierarchicalInstancedStaticMeshComponent* Hism = Cast(Component))
{
return Hism;
}
OutError = FString::Printf(TEXT("component '%s' is not a UHierarchicalInstancedStaticMeshComponent"), *ComponentName);
return nullptr;
}
}
OutError = FString::Printf(TEXT("named HISM component '%s' is missing"), *ComponentName);
return nullptr;
}
A missing or misspelled hism_component_name fails loudly, per placement, with the exact component name in the message — never a silent no-op. Placements grouped under the same container path are batched by HISM name, so one container Actor with four named components receives four separate AddInstances calls instead of one undifferentiated mesh dump.
Without this layer, the previous approach spawned one Blueprint Actor per structural instance. On a single generated level that meant thousands of individual, independently-ticking Actors in the Outliner for what is, structurally, repeated static geometry:
With the typed bridge, the same generation pass produces one reused container Actor per Blueprint path, with instances batched into the correct named HISM component:
The maze generator was the reason I built this layer, but the architecture itself is not maze-specific. Any high-volume procedural tool that needs more control than direct asset instancing provides — and that has a mix of "this needs its own logic" and "this is just repeated geometry" — can sit on the same contract: a typed placement record, Houdini deciding domain and target, Unreal owning everything about how that target actually renders and behaves.