For instance, hypothetical but common scenario, I have a player and a large pile of npcs. They all use the same skeletal mesh (Edit: This would only meaningfully help with static meshes) as a base but their skin texture and/or eye textures should vary depending on the individual (plus morphs might be used to make them more distinct and they would probably have different hair and clothing equipped as well), a fairly typical scenario for modern RPGs.
Only way I’ve found out about to do this is to make a material instance into a dynamic material instance and set the texture from there, but there’s a big problem with doing it that way.
Namely that it ballons up your draw calls as described in this video:
Which means it’s ok to use it for mostly unique entities, things that there aren’t ever gonna be very many of around the player at the same time, but generally speaking it’s something to avoid, and it’s definitely a bad idea to do it with npcs since you can almost always expect there to be a couple around the player at least, nevermind if you’re in a city or something.
Now i’ve fuond out about scalars, dynamic parameters(i think those are just for particle systems), and custom primitive data, most of which do get discussed in aforementioned video, there are also material paramater collections which enable you to manipulate scalars from blueprints.
But while the texturesample node can be made into a paramater which is editable per material instance.
I haven’t found any way at all to manipulate texturesample directly besides via a dynamic material instance.
I would like a way to swap out the texture freely (not just between one or two pre-specified textures) without depending on the dynamic material instance to free up draw calls. Is there any way at all to do this?
Another way it can be done, keeping it as a single set of draw calls is to select the different textures from within the material, using a little HLSL to create an array and return the indexed texture.
You can store the index in the NPCs meshes custom primitive data (or per-instance custom data for ISMs).
This is indeed the only other way i’ve seen to do something similar, however it isn’t what I need.
You’re just switching between a few pre-specified textures, i already knew how to do this. Problem is I need to be able to swap them out for completely new textures.
Think modding support or something to that effect. I will need players to be able to use custom textures.
I’m not aware of any other way to do that apart from using dynamic material instances.
The video’s talking about instanced meshes, your skeletal NPCs will all be their own draw calls anyway (unless you’re using a custom renderer or plugin).
i see so it only applies to static meshes, it would still be useful regardless, there are likely going to be plenty of cases where I need to do the same for just static meshes (I just tested it to confirm too, you’re right, skeletal meshes all have their own draw calls, same with niagara systems, only static meshes get free draw calls, nanite is coming to SKM in ue 5.5 though so maybe that would change? )
The answer doesn’t have to be in blueprint actually, c++ would also work, i just need a way.
Maybe one way would be to use an atlas mask for the NPC skeletal mesh (similar to how Manny and Quinn work) and that mask combined with a set of custom primitive data could point a source texture which is a composite of all possible NPC textures (e.g. a 4096x4096 texture with 4x4 1024x1024 = textures placed in a grid within for 16 variants , or 8x8 512x512 for 64 variants etc.
If you wanted to have complete customizing from any source texture, you could use a rendertarget as that composite texture and copy over the user specified textures.
That seems like a fairly optimal way to do it as it’s small on VRAM and efficient with draw calls.
If you wanted to go right in there, you could create a system that stacks material collections within a PrimitiveComponent and add an index for instances within that stack - but I’m not sure if it would give much performance boost, and possibly less as it would be loading all those textures into VRAM before executing any rendering.
Yeah, i thought about these ways and even tried the render target one.
Using an atlas isn’t really much better than the way you initially proposed, it’s more memory efficient since one atlas texture will be smaller than 4 separate textures, but ultimately you will have the problem of any instance using any of those texture options will have to load all of them to memory (this can be acceptable, i might even actually do this for ‘default’ texture variations, but it doesn’t solve the problem of actual custom textures). E.g. you load one NPC in and now your VRAM is stuffed with every possible texture variation. And it still doesn’t solve the problem that I need the player to be able to use their own custom textures.
The render target approach ‘works’ but it’s problem is twofold.
1: To render a texture to a rendertarget, you need to first load that texture into a material. So to change that texture you will still end up needing to use dynamic material instances. I’m not sure on how that’ll affect performance and memory, but I suspect it’s not too great in the long run.
2: The real problem is that a material instance can only point to one rendertarget. So for this approach to work I would need to create a new rendertarget and material instance for every npc in the game that is supposed to have distinct skin, and I’d need the player to be able to create their own material instances and rendertargets at runtime in order for them to be able to use custom ones, i mean i suppose i could have one rendertarget dedicated to the player… But I don’t want just the player to be able to swap their skin around, the npcs need to be able to do it too.
Change one rendertarget and every material instance using it will be affected.
Besides these issues (and again i’m not quite sure how major of an issue the first one really is since i haven’t tested that far, but i mean you would have a dynamic material instance for each npc anyways if you did this, it just wouldn’t be applied to their mesh), using a rendertarget to make it possible to swap out a texture is actually a pretty solid idea.
It would probably work out well for swapping out textures on static meshes, things like clothes or furniture, but each instance of those object all having to use the same texture is not always gonna be desirable.
I don’t think rendertargets and material instances can be created during runtime (and i’m not even sure how good of an idea it’d really be to go that route, but if i can make material instances at runtime then making an actor duplicate it’s original material instance and just swap out the texture in it wouldn’t be that hard, if there was a way to actually change the texture of the material instance at runtime too the same way you can in the editor)
I was thinking more along the lines of having one rendertarget (per BC,N,etc) , created in the editor and all NPCs pointing to those with a common material, with some custom primitive values, 1 for shirt, 1 for pants, 1 for shoes etc.
The rendertarget can be drawn to at runtime, so you could have routines in place to copy over the user specified textures into that rendertarget into cells in a grid.
Then just set the custom primitive data on each NPC.
As far as it using more VRAM - I guess that depends on the resolution of the rendertargets you use - and the resolution if you were just using the textures. It may actually help having the one set resident - you mentioned the NPCs come and go quite a bit - it may avoid traffic on the bus.