0 votes

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.setshaderparam()" 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 :D
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!

in Engine by (77 points)

1 Answer

0 votes

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.

by (3,881 points)

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

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 ".setshaderparam()" is effectiv.

CLICK for full resolutionsketch for a better understandingCLICK for full resolution

So i need a way to call ".setshaderparam()" 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

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.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.