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, Gameface should be initialized with the following settings.

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

All of the steps above are explained in detail below.

Standard rendering

The standard Gameface 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 Gameface 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 Gameface 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 Gameface with the following settings:

Before Gameface 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 Gameface 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 Gameface 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);
}