how to tell shader the neighbor-texture (SurfaceTool)?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By player0815

hi iam new and trying around with godot <3
at the moment i try to create a basic terrain generator e.g. tile or voxel based.
For generating the mesh i use SurfaceTool. That works very well for now and i can create a tile-plane (with an easy for-loop).

At the moment i create every tile as its own surface with a specific material and add it to the SurfaceTool. So i can generate e.g. a “Minecraft”-like surface.

Now i would like using shaders to make some cross-fade effects with neighbor textures.
For testing i have written a small shader who uses 2 textures - the main texture from the tile and a second one who represents the texture for a neighbor tile.

//import Textures
uniform sampler2D tex1: hint_albedo;
uniform sampler2D tex2: hint_black;

void fragment() {
	// get pixel color
	vec3 vTex1 = texture(tex1, UV).rgb;
	vec3 vTex2 = texture(tex2, UV).rgb;
	
	// merge & draw
	float c = 1.0 * UV.x * UV.x; // west-east "curve"
	vec3 m = mix(vTex1, vTex2, c);
	ALBEDO = m; // draw
}

i know that i can set the texture parameter with “material.set_shader_param()” and i tried something like this:

var ter = SurfaceTool.new()
var myMesh = Mesh.new()

func cube_face_top_full(offset = Vector3(0,0,0), material = matDirt, neighborTex):
	# positions
	var xr = offset.x + 1 + grid_offset
	var y = offset.y + 1 + grid_offset
	var zf = offset.z + 1 + grid_offset
	# [etc...]
	
	ter.begin(VisualServer.PRIMITIVE_TRIANGLES)
	
	# NOT WORKING HERE... <---------------
	#material.set_shader_param("tex2", load(neighborTex))
	
	ter.set_material(material)
	
	# triangle 1
	ter.add_uv(Vector2(1,1))
	ter.add_vertex(Vector3(xr,y,zf))
	# [etc...]
	
	ter.generate_normals()
	myMesh = ter.commit(myMesh)

And this is were iam stuck :smiley:
How can i tell the shader wich texture should be used?

My knowlegde of shaders and 3d-meshes is very basic but can anyone give me a hint how i can solve this problem?

sry for my bad english^^
thx a lot!

:bust_in_silhouette: Reply From: SIsilicon

How about adding another uniform to the shader.

uniform float t = 0.0;
...
    #in fragment shader
    UV.x += t; #offset the UV after texture sampling
    float c = 1.0 * UV.x * UV.x;
    
    #clamp c between 0.0 and 1.0
    vec3 m = mix(vTex1, vTex2, clamp(c, 0.0, 1.0));
    ALBEDO = m;

When t is -1.0, then you only have the first texture. If t is 1.0, then it’s the second one.

thx for your answer
but i think you dont understand me correct :slight_smile:

my problem is, that i can not tell the shader whats the texture of the neighbor tile is.
If i do it on this way (as i have shown above) the shader use it for ALL “dirt” textures on the terrain.
Because only the last call of “.set_shader_param()” is effectiv.

[CLICK for full resolutionCLICK for full resolution][1]

So i need a way to call “.set_shader_param()” just bevor the SurfaceTool draws the aktual tile.
Because, there I can still be determine which material the respective neighbours have, based on the XYZ coordinates.

But i have no idea how to do that…
Or it needs a complete other way?!

Of course later i want to implement the other neighbors too, if this works correctly…

thx

player0815 | 2018-10-02 22:17

Maybe you could try something with vertex colours. The vertex colours, specifically the red channel, can store that t variable. And in gdscript, you can animate it by rebuilding the mesh. When it’s changing. Of course that’s just on the top of my head.

SIsilicon | 2018-10-03 06:48