Texture memory vs triangle/draw count

Hello there!

I just have a quick question regarding the performance difference between loading in more and more texturemaps and having lots of assets use unique textures **VS **using texture atlases and load in fewer texture maps but have a little bit more geometry to define some shapes more since you can’t really bake unique shapes with the tileable texture atlases you’d use.

I have searched for quite a while for a head to head comparison but I haven’t been lucky. The ony thing I keep on hearing is that Unreal shreds through geometry like it’s nothing. And iv’e also read that in horizon zero dawn they had up to half a million tris for just one of the larger dinosaurs (I know it’s not made in Unreal)

To put things into perspective for my own project:

I am building a HUGE pirate ship for use inside Unreal. Our teacher wants us to optimize as much as we can, so my approach in order to optimize will be to use 3-4 tileable 2k texture maps in total for the entire ship. This means that there pretty much wont be any baking done. So because of this I am using a bit more geometry in places where it is needed. See image #2. I could make the metal door decoration in a texture of course, but instead I decided to build it using geo and then use a a metal from my texture atlases.

So back to the question. I know this doesn’t have a black on white answer, but what is generally better to do: Save on triangel count OR save on textures space/memory?

I think most of your confusion derives from the not knowing how the engine works in terms of performance.

First, whatever is on screen will cost you. whatever is not COULD cost you anyway.

A blatant example on a ship is if both keels are part of the same mesh.
Say you section off the ship in 3 parts.
Keel left half, keel right half, bridge.

Now if the ship is turned and the left keel is facing away from the player, the engine can actually NOT render that portion which isn’t on screen.

This COULD be an improvement, but it really depends on how the ship is designed in the first place.

If you are using 1 material for the whole ship, the rendering will only cost you 1 draw call.
If instead you split the ship into 2 or more parts, even using the same material, you’ll have 2 or more draw-calls (one of which may actually go away if occlusion permits).

Having more draw calls will impact performance.

Then you have Instancing.
it’s a little more complex to explain so picture it like this. If I have 1 thing on screen, I can put another billion of the same thing on screen at a reduced cost - if using instancing.
That’s mostly because the cost of the texture/material load is shared along all the objects.
Each will still however cost you 1 draw call or more (depends on how many materials the object has).

Let’s stick to the boat example. What could be an instance?
The doors, the ropes, the banisters, the sails. essentially anything that is “the same”. To some extent of-course. The cost is reduced, but do you really need the ability to go in and place individual ropes inside the engine? (Potentially yes if you want them to animate/react to wind)

Then you have LODs
You can have a model be a billion tris at LOD0 and 100tris at LOD8. the idea behind it is that the further you get from the object the less detail it will need.
A pixel is the size of a pixel. Geometry falling inside the size of a single pixel essentially will not matter.
So an instant way to optimize is to create proper LODs for all your models.

Take the door as an example of this.
If your camera is at the bow, looking directly at the door, do you really need the geometry of the metal, or the geometry for the porthole?
No, you probably do not. You can have the door be a flat 1 sided mesh with a picture of the door applied to it - and it will cost you next to nothing (except the texture load) to render.
As you walk closer to said door, you’ll probably want to start to see more and more detail, until you are up in front of it, when you really want the maximum detail you sculpted visible.
That’s achieved with LODS.

So, getting back to your question. What is better?
It all depends on how you want to work it - and also on Where the ship is to be placed.

IF you are mid ocean with nothing but clouds and ocean to render, the ship can be extremeley detailed without causing performance issues.
IF you are docked in a harbor with a billion things happening, then the ship cannot be extremely detailed as well.

Your Tris count therefore should depend on usage and scene - more-so then modeling.

As far as Textures inside 1 material.
You usually have a limit of 13. You can exceed this (for landscapes for instance). But the more you have, the more the material will cost to render.
This cost becomes exponential after a while.
However an important optimization is to allow for Mips.
Mips are what the textures are programmed to do if you correctly use textures in a power of 2 format. The engine will scale the texture down and load only the version it needs to render the whole model.
In texture atlases, this has the potential to screw things over, and you need to seriously look into texel density when creating the model in order to allow for this to happen properly.

Last but not least - don’t forget that you need a second UV map for the light build.
Building lights with a proper lightmap IS a good optimization practice regardless of if you use it (the object is static) or not (the object is movable). I wouldn’t rely on the engine to create a good light-map for your models.

I think that covers most of it.

if I were you I’d go with a modular approach that gets Merged within the engine for a manual LOD replacement.
Since the engine CAN merge actors (Actor Merging | Unreal Engine Documentation)
You can test the items individually, and try to make optimizations based on arbitrary merges before re-creating the merged mesh in your 3d program.

There’s a balance between using additional textures vs. doing it with the mesh. It’s usually good to do some stuff with your mesh so that you can use your textures in a way that adds more detail. For example with a floor that has nice panel detailing you can do that with tiled textures if you’ve cut some of those borders into the floor mesh. That kind of thing gets done all the time since adding a few hundred vertices and using something like a 256 x 256 tileable texture is going to be better than having to use a unique 1024x1024 texture.