Change material based on height

Hey guys!

In a nutshell, I am trying to replicate the effect of landscape strata - the layering effect seen in certain rock types and so forth - but I want the strata to be based on their relative “depth” in the world. That is, I would like to be able to tell it to change color at a z-depth of -128, for instance, regardless of where the mesh it is applied to is. But I have run into a bit of a wall figuring out how to set something like that up. Any advice is very appreciated.

Is it actual depth or world position Z axis you want the material to depend on ? Both are doable. You can get Z-depth by calculating distance between pixel and camera position. Z axis world position is already stored in World Position node, so that should be quite trivial.

I did something like this for the Elemental demo way back. Here are some examples:

Getting it to work is fairly simple. First, its just a simple 1d texture that I made by taking a snip from some random texture. Pretty much anything can work and you can get different looks by changing scale.

To sample the texture, you place the WorldPosition node and then component mask for the B channel. Then you divide by a scalar parameter value. This value is your ‘total gradient height’ in world units. After the divide you could also do an add with another scalar parameter that lets you vertically shift the value so you can offset the texture.

Then to sample, you just need to make it into a V2 using the Append node. Hook a 0 into A, and put your WorldPosition.B expression into the B. Note that you don’t actually have to use a 1d texture, you could try using a regular 2d texture and then you can try different slices of the texture by also making the UV.X component into another scalar, so instead of 0 if you enter 0.5 it will take a vertical slice from the center of the texture.

I was just multiplying that texture by the basecolor but I was also using the basecolor as a mask so it would affect the dark part of the basecolor more. This helps it look less like a straight multiply and hints that small rocks and pieces of sediment can be brighter than the dark stripes. If you don’t do that step it may look a bit fake.

To do that I took the basecolor.R, hooked that into the Alpha of a Lerp and then put scalars into A and B. Call them StripeMask Min and Max or something. Then put a clamp default 0-1 node. Then you can use that to lerp between your stripe texture and 1 and then you can control how much the light vs dark parts of the basecolor are affected by the stripe.

2 Likes

Absolutely excellent, thank you for the answers, guys. I am on my way to success. :smiley: