The "small issue" you're having is actually not that small. The way a shader works, is it calculates a pixel color independently from other pixels. Carlo calculates mathematically if a pixel is within given area (e.g. on a given height), but he doesn't have access to neighboring information. Ideally, you would prepare textures in a separate program, using algorithms that analyze the raster image in order to create paths between areas of the same colors, and then you would color these paths. It's not a trivial task either, and Blender nodes are much more limited, because you only have a single pass, where each pixel is calculated on its own. Well... Since you're using a height map texture, and you can transform the mapping to shift it (kind of like moving a piece of paper when it's being scanned), you actually can sample other pixels. Still, if you create a whole program, finding edges, in nodes, not only the node setup will be HUGE, but it will be run for each pixel instead of once. I'm saying all this to preemptively justify the complexity of following node setup (and the result isn't jaw-dropping):
Result: (black/yellow for better contrast)
TLDR - how it works: instead of drawing (yellow) two borders directly, I prepare to draw one area inside two borders. Then I'm sampling 8 neighboring pixels if they're also in the area. If less than 8 pixels are - I'm on a border and only then I actually draw (that is, I actually change color from black to yellow).
Explanation of nodes from left to right:
- Offset and divide by - how far is the neighboring pixel from the current pixel. The 2nd node is just a value used to divide the former. This way I gain precision on manually changing the input value.
- 4 nodes representing the offsets, making the diagonal offsets shorter, but perhaps I shouldn't.
- 8 nodes combining XYZ into vectors, creating vector offsets in 8 cardinal directions.
- standard UV mapping into the image texture, and then 8 image textures moved a little used the 8 XYZ combine nodes.
- custom node group, checking if a given pixel is in the specified area.
So far an example path for a pixel:
The green node:
- There are MIN and MAX inputs to precise the area. You could replace it with a single value or modulo, as well as you can replace Greater than + Less than with Compare like with Carlo's answer.
- Again, I divide those values just so it's easier to interactively modify them.
Let's go out of the green node and continue:
- Add math nodes to count all
1
outputs from green nodes, meaning that those pixels are inside the area.
- If less than 8 such pixels got counted - it's a border pixel.
- If the current pixel is also in the area, then the multiplication on this node will be
1 * 1 = 1
and the next RGB node will use yellow color.
Now, let's disconnect those two nodes:
And let's go to the green node and adjust MIN and MAX to get an interesting area:
Reconnect recently disconnected nodes and adjust the Offset node for border thickness. Large thickness will produce artifacts, which you can combat by adding more samples (so more XYZ - Mapping - Texture - green - Add node paths)
I took the height map from here: 50 displacement map variations of gaea's hero mountain
Link to the folder with the texture: Var_05