DistanceToNearestSurface material node

Could anyone explain how to use the DistanceToNearestSurface material node in 4.9? I’ve tried to just use it as the base color in a material, applied this material to multiple meshes and expected to see the meshes change color once I move them closer or further away from each other, but that does not really seem to be the case. Even with no other meshes around a mesh there are black areas on the mesh which randomly get bigger or smaller when moving around the object.

I have checked the mesh distance fields with visualizing the distance fields, they are perfect, since I only use cubes.

So I would really like to know how to correctly use this node :slight_smile:

you probably need to make sure the current mesh isn’t also generating distance fields to avoid sampling its own distance field.

Well thats a problem then since all meshes need to have a distance field… But I have also tried it with a landscape, which does not generate a distance field, and it did not work there too. No matter how far I move meshes near the landscape, the color does not really change.

I think ryanB and danielW are aware that landscapes do not generate distance fields. It would be amazing to get that implemented. Will have to see how epic want to use their resources. But they have my vote for that feature.

The point was that Ryan said I have to use a mesh which does NOT generate a distance field to use this node in the material from the mesh. So a landscape would be perfect since it does not generate a distance field.

The reason you dont want the shader reading distance fields to generate a distance field is that it will always return its own distance field value thus it will never really give valid information about other surfaces. You will basically see the interference pattern between the mesh and the low resolution distance fields. As you move the mesh you might see it flash black as it happens to line up with the sampling resolution etc. This is just a fundamental limitation of this method. In most cases it isn’t a problem though… what exactly are you trying to do?

You could try to work around it by sampling at an offset position along the vertex normals. Basically take worldposition + (vertexnormal * offset) and that will let you sample a bit away from the actual mesh. As long as the intersection with the neighboring surface continues along in a straight-ish line a decent distance away, the result should be somewhat valid. But if there was an intersection that curved away from the object fairly close, it might be missed etc.

FWIW, that is the same basic method you would use to trace a rain mask if you wanted rain splashes automatically on the ground, but have things like awnings block the rain. You would simply “get distance to nearest surface” a few times each with a greater Z offset and if any result gets within a certain threshold you mask the rain.

Thanks!

It should work fine with a landscape, right? So if I apply a material on the landscape which uses the DistanceToNearestSurface as the base color I should see the landscape turning more dark when moving meshes near it which generate distance fields, right?

Yes. I just tested and its working for me. Is it possible you aren’t dividing the distance by enough to make it visible?

The quickest way to check if its working is to make “distance to nearest surface” goto emissive, then view in unlit and throw a giant cube on the landscape. Select the cube and find the property “render in main pass” and set it to FALSE. That way you can be sure you are seeing the black area inside the cube. Normally when you hide a mesh it will also hide the distance field so it can be tricky to debug sometimes. And of course if you dont see anything, visualize the mesh distance fields to make sure your cube shows up at all there.

Most of this has already been said but just for completeness:

DistanceToNearestSurface only works if you have ‘Generate Mesh Distance Fields’ project setting enabled (you have to restart editor after changing), and you are on DX11 hardware. This means Geforce 4xx and above, Radeon 6xxx and above.

DistanceToNearestSurface will always return around 0 if sampled on a shadow casting opaque surface, by definition. It’s the distance to the nearest opaque surface. However only static mesh components + foliage + instanced SMC’s actually have distance field reprsentations, so on something like Landscape you should get a non-zero value. On other meshes you have to disable either CastShadows or bAffectDistanceFieldLighting in order to sample the distance values of other meshes.

Going forward we can have landscape affect the global distance field, let me know if that would be useful.

2 Likes

Thanks for your answers, I still can’t get it to work :frowning:

If the cube is “going through” the landscape, I actually see the different color in the landscape.

If it’s just “touching” the landscape perfectly, I still see the black on the landscape:

But once it is slightly above the landscape, the landscape again is pure white.

The mesh distance fields are good:

“Local” Distance field:

Global Distance Field:

Another thing I noticed is, if I disable “cast shadows” on the cube, the landscape turns fully black. I tested a bit more and noticed that I need to have at least one shadow casting mesh in the world, otherwise the landscape is fully black. I have “cast static shadows” disabled in the project settings.

I have also tried to divide the output from the node and to power(0.2) or power(20) it, but it really just outputs a perfect white (0/0/0) even if the cube is just 0.01 cm above the landscape :frowning:

What did you divide by? Try dividing by 1000. It is expected that it turns white as soon as the cube is slightly above since the distance is in world units or centimeters. So only 1 cm above means full “white”. The color white isn’t really meaningful since its just clamping the output color to white… the values keep climbing.

fwiw if the cube is not touching but you want to treat it as if it was, you will need to apply a bias by adding a scalar parameter value to the result. But that will bias all surfaces equally.

Also, it may in some cases help to fly the camera far away and then back up close after making changes to distance field settings. I have seen some bugs where the global distance fields get corrupted momentarily. The hard edges in your 2nd image look suspect to me.

Thanks a lot, dividing by 1000 helped. It’s awesome :slight_smile:

What I want to achieve is actually masking the grass node in the material, so make grass not spawn where other meshes are near, so it won’t spawn in the floor of a building etc.

This is the cube in the ground:

I lerp with the mask based on the DistanceToNearestSurface node between red and blue, so the mask is really good (I would really like to see a “Gaussian Smoothing” material node, I would use it so often :rolleyes:).

Now I try to do this:

3240a759b0.png

And it would actually work, but after testing with a manual alpha value I noticed the grass only updates after I hit “apply” in the material again and I can’t change the alpha e.g. in a material instance, changing it after the material is “compiled” does not update the grass :frowning: Would have been so awesome if it would have worked… :confused:

That would be very useful indeed. For example, you could mask crashing waves on ocean planes and in reverse make effects for wet sand, erosion or what have you. Yes, pretty please with sugar and cream and jam and chocolate on top :slight_smile: