Compositor (3D UI)

The Compositor feature allows for rendering elements of the HTML page as completely separate geometries, unrestricted by the in-world Mesh the View is bound to.


Quick usage guide

  • Firstly, Prysm should be initialized with the following settings.

  • Add a Prysm Component to an in-world Mesh.

All of the steps above are explained in detail below.

Standard rendering

The standard Prysm View renders its content by transforming all HTML elements and then flattening the Z coordinate so everything is placed on a single plane (Texture). That Texture is then displayed either on the HUD (HUD View/UMG Widget) or attached to an in-world Mesh and rendered onto it (in-world View).

When using a HUD View, you can author the HTML/CSS in such way that it simulates a 3D object and looks quite convincing, since the View is attached to the player’s screen and is independent of the player’s movement/rotation.

In-world Views, however, are dependent on the position/orientation of the player and break the 3D illusion quite easily. That’s because Prysm renders the flattened 3D elements on a flat plane, as can be seen by the wireframe screenshot below (the View is attached to the purple plane).

Rendering with the Compositor

Here’s where the Compositor feature comes in. It allows clients to mark DOM elements with the custom coh-compositor-id CSS property, giving the composed object a unique identifier. The Prysm UE integration features a default Compositor implementation (see RenoirSublayerCompositor.cpp and the FCohCompositor class)

Requirements for using the feature (thread safety)

Some UE APIs need to be invoked on a specific thread. In order to avoid race conditions, you should set initialize the Prysm with the following settings:

Before Prysm 1.32:

Info.ExecuteLayoutOnDedicatedThread = false; // In the UCohtmlBaseComponent::CreateView method (CohtmlBaseComponent.cpp)
Info.ExecuteCommandProcessingWithLayout = true; // In the UCohtmlBaseComponent::CreateView method (CohtmlBaseComponent.cpp)
Params.UseDedicatedLayoutThread = false; // In the FCohtmlPlugin::InitializeLibrary method (CohtmlPlugin.cpp)
Params.AllowMultithreadedCommandProcessing = true; // In the FCoherentRenderingPlugin::InitializeLibrary method (CoherentRenderingPlugin.cpp)


From Prysm 1.32 and after:

  • In C++:
Info.ExecuteCommandProcessingWithLayout = true; // In the UCohtmlBaseComponent::CreateView method (CohtmlBaseComponent.cpp)
Params.AllowMultithreadedCommandProcessing = true; // In the FCoherentRenderingPlugin::InitializeLibrary method (CoherentRenderingPlugin.cpp)
  • Alternatively, this can also be done in the Unreal Editor:

    • The AllowMultithreadedCommandProcessing option can be toggled in the plugin settings (requires a restart of the Unreal Editor):
    • The ExecuteCommandProcessingWithLayout option can be controlled on a per View basis either from the SetupView Blueprint function:

      Or in the Unreal Editor’s Details Panel, while editing a Cohtml component:

Using the Compositor

The default Compositor (The FCohCompositor class) is set up to create, destroy, and manage the whole lifetime of composed surfaces. It does so by creating new geometries for those surfaces and adds them as children of the Actor that the Prysm View is attached to.

The only thing that the client needs to do is to author the HTML/CSS, and the 3D transforms from the CSS will be applied directly in the 3D world!

Here’s an example that uses 3D transformations in the same UI as before, along with the coh-composition-id property that will force rendering on newly spawned 3D geometry:

<div id="mapContainer">
    <div id="map">
        <div>...</div>
    </div>
</div>
#mapContainer {
    /* The parent of the composed element must use preserve-3d to preserve 3D transformations*/
    transform-style: preserve-3d;
}
#map {
    coh-composition-id: map;
    transform: rotateY(-30deg);
}