HomeModule plugins › AFM_Spectator
Module

AFM_Spectator

Spectator camera and manager, with modes for following a player and for fixed cinematic viewpoints.

What it gives you

  • A spectator view independent of the VR player
  • Follow and fixed camera modes
  • A cleaner output for streaming and capture

Requires

None

Required by

AFE_Showroom

4 assets21 API members

Description

A VR headset view makes poor video — it is shaky and mono. AFM_Spectator provides a second camera that can follow the player smoothly or sit at a fixed cinematic position, which is what you want for demos, trade shows and recorded footage.

BP_Manager_Spectator coordinates the available cameras and modes; BP_SpectatorCamera is the placeable camera; Comp_Spectator drives the behaviour.

Setup

  1. Enable AFM_Spectator.
  2. Place a BP_Manager_Spectator in the level.
  3. Place BP_SpectatorCamera actors at the viewpoints you want.
  4. Select a mode from E_Spectator_Modes.

Usage

Following the player

Choose the follow mode; the camera smooths its motion rather than copying head movement directly.

Fixed viewpoints

Place cameras and switch between them for a multi-angle demo.

The spectator view alongside the headset view
AFM_Spectator_result.pngThe spectator view alongside the headset view
The spectator view alongside the headset view

Key properties

PropertyWhen to change
Spectator modeFollow or fixed
Camera smoothingHow closely the follow camera tracks

Extending

Derive from BP_SpectatorCamera for custom framing behaviour.

Example map

Set up in the Showroom for demo purposes.

Troubleshooting

The spectator view is still the headset view. The spectator screen mode is set to a mirrored mode — the VR pawn sets SingleEyeCroppedToFill by default and the manager must override it.

API reference

Every blueprint asset in this plugin. Expand an asset to see its members.

Blueprints

BP_Manager_Spectator6 members
extends Actor
KindNameSignatureDescription
eventRegisterSpectator(ref const SpectatorComponent: Comp_Spectator, ref const Key: name)Files a spectator component in the coordinator's lookup under the given key so it can later be activated by name. Called by every spectator component at begin play; an empty key is refused with a log message, and two components sharing a key leave only the last one reachable.
eventActivateSpectator(Spectator: Comp_Spectator)Makes the given spectator the live feed: stops whichever one was running, starts its capture, broadcasts New Spectator Activated with the component, its owning actor and its render target, then reapplies the preferred screen mode. Does nothing if that spectator is already recorded as the active one.
eventDeactivateActiveSpectator()Stops whichever spectator is currently the live feed and returns the headset mirror to a single cropped eye. Does nothing when no spectator has been activated yet.
eventActivateSpecatorByKey(ref const Key: name)Activates the spectator registered under the given key, which is the Key set on the spectator component or the Name on a spectator camera actor. Keys that were never registered are ignored without a warning.
eventSetScreenMode(ScreenMode: E_Spectator_Modes)Records the preferred layout and applies it to the headset mirror straight away. The two corner layouts are the reverse of their names: Texture Top Right fills the screen with the spectator feed and insets the headset view top right, while Eye Top Right shows the headset view full screen with the feed inset.
eventDeactivateSpectator(Spectator: Comp_Spectator)Stops the given spectator's capture and returns the headset mirror to a single cropped eye, provided it is the one currently live. The record of the active spectator is left in place, so that same spectator cannot be started again until a different one has been activated.
BP_SpectatorCamera3 members
extends Actor
KindNameSignatureDescription
varKeyKeyInput key that toggles this camera's feed on and off. The actor listens on player zero and does not consume the press, so the same key still reaches the rest of your input handling.
varNamenameIdentifier copied onto the camera's spectator component as its key when the actor is constructed, and shown on the label that floats above the camera in the editor. Left at None the camera never registers with the coordinator and cannot be selected by key.
eventInputKey_AnyKey_Pressed(Key: Key)Called on every key press player zero receives; when the pressed key matches Key, toggles this camera's spectator feed. The press is passed on rather than consumed.

Components

Comp_Spectator10 members
extends CameraComponent
KindNameSignatureDescription
varSpectatorScreenSizeSettingsVector2DResolution in pixels of the render target the live feed is drawn into, width by height, truncated to whole numbers. The target is created once on first use, so changing this after the feed has started has no effect, and leaving either axis at zero gives no usable picture.
varKeySettingsnameIdentifier this component registers under with the coordinator at begin play, and the name Activate Spectator By Key looks up. Give every spectator in the level its own; left at None the component is not registered and a warning is logged instead. On a spectator camera the construction script overwrites it with that actor's Name.
fngetSpectatorHelper(out SpectatorHelper: BP_Helper_Spectator)Returns the hidden capture actor that renders this feed, spawning it, attaching it to the component and pointing its scene capture at the render target the first time it is asked for. Cached afterwards; despite being a pure node it does spawn an actor on that first call.
fngetSpectatorCoordinator(out SpectatorCoordinator: BP_Manager_Spectator)Returns the level's spectator coordinator, taking the first one it finds and spawning one if the level has none, then caching the result. Placing a coordinator by hand is therefore optional.
fngetRenderTarget(out RenderTarget: TextureRenderTarget2D)Returns the render target the feed is captured into, creating it at Spectator Screen Size with a target gamma of 2.2 and taking one capture immediately if it does not exist yet. Cached afterwards, so the resolution is fixed at the moment of the first call.
eventStartCapture()Begins capturing this feed: marks the component active so the scene is captured every tick, broadcasts Spectator Camera Activated with the component, its owning actor and the render target, and hands that target to the headset mirror. Called by the coordinator, so reach for Activate Spectator instead.
eventStopCapture()Clears the active flag so the per-tick scene capture stops, leaving the last frame standing in the render target. Called by the coordinator; on its own it does not restore the headset mirror.
eventActivateSpectator()Asks the coordinator to make this component the live spectator feed, stopping whichever feed was running before. The coordinator is found or spawned on demand, so it works without one placed in the level.
eventToggleSpectator()Switches this feed on or off according to whether it is currently capturing, and is what a spectator camera calls when its input key is pressed. Since the coordinator keeps its record of the active spectator when a feed stops, switching the same camera back on has no effect until another one has been activated.
eventDeactivateSpectator()Asks the coordinator to stop this feed and return the headset mirror to a single cropped eye. Nothing happens if a different spectator is the live one.

Helper

BP_Helper_Spectator2 members
extends Actor
KindNameSignatureDescription
varPostProcessSettingsPostProcessSettingsPost-process settings copied onto the helper's scene capture as it is constructed, so the spectator feed can be graded apart from the player's view. A spectator component passes its own camera settings in on spawn; the copy happens in the construction script only, so later edits never reach the capture.
varFOVAnglefloatField of view in degrees handed to the scene capture by the construction script, 75 by default to match the camera the helper stands in for. Spectator components hard-code 75 when they spawn their helper, so a different value only takes effect on helpers you spawn yourself.