Is packed level instance more efficient than unique static meshes?

Suppose we want to create a wall.

A wall is composed of blocks.

We can build the wall two ways:

  1. Combine the block static mesh into a wall in external 3d app. Export the wall to unreal. Now Unreal knows about SM_Block, and SM_Wall. It does not know that SM_Wall is just a bunch of SM_Blocks, so there is some inefficiency.

  2. In unreal, make a Packed Level Instance and stack SM_Block to make a wall. The PLI instances the SM_Block for max efficiency. The PLI has some memory footprint, but it is not as great as a unique static mesh for the wall.

Is this correct? Can anybody suggest how great this memory difference may be? I’ve done some test and it appears that the difference between a single unique static mesh wall and a PLI that is an entire building is about the same memory size, which suggest PLI’s would save a lot of memory at scale.

Is there any other important consideration at play? I ask because I’d rather setup things Maya side as it is faster, but if the game will be gigabytes less to download because of PLI use, that may be better.

Hi BIGTIMEMASTER,

I’ve got some speed comparisons here:

2 Likes

Thank you very much!

1 Like

Just no.
Period.

1 draw call, vs at a minimum 1 for every instance.

Size on disk is ofc is a different (performance unrelated) story.
The single mesh being repeated would win out as its just one small file being repeated.

What is actually best all around is to merge the actors at runtime.

The end result is therefore one small mesh, 1 drawcall, and whatever memory gets eaten up by the merging process.
(Which you only partially care about, because afterall a low ram system needs to be able to handle the end product depending on what minimum specs you want).

Lots of games with a build system do just this. Including Fortnite.

Because effectively you can’t expect much of anything to be able to handle 3 billion draw calls in less than 30ms…

@RecourseDesign
You probably don’t care, but there’s about as many ways to inteoduce individualized instances into a merged mesh as one can think of.
From material driven effects to localized instance stuff via vector paint.
The editing time for those is probably a 1/5 though.

I care very much about these things :slight_smile:

i thought that was the point of the Packed Level Instance?

Which part is incorrect?

If I have a single building that is a static mesh, it’s memory footprint is larger than a Packed Level Instance composed of just the small, repeating parts. It has one draw call per material, no?

The Packed Level Instance should be batching things are efficiently as possible, and also there is nanite involved so that should be streamlining draw calls as well?

To be clear, I don’t see runtime performance ever being an issue here. It is a small level and not a huge amount of assets. But it looks like if I used static mesh per building that my disk memory size is going to be like 10x larger (but tradeoff is that setting up PLI compared to setting up buildings in Maya is slower)

Here’s a few comparisons. Same building as a single static mesh compared to a PLI composed of small parts.

Condensed summary:

The PLI is composed of 34 unique static meshes:

Static mesh building Memory Size

Static mesh building disk size

PLI Memory Size


PLI Disk Size

So the PLI disk size is a big difference, memory size not so much. I am not sure the difference, I think memory means like runtime memory needed, which would effect runtime performance? Will look it up.

The big thing though is that setting up modular kit in unreal is terribly slow compared to construct buildings in maya. Difficult to make a decision. Perhaps since performance is not a concern yet, I should just go with the faster way and see if it really becomes an issue or not.

made a tutorial how you can do the level art setup in maya an import to unreal as PLI.

Some other advantages of using smaller pieces is the reuse of them - building from smaller parts allows you to use those same parts all over your level - all from the same draw call - less VRAM, less CPU, less bus transactions - no need to add them to HLODs.

When you combine the meshes you loose that, you end up with your big mesh and smaller meshes, both with different textures (unless you’ve used masking, which is another texture or 2 anyway) and both with different draw calls - and the extra overhead of another, more complex mesh along with it’s collisions.

If you’re using destruction and/or interaction - you’ll need to have the smaller objects anyway - you can fracture the larger mesh, but it’s not giving you things like complete items (eg cans of drink) flying out from the destruction.

2 Likes

There are a few things to consider:

Target release platform?
For instance, using a switch you must limit the disk size to some 68GB to be able to make cartriges to sell (they probably got larger by now, but its impossible to find out without signing 20 NDAs with nintendo, which also means i can’t disclose what they tell me anyway).
Using steam/pc stuff there is no limit, nor any cost associated with the size, so your size on disk doesn’t really matter too much.

Performance costs?
Which overall if any provides less draw calls?
Always go with that to side with performance.

Avaliable Vram on end release target system?
You obviously have to make sure your texture pool isn’t exceeded and all of that (like you always should anyway).
Using instances instead of a properly crafted and merged large model can be eay heavier.
Thats because when merging parts into a DCC you usually also re-create the UV and set it up to work better. Probbaly merge materials down into a single texture as well (Less materials less drawcalls).
Obviously you can’t do this at runtime.

This is probably why you have less drawcalls really.

If nanite is on for the meshes, in theory, it wouldn’t matter if they are instanced or not. The engine would automatically compute them into the single nanite mesh that is rendered - the processing time for it may change in practice, so always test, don’t go by anything anyone says.

Memory needed doesn’t directly affect performance. Unless you go over the maximum and cause the buffer to overflow which involves more computations to be done to split it out and get results.
It’s really just a reference to know how far from your target end system you are and what you can affod to add in.
(If you were working on an N64 game, with 64MB you’d be very concerned about this. Anyone else in modern times probably isn’t).

Was going to suggest something similar.
There’s no reason to not use whatever is best for you.

Instances of thinga are just an array of locations.
You can import and distribute instances off an excel sheet if you need to. Data being data and all of that it doesnt really matter too much how that data gets generated.

Generally that is precisely the goal.

Say you make a spaceship out of parts. The goal behind merging it is to obtain one single object with one single texture so that you can then spawn the large (walk inside of it) object with a minimal cost/footprint.

In the case of the temple, you would split up the UVs and merge them loosing some definition in exchange for the material/texture count becoming 1 instead of say 4 (roof, frieze, marble, columns).

While this usually isn’t necessary on modern hardware, it is supposed to be the general goal when merging objects together.

Which makes the merging process even more painful than you thought:
Particularly when you realize that if you need to bake lights your light UV probably can’t tile and overlap for the object, so you have to re-unwrap a light UV specifically for it in a way that you get as little bleed on objects as possible.

There’s a lot of give/take between all methods.
Knowing or guessing which one to use depends on what you want to achieve and how much time you want to dedicate to it (parricularly if you need to light bake after).

1 Like

thanks guys, this has been really helpful for me. Now I got a much better idea how to measure things going forward.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.