Download

Sharper landscape layer height blending?

Hi, I’m trying to height blend my landscape layers but I can’t get more sharp/precise blending.
I’m using heightmaps with increased contrast (lerping heightmaps with -10 and +10 value or even more) but I think that heightmaps lacks of precision (maybe it’s possible to derive height from normalmap?)
Here’s what blending a rock layer and a pine forest ground look like :

What do your height maps look like?

What does your landscape material look like - particularly the two textures and their height blends?

Assuming your material has a height map, you’ll want the blending function to look something like:

coverage = saturate(toplayer.weight * 2 - 1 + toplayertexture.height)

If you want a sharper transition, you can make it look something like:

coverage = saturate(toplayer.weight * 11 - 10 + toplayertexture.height * 10)

​​​​​

pretty sure the OP is using the built-in landscape layer height blend and just plugging material nodes (while the blend function is internal to the engine shaders). I could be wrong though

if I’m not mistaken you’re using the buit-in landscape layer height blend? if so, keep reading

I’ve spent quite some hours trying to achieve what I think you want, basically having a ‘hardness’ parameter value that should -if needed- allow up to purely binary hard blending.
with the way layer height blends work internally (a -1 to 1 lerp with the height value as alpha) anything I tried that would give me a harder blend (biasing, multiplying, etc) was also giving me negative blend values in some of the blended layers, causing wrong blending here and there.

my personal conclusion was that I’ll need to modify the engine shader to achieve what I want. once I get back to this work I’ll try that route, though I’d love to not need to do it.
so really curious if you find a working solution.

nice scene btw :wink:

You’re exactly right. I was using the layer blend node set to “height blend type”. Then I found this post from Ryan : https://forums.unrealengine.com/development-discussion/rendering/100598-terrain-material-height-lerp-and-slope-mask-problems

This part is interesting : “If you want to do it manually, then you shouldn’t use the “layer blend” node at all, instead you just place “Layer Sample” nodes and use those as the input to “transition Phase” on the heightlerp node. I feel doing it this way gives you way more control and as a result I never used ‘layer blend’ for any reason.”

Using the HeightLerp function node and use the alpha output as alpha input of a BlendMaterialAttributes gives better control and sharper transition than the height blend function of the Layer Blend node.
Now the problem I’m trying to fix is the blending of the very first layer.
Actualy I’m blending the material attributes of the “layer2” and “layer3” with the heightmap of the layer3, “layer3” and “layer4” with the heightmap of the “layer4” and so on.
But how do I use the heightmap of the layer1? Because I’m blending layer1 and layer2 with the heightmap of the layer2, so the heightmap of layer1 is unused and leads to this issue :

Layer1 is grass
Layer2 is pine
Layer3 is rock
The whole landscape is filled with rock layer then I’m trying to paint some layer2 (pine) and while I’m having some nice transition between layer2 and layer3, layer1 is drawing even there’s no layer1 painted here :

by not using the layer blend node you’re going the route of a manual blend, more in line with what jwatte suggested. like you say, using Layer Sample mixed with the heightmap.

with your current setup you could blend a blank layer of “nothing” (black color) first with layer 1 using the sample of layer 1. at least it would give you a result where you’d visually see where no layers are painted (similar to when you use layer blend node). it’s a good guide to know where you haven’t painted anything, but blending with this blank layer is an unnecessary cost.
leaving it as you have it isn’t a bad idea either. I know having layer 1 everywhere as a background isn’t desired, but you’re gonna want to paint layers everywhere anyway, and you’ll replace it with the real layer1 or with others in the end.
consider that [if you’re using weight-blended layers] all the painted layers will be normalized so their accumulated weight is 100%, so for example if layer2 is painted to 20% and layer3 is at 0% the natural result would be that layer1 is there at 80%. while this isn’t the case right now as you haven’t fully painted your landscape, it will be the case once you paint layers everywhere, and your problem won’t be a problem anymore - and that’s why in the end it’s unnecessary.

taking a step back though, this approach of manual blending is something I was trying to avoid. to elaborate on why:
like I stated above all painted layers get normalized so that their accumulated weight is 100%. however when you modify a layer’s visible weight through a heightmap at any given point, you increase/decrease the weight of it and therefore you should counter decrease/increase the weight of the other blended layers at that same given point. the layer blend node does exactly that internally (it re-normalizes the other layer weights after the heightmap modifies a layer’s weight).
by doing the blend manually you don’t have access to this functionality, you simply blend the layers with an order of precedence (the order that you put your blend nodes). the result of this will be that the higher-order-blend layers will “bury” the lower-order-blend layers. if your layers come from worldmachine or similar you’d start noticing that the lower layers (layer1, layer2…) will not be as visible as they should, and higher layers (layer99, layer98…) will be more visible than they should.
if you paint your layers manually though, you won’t care much because what you see is what you paint.

that’s the theory at least. in the end I don’t know how noticeable this issue would be, and therefore if it would be a real issue to worry about.

Blending a blank layer with layer 1 result in having this blank layer showing instead of the grass layer where two layers blends (so when two layers are painted, not only where no layer is painted)

The problem with the setup in the previous post (Layer1 blendend with Layer2 heightmap) is that Layer1 is showing where two other layers are crossing. I think it happens where both heightmaps are black, which means no blending, so it draws Layer1 (because the alpha of both BlendMaterialAttributes nodes is 0)

Ok, now I understand what you’re saying about weight blend layers.
So yes, as soon as I start painting Layer3 over Layer2 it decrease the weight of layer 2 but because every black pixel of Layer3 heightmap means no blending, it doesn’t increase the weight of Layer3 for those pixels so Layer1 is shown here.
Is there something I can do to fix this or do I have to use no weight blend layers (which are a pain to use)?

The main problem is that, if you paint layer N+1, the weight for layer N and below will be reduced.

If you’re going entirely manually, you can interpret the weight of each layer as a “replacement” constant instead. If that’s the case, then you can construct the weight of the “next” layer as the sum of all the layers above it.

There’s no perfect solution to this, but one option is to treat any value greater than 0.1 or so as 1.0 – e g, the “weight” of each layer is saturate(10*paintweight), and then adjust that further a bit through your height-based map.

if you want hard blending your blending function should not make those areas result in 0.0 value blend.
it’s simple, in an area if you have just one layer painted (and nothing else) and the heightmap’s black pixels make the blend value 0.0, you’re basically telling it to not show that one layer, so it has nothing else to show.

you need a different function that blends the heightmap with the layer sample in a way that black pixels don’t result in 0.0 blending.
as I see it, conceptually what you need is a blend function that when the blend value is 0 it blends nothing, as the value increases it blends with the heightmap, as it reaches 0.5 it fully blends the heightmap, and as it get close to 1 it discards the heightmap and does a full blend.
you’ll need some time to figure out the math though

But this is not doable in material graph right?

Yes it is, if you sample the layer weights directly instead of using the built-in landscape blend macros.

Do you mind showing me what it would look like in graph then please because I don’t get it

At least 10 characters.