Techniques to reduce terrain texture repeating effect

Hi everyone,

What image techniques is there to reduce or eliminate the texture repeating effect when splatting texture on terrain material?

This is a sample scene where you can see that texture repeating is obvious.

I found this technique in which you make 4 textures by rotating the original textures (90 to 270 degrees)

I tried to follow this, I assigned these 4 textures on terrain material and as an example set the layer weights respectively to 0.5 (1st layer), 0.6 (2nd layer), 0.7 (3rd layer) and 0.8 (4th layer). It looks fine from a close distance but the repeating effect still is obvious from far.

Maybe I am doing something wrong?
Do you know of any other techniques?

Regards

1 Like

when you will blend multiple textures, then even just a little 0.1% blend will make difference.
(you can also blend same texture but in much higher shader-resolution to change colors - then repeatable would be visible only from far far away - in a lot of games it is visible anyway, but often grass mesh and objects make it not visible)

Just never leave space where there is only one same color in alphamap

or just make a very much things affect your terrain like metalness/roughness/parallax/color(AO)/etc

like here(its same color for alphamap here - repeatable would be visible but from far away):

1 Like

I’ve briefly looked at some other techniques you can do in the shader like the one you mentioned, but haven’t tried anything myself yet because I expect it would take a while and isn’t one of my top priorities yet. But I have found a few basic things that you can easily do to help terrain textures appear with less repetition:

Using tri-planar helps since tri-planar mode alters tex coords for non-flat parts of the terrain, so tri planar will also reduce the texture repetition as long as an area isn’t entirely flat.

And you can also reduce the repetition by mixing using more than one grass texture for your terrain, and paint them in a way that looks more natural (or even better, write some code that uses noise to layer 2 grass textures and 1-2 dirt textures in your alpha maps in a realistic way)

And (depending on your game and how complex you plan for your scene to be) the repeating textures on a terrain will also become much less noticeable once you add foilage models on on top of the terrain, like grass, bushes, stones, branches, etc etc. All of this will help to add variation to the scene and ends up covering parts of the terrain so the repetition becomes much less noticeable.

3 Likes

yes, the idea isnt bad, but IMO its very much shader work(i mean gpu) that is not really needed. In the idea case we already blend 4 textures that is really just 1 texture here. or am i wrong?

that is just IMO too much for what is needed. (unless gpu is not a problem)

While you can just blend 2-3 different(not same rotated) textures to achieve similar not-repeatable view.

I have noticed on very good gpu that a lot of blending can really affect GPU(and as i remember this was the reason why i use only 1 alphamap, since i already use a lot blending and it was better to just split terrain into multiple terrain Geoms so each Terrain had different “textures” assigned)

1 Like

Kind of but i wouldn’t say its “just one texture” since you can reuse those textures in multiple places in the terrain. And I think it also depends on how optimized the scene needs to be, my example of using 4 definitely would only be good for a desktop game aimed at higher spec devices.

But most games will already be using a dirt, grass, and mountain texture, so adding one extra dirt or grass texture that can easily blend ontop of those other 3 to add detail and reduce noticeable repetition isn’t adding too much. 1-2 extra texture slots on a few terrains will rarely be enough to make a game unplayable unless there’s already some other larger optimization issues at hand for the devices the game’s targeted for.

On my device, I end up having about 5-9 terrain texture slots on each terrain, and each has texture slot 3 texture reads (albedo, normal, packed MetallicRoughnessAoEi) and also operate in tri-planar which require 2 extra texture reads per texture, but surprisingly I don’t have any performance issues and can run at at least 60 fps, and much higher if its only terrains in the scene.

One big difference between our terrain shaders ( I think ) is that you support parallax, which from my experience seemed to really slow things down and required more texture reads, so I chose not to include parallax in my terrain shaders.

1 Like

yes, well, i also had 60 fps, but dropped from like 200-300.

and i had kind of 12 textures (if i rememebr correctly) where each one had albedo/normal/roughness/metalness/AO/parallax (yes i could pack it too, but still)

i remember there were a lot of increase just by avoiding additional alphamaps, but assigning required textures to certain “terrain chunks” material.

That does sound like a lot of texture reads. In my shader, each textures slot has half the reads since I don’t use parallax and also pack the metallic/roughness/ao together. And I rarley go over 8 texture slots so I can stay on just 2 alpha maps. But then I also use tri-planar which multiplies it by 3 if I remember correctly.

I also think the terrainPatch size matters, since a terrain comprised of more terrain patches ends up using more resources on top of texture reads. I always use 512 size terrains with 256 patch size so each terrain is only 4 geometries.

So overall I think it ends up being not so straightforward to calculate how fast a terrain will / should render.

1 Like

yes, well i also forgot that i had 1/2k resolution textures loaded, tho it should not affect blending(since its per visible pixel) but maybe it was also counting somehow.

Anyway based on this, 8 texture slots + 4 textures used per slot is “save for desktop”.

Tho idk if @Ali_RS is doing Desktop or Android game here (editor can be on desktop while game itself run in Android)

2 Likes

Yeah, game is targeted both for desktop and android. But the editor is only for desktop.

1 Like

hmm, and now its problem for me to tell, since im not sure how much blending Android devices can “survive”.

You would need to make some research about it.

But anyway IMO then you should use lowest blending amount as possible

1 Like

Another thing you can do is load a noise texture and use it to perturb the UVs. Combined with other techniques, it can be very effective. For example, if you layer two textures (a lores and a hires) then you can use different offsets for each… especially if your noise texture is four channel then that’s only one lookup.

Something like:

vec2 loresUV = ...
vec2 hiresUV = ...
vec4 offset = texture2D(noise, pos.xz) - vec4(0.5);
loresUV += offset.xy * NOISE_FACTOR;
hiresUV += offset.zw * NOISE_FACTOR;

Where NOISE_FACTOR is how dramatic you want to be.

Different noise will have different characteristics. I have a four channel smooth noise that I use quite often. I can provide it if desired.

Voronoi-based texture may also have interesting properties here but I’ve not tried it.

6 Likes

I am willing to give this a try. May I ask you to share this texture, please?

Will also check with voronoi texture you provided.

Thanks

For terrains you can also zoom textures as they get farther from the camera and then blend the zoomed texture with the actual texture (+ noise to get better results). That would mostly work only when the terrain is seen from a perspective and not flat, though.

1 Like

Yeah, for a lot of texture the lores texture and the hires texture can be the same.

I’m having trouble locating my 4 channel noise texture and I can only find my 3 channel texture.


It should be enough to try out the technique even if you have to sample it twice.

Edit: though note that for the technique, it probably as near as doesn’t matter to sample this texture once and use xy for one offset and yz for the other.

5 Likes

Thanks

Applying noise makes a huge difference, even with a single texture. :slightly_smiling_face:

Edit:
For the start, I tried Technique 1 and 2 from Inigo Quilez :: computer graphics, mathematics, shaders, fractals, demoscene and more (just a code copy/paste). They generate a random UV offset in code and do not use a noise texture. The result looks cool but not sure if they are optimized.

The next step is to try with the noise texture.

1 Like

and its great that way, the lowest amount of blending here, the better, expecially for Android.

1 Like

For the pos.xz should I use the vPos.xz (vertex position?) or texCoord.xy?

Edit:

Is this correct?

  float NOISE_FACTOR = 0.05;
  vec2 hiresUV = texCoord;
  vec4 offset = texture2D(m_NoiseMap, texCoord.xy) - vec4(0.5);
  hiresUV += offset.xy * NOISE_FACTOR;
  diffuseColor = texture2D(m_DiffuseMap, hiresUV * m_DiffuseMap_0_scale);
1 Like

Looks correct to me.

Easiest to see the effect if you use a checkerboard (multicolor preferable) as your diffuse map for testing.

Edit: and yes you are right about UV where I said pos. A lot of my stuff uses pos as the UV so my brain sometimes interchanges them when I’m in a hurry.

Edit2: Hmmm… except in this case, I kind of meant it. Though it wouldn’t work as written without scaling. You need some spatial input into the noise texture to avoid repeating patterns. The UVs are fine for your use-case. Sometimes a scaled position is better if you want to avoid repetition over a larger area than the UV covers.

1 Like

I was wondering this the other day so it’s really cool to see some discussion and ideas
:raised_hands:

2 Likes