Help with texture blend shader

Godot Version

4.3

Question

I am a shader noob. Is there a way in godot to use a shader to blend textures to different positions on a mesh for a terrain that uses different materials or like for a paint effect like in splatoon? Using an array shader parameter that contains the material indexes for the coordinates of the mesh or something like that? Without having a huge unwrapped texture for the mesh but a repeating one?
Thanks for the help! :slight_smile:

This is not a direct answer to your question because it doesn’t use shaders, but there is nice a way to “mark up” a texture using subviewports that’s discussed in this video. In this case, getting “tire tracks” to stay on the ground in a racing game. https://www.youtube.com/watch?v=cwZGq1qJYoQ

I’m no expert, but I’m not sure a purely shader solution is ideal, unless maybe using a compute shader(? I don’t know enough to be sure), because you’d have to keep rewriting the paint effect if it’s not saved somehow, which is inefficient. I’d be thinking about using an ImageTexture and the Image class’s blit_rect() function. Image — Godot Engine (stable) documentation in English

1 Like

I haven’t tried anything like this in Godot, but if I were trying to do something like this, I’d probably keep an extra byte (or something) of “paintedness” with the mesh vertices. You could then hand that through to the frag shader and use it to decide how much paint to blend in per fragment.

1 Like

I’m doing something a little bit like this. I use a single-channel 3D texture to represent the amount of a single color of paint in 3D space, and then apply this to a mesh using a shader that blends between the normal material color and the paint based on the value in the 3D texture.

This shader is quite simple, the more complicated part is applying the paint, which is done in gdscript by converting 3D spatial coordinates to texture coordinates, reading the texture, adding a the paint value, and then writing the new value back to the texture. This is still fairly straightforward, because my 3D texture just uses world position plus an offset as the texture coords.

The downside of this is that 3D textures are quite large for even a single channel, and so my resoltion is fairly low, 1 meter = 1 texel in my case.

You can do a similar effect with 2D textures. The trick is you have to have unique texture coords for every position in your world model, and you have to have a way to map world coordinates to the UV coordinates for your blend texture. The simplest way would be to just use a top-down projection, however this assumes that your world painting would not use multiple vertical layers of geometry.

As far as blending multiple textures together, the simplest way would just be to use a multiple channel blend texture, and make all of the channels add up to 1.0 or less. So Red could represent the amount of texture1, Green texture2, etc., up to 4 textures.

Does any of this sound workable for you? I do think that some kind of blend texture would be necessary, although using writeable vertex colors would be an alternative. I could help with the shader code, but like I said, the shader itself is the easy part, it’s creating a blend texture that adequately covers your world and then dynamically writing to it that’s the harder part.

1 Like