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.
HUD Views/UMG widgets are not supported.
In the HTML/CSS code, add the new
coh-composition-id: myComposition;
CSS property to the element you want to compose.In the HTML/CSS code, add
transform-style: preserve-3d
to the parent of the composed element.Add some 3D transformations to the element in the CSS code and watch them materialize in the UE world!
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 perView
basis either from theSetupView
Blueprint function:Or in the Unreal Editor’s
Details Panel
, while editing aCohtml component
:
- The
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!
transform-style: preserve-3d;
style. Otherwise, the element’s transform will be flattened to 2D before being passed to the compositor.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);
}