Advertisement

UE4: When does the Unreal Engine access file system to load actor assets (mesh, sounds, etc) if you spawn a new actor at runtime?

Started by March 23, 2022 04:23 PM
10 comments, last by Mussi 2 years, 7 months ago

I have a class derrived from AActor which has properties like Meshes, etc. The meshes is a separate assets in content folder which assigned to this properties.

I spawn my actors at runtime using SpawnActor function.

When my meshes will be loaded? During the spawn, after the spawn or at game loading?

I found the Actor Lifecycle documentation https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Actors/ActorLifecycle/​ but I can't find answer to my question in it. I see that serialized to level actor will be loaded when the level loaded. But what is about spawned at runtime actors?

Why? Details can get tricky.

You'll have metadata describing the assets, but the actual highest resolution mesh and texture data might not be available.

Unreal has a lot of options about streaming in resources, such as persistent levels and streaming levels, sublevels, and more. As you wrote, actors serialized to a level are loaded when that part of the level is loaded. LOD settings and view distance settings allow the system to load and unload meshes and textures based on proximity and actual use patterns.

The system guarantees that inside the life cycle you'll have a fully built object with all the metadata needed to use it. This includes objects created at runtime. They may not be fully realized on screen at that time when streaming is enabled, they might not actually be renderable yet as textures stream around, or they might be visible as a low LOD object, or even just a billboard off in the distance. Between the times of BeginPlay() and EndPlay() the data should be there for you to use it.

Advertisement

frob said:

The system guarantees that inside the life cycle you'll have a fully built object with all the metadata needed to use it. This includes objects created at runtime. They may not be fully realized on screen at that time when streaming is enabled, they might not actually be renderable yet as textures stream around, or they might be visible as a low LOD object, or even just a billboard off in the distance. Between the times of BeginPlay() and EndPlay() the data should be there for you to use it.

Looks like, you didn't understood the question.
I have a Spawner class, which has a property

UPROPERTY(EditInstanceOnly, BlueprintReadOnly, Category = "AI Spawner")
TSubclassOf<AGladiusBaseCharacter> CharacterToSpawn;

I assigned to it blueprint class (derrived from c++ class derrived from actor) and then in runtime I spawn actors when I need them:

FActorSpawnParameters SpawnInfo;
SpawnInfo.Instigator = GetInstigator();
SpawnInfo.ObjectFlags |= RF_Transient;

AGladiusBaseCharacter* Character = GetWorld()->SpawnActor<AGladiusBaseCharacter>(CharacterToSpawn, SpawnTransform, SpawnInfo);

Actor can be heavy: contains a lot of meshes, sounds, etc.

Yes, when I spawn it every component of actor is loaded and ready to use.

But I'm asking: when Unreal Engine loads it? At start of game or during the first spawn?

I want to elliminate every access to filesystem during runtime to prevent game thread freezing. I want to load everything on the game start and use only preloaded data at runtime. How to do it?

If UE loaded everything that could ever be needed at runtime at the start of the game it would be quite possible you would run out of memory (and it would be infeasible either way for UE to parse your code and find what would be needed to be spawned of course).

If the world is setup already in the constructor of your spawner class then you could create an object pool at that point and then later just enable the objects. Otherwise you could do it at BeginPlay. That is assuming that the spawner class itself is part of the scene from the start. Otherwise you would have the same problem just all at one time during runtime.

Another idea would be to load all of the data at the start that a spawned actor can use, and then inject that data when spawning but I guess you would have to look at all spawn parameters to get that working properly.

But I wouldn't be surprised if there is some more clever way that UE can re-use the data of one object so it doesn't have to read from the filesystem each time.

YellowCartridge said:
But I'm asking: when Unreal Engine loads it? At start of game or during the first spawn? I want to elliminate every access to filesystem during runtime to prevent game thread freezing. I want to load everything on the game start and use only preloaded data at runtime. How to do it?

In that scenario you're working against the way the engine works.

You shouldn't have the engine freezing, that's probably a programming bug you need to fix in your code. But the overall streaming is just part of the design.

For the game actually stalling or freezing during a load, you need to fire up a profiler or debugger and detect what is going on when it happens. Almost certainly you're making a blocking call when non-blocking options are available.

The rest is by design. It is fundamental to how Unreal works.

The engine loads up metadata for you to use that serves as proxies to the actual data. You get an object that represents the mesh, you get an object that represents the texture. You don't get the raw data which is sent to the video card because your raw data might not be loaded, it might be instanced, it might be at a low level of detail, it might be on a billboard, it might not be loaded at all. If you dig into the system it is exposed in the depths, but it's quite rare to actually need that sort of thing.

The engine is designed to automatically load and unload things behind your back. It loads some things at startup, but it also loads things during runtime. That's a good thing, and most games love the feature. The alternative means you cannot have worlds that are as complex or diverse, it means you have to manually phase things in and out, or you need to design each world with only a small subset of resources.

There are steps you can take to encourage loading. You can mark assets that you want loaded. You can mark audio by priming it for playback and marking with Retain on Load, you can mark level objects by making them persistent, you can create an Array of objects that you keep around so it doesn't get garbage collected. Just be aware that none of those are strict guarantees. They might not have all the details fully loaded when you start up. When space gets tight the system will unload stuff for you. And if you force too much stuff into memory and you run out, you'll get crashes. For example, if you try to force all your graphics to load you'll fill your GRam buffers and get an Out of Memory crash.

That's just the nature of Unreal. Play any Unreal game and that's what players are used to experiencing. When they first load into the world or use fast travel assets are streaming in, some popping into existence and others getting progressively better detail as assets stream. Unity does something similar.

So, correct me if I wrong. Unreal loads assets from filesystem when you call SpawnActor, but does this in separate thread and don't affects the main thread. Right?

Advertisement

frob said:
You shouldn't have the engine freezing

Why? How it works?

Can anybody explain me the SpawnActor workflow? Why the loading of huge assets from slow hdd should not freeze the game thread? How it works?

If you have the engine source you can always step through the application and see what is actually happening each time you try to spawn something. I'm sure there is some documentation for it somewhere but in the end the source code is the ultimate truth.

YellowCartridge said:

So, correct me if I wrong. Unreal loads assets from filesystem when you call SpawnActor, but does this in separate thread and don't affects the main thread. Right?

It does not. Well, it might do LODs or MIPs or things like that but it's not true for the blueprint you're trying to spawn. That needs to be loaded sometime before you call SpawnActor.

In this particular case, Unreal is going to load the blueprint assigned to CharacterToSpawn whenever the class holding that property is loaded. This is because TSubclassOf is a hard reference. So it will already be loaded. There are alternatives to hard references that require you to do more management of content, either with TSoftClassPtr and manual loading calls or use of the AssetBundles system (also using TSoftClassPtr).

--Russell Aasland
--Principal Engineer
--Midsummer Studios

Right, the blueprints, class names, and other metadata are loaded early on, and other resources like models and meshes, textures, and audio are loaded and unloaded as needed.

The asset manager has primary assets like the persistent world and they are loaded early. The definition and metadata for blueprint classes are loaded early otherwise you could not find them with searches. Secondary assets are loaded and unloaded as needed. The same with streamables and asset bundles and sublevels, when they are initially loaded the metadata is pulled in but the secondary assets are only loaded when needed, and unloaded on request or when needed by resource management.

The docs have a good starting point. You can also leverage the Audit Assets tab in the content browser for useful information. It very quickly turns into source diving if you need to dig deeper.

It can help to remember that all resources are not equal. There are essential elements that the system needs, like the names of items and the links to filenames and IDs for later loading, and elements that can be proxied out both to improve loading time and to accommodate hardware requirements like avaliable memory, faster rendering, or limited audio pools. The engine does a lot of work to balance the need for access versus the reality of the hardware, including hiding the wide variety of home computer configurations.

This topic is closed to new replies.

Advertisement