I'm using a tileable texture for the grass texture. I'm using a simple visual shader that looks like this: I think one method of adding some randomization would have been to randomly rotate the texture (or UV?) 0, 90, 180 degrees etc. But, is there any way to do it through visual shader.

I have not fully mastered code based shader yet, but I guess I could try coding if there is no rand function in visualshader

• I believe what you are looking to do is something along the lines of this:
http://www.iquilezles.org/www/articles/texturerepetition/texturerepetition.htm

• What can I use in place of the hash4? Godot seems to not have that function.

• Looking at the article @Megalomaniak linked, it appears the `hash4` function is a custom function. Initially I thought it was something OpenGL specific, but in the ShaderToy shader linked in the article, it turns out that `hash4` is just a function created in the shader:

``````vec4 hash4( vec2 p )
{
return fract(sin(vec4(
1.0+dot(p,vec2(37.0,17.0)),
2.0+dot(p,vec2(11.0,47.0)),
3.0+dot(p,vec2(41.0,29.0)),
4.0+dot(p,vec2(23.0,31.0))))*103.0);
}
``````

This should be doable in Godot's shader language.

I'm not totally sure if it is possible through the visual shader though.

In Godot 3.2 there will be a way to add a expression node to the visual shader editor, which you could use to define the hash4 function.

• think of each thing there as a node:

fract takes a single input, and it's output is the final return.

This should already hint to you that visual/flowgraphs in comparison to written code are represented in reverse, btw. So order of operations as you read them is opposite, but for the computer they will be the same, of course.

Next we see a sinewave, but we need to also account for the end of brackets. So the next node working backwards(from output toward input) would be a math multiplication, scalar to be exact. Note that the output of sine is multiplied by 103.0 there.

So next we look at what is input into the sinewave function? It's a vec4 with each of it's components holding the result of another math operation, this time an addition. So on and so forth. You just deconstruct that hash4 and reconstruct it as a visual flowgraph of the logic. That's basically it.

• @TwistedTwigleg Oh, I see. Thanks. Makes sense.

• edited August 16

Sorry for late response, I had to lower this in my to-dos. I finally got it to work. But there is still some repetition because each ground tile in the gridmap has the same texture, but it's less obvious because there is no obvious repetition WITHIN a tile. Especially there are some weird artifacts as the edges of the grid tiles  Maybe I didn't do it correctly? Am I supposed to use Fragcoord?

Here is the code I used:

``````shader_type spatial;

vec4 hash4(vec2 p){
return fract ( sin(vec4( 1.0+dot(p,vec2(37.0,17.0)), 2.0+dot(p,vec2(11.0,47.0)), 3.0+dot(p,vec2(41.0,29.0)), 4.0+dot(p,vec2(23.0,31.0)) ) ) *103.0);
}

vec4 textureNoTile (sampler2D samp, vec2 uv)
{
vec2 iuv = floor(uv);
vec2 fuv = fract(uv);

vec4 ofa = hash4( iuv + vec2(0,0) );
vec4 ofb = hash4( iuv + vec2(0,0) );
vec4 ofc = hash4( iuv + vec2(0,0) );
vec4 ofd = hash4( iuv + vec2(0,0) );

vec2 ddx = dFdx(uv);
vec2 ddy = dFdy(uv);

ofa.zw = sign(ofa.zw -0.5 );
ofb.zw = sign(ofb.zw -0.5 );
ofc.zw = sign(ofc.zw -0.5 );
ofd.zw = sign(ofd.zw -0.5 );

vec2 uva = uv*ofa.zw + ofa.xy, ddxa = ddx*ofa.zw, ddya = ddy*ofa.zw;
vec2 uvb = uv*ofb.zw + ofb.xy, ddxb = ddx*ofb.zw, ddyb = ddy*ofb.zw;
vec2 uvc = uv*ofc.zw + ofc.xy, ddxc = ddx*ofc.zw, ddyc = ddy*ofc.zw;
vec2 uvd = uv*ofd.zw + ofd.xy, ddxd = ddx*ofd.zw, ddyd = ddy*ofd.zw;

vec2 b = smoothstep (0.25, 0.75, fuv);

return mix(mix (textureGrad(samp, uva, ddxa, ddya), textureGrad(samp, uvb, ddxb, ddyb), b.x), mix(textureGrad( samp, uvc, ddxc, ddyc ), textureGrad( samp, uvd, ddxd, ddyd ), b.x), b.y);
}

uniform sampler2D grass_tex;
uniform vec4 col_mult: hint_color;

void fragment() {
vec4 texture_modified = textureNoTile(grass_tex, vec2(UV.x *3.0, UV.y * 3.0));

//vec3 col = col_mult.rgb * texture_modified.rgb;

ALBEDO = texture_modified.rgb;
}
``````

Another question what is the equivalent of VectorOP>Multiply from the visual shader in written shader? Just doing color.rgb * texture.rgb doesn't seem to do the same thing as the resulting color is different from visualshader's vectorOP>Multiply

• Now that I think about it, I think messed up during the implementation of the texturenotile function as I didn't use fragcord/iresolution. I will have to play around with it some more.

• edited September 15

To get rid of repetition over multiple tiles, you would likely want to look into some global/world-space texture mapping.

I mean if you get rid of the tiling/pattern repetition within a tile and then tile it...

• edited September 15

If I recall correctly, `fragcoord` is the position of the fragment/pixel in world space, so that is probably what you will need if you want the texture to tile in world space instead of local space.

Though if you do not mind that the UV maps are modified, you can work around the issue by shifting the UV by the world position of the vertex. I had to reference the Triplanar Godot shader, but with the vertex modifications it should look like this:

``````shader_type spatial;
render_mode world_vertex_coords;

vec4 hash4(vec2 p){
return fract ( sin(vec4( 1.0+dot(p,vec2(37.0,17.0)), 2.0+dot(p,vec2(11.0,47.0)), 3.0+dot(p,vec2(41.0,29.0)), 4.0+dot(p,vec2(23.0,31.0)) ) ) *103.0);
}
vec4 textureNoTile (sampler2D samp, vec2 uv)
{
vec2 iuv = floor(uv);
vec2 fuv = fract(uv);
vec4 ofa = hash4( iuv + vec2(0,0) );
vec4 ofb = hash4( iuv + vec2(0,0) );
vec4 ofc = hash4( iuv + vec2(0,0) );
vec4 ofd = hash4( iuv + vec2(0,0) );
vec2 ddx = dFdx(uv);
vec2 ddy = dFdy(uv);
ofa.zw = sign(ofa.zw -0.5 );
ofb.zw = sign(ofb.zw -0.5 );
ofc.zw = sign(ofc.zw -0.5 );
ofd.zw = sign(ofd.zw -0.5 );
vec2 uva = uv*ofa.zw + ofa.xy, ddxa = ddx*ofa.zw, ddya = ddy*ofa.zw;
vec2 uvb = uv*ofb.zw + ofb.xy, ddxb = ddx*ofb.zw, ddyb = ddy*ofb.zw;
vec2 uvc = uv*ofc.zw + ofc.xy, ddxc = ddx*ofc.zw, ddyc = ddy*ofc.zw;
vec2 uvd = uv*ofd.zw + ofd.xy, ddxd = ddx*ofd.zw, ddyd = ddy*ofd.zw;
vec2 b = smoothstep (0.25, 0.75, fuv);
return mix(mix (textureGrad(samp, uva, ddxa, ddya), textureGrad(samp, uvb, ddxb, ddyb), b.x), mix(textureGrad( samp, uvc, ddxc, ddyc ), textureGrad( samp, uvd, ddxd, ddyd ), b.x), b.y);
}
uniform sampler2D grass_tex;
uniform vec4 col_mult: hint_color;

void vertex()
{
UV += (VERTEX).xy * NORMAL.z;
UV += (VERTEX).xz * NORMAL.y;
UV += (VERTEX).zy * vec2(-1.0, 1.0) * NORMAL.x;
}

void fragment() {
vec4 texture_modified = textureNoTile(grass_tex, vec2(UV.x *3.0, UV.y * 3.0));
//vec3 col = col_mult.rgb * texture_modified.rgb;
ALBEDO = texture_modified.rgb;
}
``````

The tiling doesn't seem to totally work with the cube I was using for testing though.

• Thanks so much, I'll try this When I have access to my main computer again.

• Hey.

I would just blend the texture with the same or other textures scaled (UV scaled) to different sizes in the visual shader.

If you want to do something like random dirt patches, you could have one big black and white texture that represents grass/dirt and then sample that with U/V coords and use that value to interpolate between a point on the grass texture and the corresponding point on the dirt texture.

Anyways just some ideas.