How to set a texture in a Mesh Library/Gridmap without duplicating the entire mesh resource?

Godot Version

4.5 beta3 but honestly not that important here.

Question

I’m making a 3D pixel-art game with gridmaps. I was hoping to use palette swapping on each gridmap so I don’t have to bake the same texture a dozen times. I DO have a working palette-swap shader I hacked together from a 2D canvas_item one, all I need to do is change 1 shader parameter variable, but 3D array meshes have a caveat: You can’t edit shader properties per-object without duplicating the entire mesh resource using it. (Otherwise it will affect all gridmaps using the texture instead of just the one.)

Unfortunately, the only way 3D palette swapping (or just changing textures in general) on Gridmaps/Mesh Libraries can work is by calling .duplicate(true) on the entire mesh library and editing every mesh’s texture via set_shader_parameter(). This TECHNICALLY works…

…But the problem is that we now have an entirely duplicated mesh library of 86 meshes in the background just to edit one texture. For every gridmap. I fear that it will affect performance later on.

Possible Fixes

I know that the texture created from this will at least be shared by every mesh in the duplicated meshlib, but the meshes themselves are still a problem. We shouldn’t be duplicating 86 meshes just to edit a single MaterialShader variable…

I think individual meshes DO have a seperate override material setting that would work here, but mesh libraries (and by extension Gridmaps) do not have this option? Is it possible to do some dark magic by turning the gridmap into another kind of combined mesh at run-time that supports material overriding, maybe? (Even applying the entire thing with 1 texture will work for me as I’m using an atlas texture.)

I could also just bite the bullet and add each new textured mesh as part of the mesh library but that’s basically the same problem with extra steps?

tl;dr I need to edit a Shadermaterial parameter on a GridMap without affecting other GridMaps. Duplicating the entire meshlibrary works but is very wasteful. Alternative?

I’ve only done this in the editor, but you can do this in code the same way. In a GridMap you can edit a MeshLibrary instance. If you have multiple things using it, you need to make it unique first if you don’t want to change everything that uses it. This will create a separate resource.

What you need to change is item/index/surface_0/material where index is the index number (starting with 0) in the MeshLibrary.


This is a MeshLibrary local instance where I have changed the surface material for some items, but not others in the GridMap. I use the same MeshLibrary and GridMap scene for 5 different levels, each with a different material.

The only difference is I’m using a StandarMaterial3D material instead of a ShaderMaterial.

I’ve already done this through code.

What’s worrying me is when you “make unique” a mesh library of 86 meshes, you now have 86 new meshes to load. For 5 palette swaps, that’s 430 meshes. And so on.

Isn’t that how unique meshlib resources work? Or am I mistaken?

If unique resources keep using the old resources until edited that’d be fine, but if it’s completely new then this can be quite a problem for me, because a level that uses 86 meshes as building blocks can suddenly shoot up to 600+ just because some gridmaps have a edited texture.

I’m starting to think that it’s best I just combine the new re-textured meshes into a single mesh library like a normal person, since at least I won’t duplicate the meshes that aren’t affected/used in a palette swap that way.

1 Like