> For the complete documentation index, see [llms.txt](https://docs.msquared.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.msquared.io/creation/unreal-development/getting-started/networking/morpheus-render-targets.md).

# Morpheus Render Targets

### What is a Render Target?

In Morpheus, every client sees every `AMorpheusActor` in the world, no matter how far away that `AMorpheusActor` is. If your game has 10000 players, each client will have 10000 player `AMorpheusActor`s in their scene.

This means that, for high-scale types of `AMorpheusActor`, you cannot have very expensive components on that `AMorpheusActor`. For example, 10000 skeletal mesh components, or 10000 character movement components, would significantly slow down the client and server.

Morpheus has a feature called **render targets** which addresses this. A render target is a way of rendering an `AMorpheusActor`, which can change dynamically.

### Available Render Targets

Currently, a render target can be either:

* Nothing.
* A non-`AMorpheusActor` actor of a given class.
* A member of an animated crowd.

An `AMorpheusActor` can have only one render target active at any given point, and you can configure automatic handling of which render target to apply, when.

By default, an `AMorpheusActor` will never load any render targets.

### Setting up Render Targets

In your `AMorpheusActor` derived Blueprint, you will find the `MorpheusRenderTargetComponent`

<figure><img src="/files/nruZYRsGkHsjQt9MmITC" alt=""><figcaption><p>MorpheusRenderTargetComponent in a MorpheusActor Blueprint</p></figcaption></figure>

In the details panel of the component you can control its render targets:\\

#### **Server Render Target**

This is the render target always applied on the server. Although the server doesn't render anything, it can sometimes be convenient to have a server-side actor associated with an `AMorpheusActor`.

#### Authoritative Client Render Target

This is the render target which is always applied on the client which has authority over this `AMorpheusActor`.

*Actors with authoritative render targets will not have their LOD switched and calculated.*

#### LOD Group Id

In order for an actor to be rendered, it must be assigned to a `FMorpheusLODGroup`

By default, we have the `PlayerClient` LOD group ID but you can add as many as you want from the project settings when clicking `Create LOD Group`

<figure><img src="/files/7qjsgLG7CiTLw5vax2rv" alt=""><figcaption></figcaption></figure>

If the LOD group ID is not assigned we fallback to the `DefaultLODGroup` in the following setting.

#### Default LOD Group

Each LOD Group has a list of `FMorpheusLODGroupLevel` and `FMorpheusLODGroupBucket`.

* A LOD Group Level defines the `NumEntities` that can be rendered in that level.
* A LOD Group Bucket is used to prioritize some actors over others within the same LOD Group. It defines a `MaxDistance` within which the actors belonging to that bucket will be prioritized.

Each non-authoritative client will render the closest `NumEntities` entities (within the same `FMorpheusLODGroup`) starting from LOD 0.

For example, an actor with the following three LOD levels:

* 0: Actor render target with actor class `ACharacter`.
* 1: Animated crowd render target with high quality vertex animated meshes.
* 2: None

and belonging to the LOD Group `CharacterLODGroup` defined with:

* LOD Level 0: (NumEntities=`30`)
* LOD Level 1: (NumEntities=`500`)

Will render the closest 30 entities as the `ACharacter` class, the next 500 closest entities as Animated Crowd memers, the remaining actors as imposters, and have no render targets.

The render targets will be automatically swapped when the `AMorpheusActor`s move closer or further away.

#### LOD Group Buckets

A LOD Group can define buckets, and actors can register to the buckets to be prioritized. This can be done from the `MorpheusRenderTargetComponent`\\

For example, using the previously described LOD Group `CharacterLODGroup` , let's say it also defines these buckets:

* Bucket 0: (Name=`HighPriority`, MaxDistance=`10000`)
* Bucket 1: (Name=`LowPriority`, MaxDistance=`5000`)

Notice that buckets at lower indices will always have higher priority than buckets at higher indices.

`UMorpheusRenderTargetManager` will prioritize the actors belonging to bucket `HighPriority` (if their distance from the camera is below 10000) over the actors in the `LowPriority` group:

* Actor 0: Belonging to `HighPriority` bucket and with Distance=7000
* Actor 1: Belonging to `LowPriority` bucket and with Distance=1000
* Actor 2: Doesn't have a bucket assigned (i.e `None` ) and with Distance=400

In the above situation, the actors will occupy the available slots (`NumEntities`) in the `CharacterLodGroup` in the same order they were listed respecting the bucketing order.\
\
So actors belonging to the `HighPriority` bucket will get assigned first followed by `LowPriority` bucket then the unassigned bucket actors.

### Setting the Render Targets during runtime

If you want to update your Render Target setup during runtime, there are some blueprint functions that can be used to achieve this:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/cf149ed5-29a5-4526-baa3-91bab1ddf6ef>" %}

These options should be used sparingly as they may cause multiple render target reloads depending on the new `NumEntities` capacity - for example, when calling `SetClientLODLevels` it will attempt to reload the render target to a sensible default option based on the previous LOD level index.

{% hint style="info" %}
In release v40 onwards, we have some additional helpers, which we recommend using instead of setting the Client LOD levels directly:

<img src="/files/f3IaSzc8a6Yp6ukw9Ft1" alt="" data-size="original">
{% endhint %}

### Checking which Render Target is currently in use

In order to identify which render target is currently in use you can use the following nodes in Blueprints:\\

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/0ceab40d-16bb-46c2-8030-046755ba8426>" %}

If an `AMorpheusActor` currently has an actor render target enabled, `MorpheusActorRenderTargetComponent->CurrentActor` is set to the actor. `MorpheusActorRenderTargetComponent->CurrentActor` is `nullptr` otherwise.

If an `AMorpheusActor` currently has an animated crowd render target enabled, `MorpheusActorRenderTargetComponent->CurrentAnimatedCrowd` is set to the animated crowd actor. `MorpheusActorRenderTargetComponent->CurrentAnimatedCrowd` is `nullptr` otherwise.

`MorpheusActorRenderTargetComponent->GetClientLODIndex()` can be used to determine which client LOD level index is currently active, if any.

### Render Target State

The `MorpheusActorRenderTargetComponent` has a generic state that is stored locally (NOT replicated). This state will be known as the `Render Target State` and can be used to maintain the rendering state of the `MorpheusActor`

The `Render Target State` is of a type called `FMorpheusPackedStruct` which is a special type that can store any type of a struct.

Before using the `Render Target State` you will need to create or specify the struct that will represent your rendering state.

Here is a BP example that shows it in action:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/5bdded46-ddd3-4b42-b287-227004050983>" %}

You can also respond to updates that occur to your `Render Target State` via the delegate `OnRenderTargetStateUpdated` which will fire as a result of any of these triggers:

* An update to the `Render Target State`
  * i.e. a call to `SetPackedRenderTargetState` .
* A render target transition
  * e.g. Actor to Animated Crowd or vise versa.
* A render target is first loaded
  * e.g. as a result of a newly spawned `MorpheusActor`.

Here is an example of how to use this event in Blueprints:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/14541d54-686a-48a5-bd64-1ca00fa77d0c>" %}

{% hint style="info" %}
It's recommended to use the delegate `OnRenderTargetStateUpdated` delegate for updating your render target compared to the `Additional Render Target Events` below as it's more inclusive.
{% endhint %}

### Additional Render Target Events

The `MorpheusActor` provides some events to listen for when its render target is updated.

* `OnRenderTargetUpdated` : This is triggered when the render target is updated (e.g. switching from Actor to AnimatedCrowd)
* `OnRenderTargetSpawnedEvent` : Triggered when the Render Target has been switched to an Actor that has just finished spawning.
