What rendering features are supported in splitscreen/with multiple views?

The documentation for Nanite currently mentions it doesn’t support Split Screen- however the only posts I can find discussing this are quite old and doing some tests locally it seems like it’s working. Before we go down a rabbit hole with potentially trying to render multiple views for a project I was wondering if I can get some up to date info on what render features are expected to work with this this- Nanite? (SW/HW) Lumen? VSMs? MegaLights? etc.

We aren’t deadset on using any particular tech but just knowing what is and isn’t supported/what kinds of problems we could expect if we tried to do this would be helpful.

Thanks!

[Attachment Removed]

Hello!

We don’t have an official list because splitscreen isn’t as well tested but it is supported in Fortnite and in general you should be able to use most of the major features in splitscreen.

Features that should work, though they may not have splitscreen optimizations.

Nanite (Per-view cull/raster pass) - Each view gets an independent Nanite draw pass. The single-pass multi-view optimization (r.Nanite.MultipleSceneViewsInOnePass) is currently ISR stereo only — split screen views are serialized. Cost scales linearly with view count.

VSM (Hybrid shared/per-view) - Physical page pool is shared; directional light clipmaps are per-view; local light shadow maps pick the closest view. No view count limit.

CSM (Per-view cascades) Each view creates its own cascades via DependentView. Shadow depth is rendered once per cascade; projection is per-view with FadeAlphas[] controlling per-view visibility.

First Person Meshes (per-player) - Each player gets their own first-person bounds, their own VSM first-person clipmap, and primitive ownership is enforced via IsOwnedBy(View.ViewActor). Per-view self-shadow tracing. There have been reports of Nanite first person meshes appearing in the wrong view, but that should be fixed in 5.8.

SLW (Per-view) - Standard per-view iteration. Each view gets its own tile classification and render pass

RVT (view-agnostic) - Uses a single global feedback buffer — all views write into it. RVT tile rendering uses its own internal orthographic view, independent of game views. No per-view distinction needed.

SVT (view-agnostic) - Shares the same global feedback pipeline as RVT. Streaming requests are gathered from all views collectively.

Volumetric Fog (Per-view) - Full independent fog computation per view — volume setup, light injection, voxelization, and integration all iterate per view.

Ray Tracing (Per-view) - RT scene is built once (shared TLAS), per-view effects (shadows, AO, reflections) dispatch individually. ShouldRenderRayTracingEffect checks Views[0] assuming all views share the same RT settings. No split screen disable.

Grooms (Per-view) - Per-view visibility via bit packing (supports up to 8 views). Split screen views each get independent processing.

Distance Fields (Per-view) - Each view maintains its own FGlobalDistanceFieldInfo and gets an independent UpdateGlobalDistanceFieldVolume call.

Distance Fields (AO Per-view ) - Controlled by r.DistanceFieldAO.MultiView (default 1 = enabled). When enabled, renders per-view. When 0, DF AO is completely disabled with >1 view.

HZB (Per-view) - Each view builds its own independent HZB from its viewport rect. BuildHZB called in a Views.Num() loop. Not shared.

Translucency (Per-view shared RT) - Uses shared render targets but renders per-view with viewport scissoring. Separate translucency textures tile each view into its own rect.

ISM/HISM (Per-view LOD + culling) - ISM selects LOD per-view. HISM does a full hierarchical tree traversal per view with independent frustum culling. GPU instance culling is multi-view aware.

TSR (Per-view) - Each view has its own FTSRHistory in ViewState. Called independently per view in the post-processing loop.

Megalights (Per-view) - Creates an independent FMegaLightsViewContext per view. No MAX_VIEWS gate like Lumen. check() asserts assume all views share the same config (translucency volume, async compute).

Features that have known splitscreen limitations

Niagara (Per-view rendering) - Sprite and mesh renderers iterate per-view with per-view distance culling and sorting. GPU sim runs once (using first view’s data) but is multi-view-family-aware. When using certain nodes that calculate distance to view only view 0 is considered.

Lumen - Hard limit of 2 views, LUMEN_MAX_VIEWS = 2 in LumenDefinitions.h. ShouldRenderLumenForViewFamily() returns false if Views.Num() > 2 (unless cube capture). 3+ player split screen = no Lumen GI/reflections. 2-player works but has known bugs: stochastic direct lighting hardcodes ViewIndex = 0, and mesh SDF culling can break for a distant second view.

Volumetric Clouds - Shadow map uses Views[0] only Cloud shadow maps and sky AO are computed from Views[0]'s camera position. A // TODO Make it work for all views comment exists. Players far from Player 1 may have incorrect cloud shadows. Cloud ray marching is per-view. However, cloud shadow maps and sky AO are anchored to Views[0] only — has a // TODO Make it work for all views comment. Secondary views may have slightly incorrect cloud shadows.

Light Batching (Shadow Denoising) Batching disabled for multi-view. const bool bDoShadowBatching = … && Views.Num() == 1; — RT shadow denoising batching is explicitly disabled with >1 view. Each shadowed light is rendered individually per view.

Motion Blur Post-motion-blur translucency may be broken based on // TODO: broken with split screen comment in PostProcessMotionBlur.cpp. The translucency compositing after motion blur doesn’t account for split screen viewport offsets correctly.

There are a lot of engine features so if there’s something specific I left out or some configuration please let me know.

[Attachment Removed]

Thanks! This is great information!

[Attachment Removed]