Virtual Height Mesh + multiple RVT sources: landscape position is missing

in UE5, I’m using Runtime Virtual Texture (RVT) for both landscape an a spline road blueprint in order to “print” the road on the RVT and blend it with the landscape (see tutorial about this here). I have been adding Virtual Height Mesh (VHM) support but I am hitting a roadblock (!), as I think there is something missing in the RVT+VHM combination at this point. Here are the details:

Both the landscape and the spline road BP material are using RVT and VHM. While the road properly displays displacement when the landscape is flat, it does not when there is a hill on the landscape:

The reason of that issue is that we need to add up the Absolute World Position (AWP) Z coordinate of the landscape to the road height in order to take into account variations of the landscape height, and I don’t see how this is possible. Both the road and landscape material are writing to RVT’s World Height but I don’t see how they can add-up.

In the above screen (spline road material) I’m adding up the AWP Z to the road height but that won’t work, as AWP returns the spline position, not the landscape position. And when in the landscape material, we cannot access the road’s height data.

Edit: I also tried to output the road height from the spline BP material to the RVT WorldHeight and the AWP from the landscape material to the RVT WorldHeight, in hope they would add up: this didn’t work, this may be due to the fact the spline BP material also writes to the Opacity of the RVT. If this opacity is taken into account for the WorldHeight calculation, then they cannot add up, WorldHeight should ignore opacity for things to work I guess.

So unless I am mistaken, it looks like we are missing something here. Thanks if someone can shed some light on this, and potentially relay to the WHM developers if indeed this is a limitation of the system currently.

For me, I paint only in the Z of the WorldPosition in the mesh-material. One only wants to add Z-values (owing to the nature of the heightmesh) and only in the 0-1 range of the thing you are painting into it.

Since the heightvalues are ADDITIVE into the world-height channel of the RVT output, just add stuff into it one by one, they normally do not need to know about one another.

Times you might need to be aware of the other stuff is if you say, want to sample the height of the heightmesh so you can math some height-blending to look better. Or reference that height so you can always blend across a fixed vertical distance above the mesh, you’d need to know the height-mesh height there as well.

For straight-up, I want to paint into the RVT so it just-comes-out-on-top-of-the-heightmesh: WorldPosition ->ComponentMask(Zchannel) right into WorldHeight in the RVT outputnode for your mesh-material.

In your case, if you really want the height of the landscape, you might need to reference the worldheight in the RVT since WorldPosition in the brick material will give you the position of the brick-pixel, not the landscape.

Use a RVT sampler node to grab the height and use it as you would otherwise.

I’ll check the tutorial and see if I can make it work. I have an alternative solution for something like this but always eager to see if someone else has a tidbit. Gimmie a day or two as I am working on something ATM.

1 Like

I didn’t have this working. Outputting the road height into the RVT WordlHeight from the road material and the Abs World Position from the landscape material didn’t produce the expected effect, they just didn’t add up.
Note that when writing from the road material into the RVT, we also write into the Opacity channel, maybe this is what is preventing the landscape height to add up, because from the landscape perspective, its opacity is 0 at location of the road (well, in order to display the road).

Problem is this is too late, we must write into the RVT WorldHeight while writing to RVT, not after.

Great, I’d be glad to know if you find a solution!

You can render multiple things into the heightmesh. You can also sample-from and render-to the RVT in the same material.

I do the very thing I described above with the sampling of the heightmesh height from the RVT and use it to build a height/heightblend mask for landscape blending.

Height, for whatever thing I am using, is piped right into the node. The RVT height is only used for the blend.

I get using the spline is different as it can reference the world-positioning of the spline when deploying meshes, but let me look at the video.

I can say for sure that for rocks, debris, etc, stuff I paint with a grass-layer and/or the foliage tool, the above method works. With the spline-method, I can see subtracting/diff against the position of the spline vs the heightmesh and/or mesh itself might be required, but in any case, what you need in that trio is all available via some path.

1 Like

Yes we can send to RVT and read from RVT in the same material graph but per my understanding, they are run one after the other, i.e. write to RVT first, then read from RVT. And we cannot connect a read from RVT to a write to RVT (this leads to an error msg in graph) in the same graph, they are like 2 independent subgraphs.

Anyway, my understanding may not be correct, but so far I didn’t manage to make the stuff work. Hope there will be a solution!

I got this sorta working.

As suspected, in the splinemesh material, I needed to get the height from the landscape RVT and add it to the quantity (heightmap * VertexNormalWS). Anything else and I ended up with a flat-ramp given the mesh is flat along the path of the spline.

The Z-nature of the heightmesh means it can only deform straight up. If you want to modify the deformation to follow the surface, multiply the height/displacement/offset value by the VertexNormalWS so it’s deformed along the normal.

This, however, doesn’t resolve the fundamental limitation of z-only deformation. As the surface becomes more sheer (wall-like) z-deformation means less and less. You can’t use the heightmesh for walls (believe me, I’ve tried)…

My solution was to use a landscape-layer with a tiled-texture and just-paint it in as a ‘regular’ layer. That has the disadvantage of not being oriented along a spline but it IS cheap… Otherwise I had a spline-tool where it did the whole distribute actual bricks/meshes along the spline and their materials painted-into the RVT like we are doing here. As part of that spliner-logic, it would line-trace down to the landscape and make sure the bricks were all positioned appropriately. Something like I would have imagined was used in Elden Ring and the like.

How do you get the height of the landscape from the spline material? That is the main issue I have :wink:

Or if you get if from reading the WorldHeight from the RVT in the spline material, then how do you put that value (with proper addition of the road height) back into the RVT WorldHeight still from the spline material, knowing that if we read from RVT we cannot write back?

You can get the height of the landscape if you use enough spline points to hug the terrain. The system can handle a few more or less, as long as we’re not getting into the 100’s per spline. Generally where the terrain rises or dips, and you can lessen than if you choose to sculpt your landscape to help flatten, etc.

Regardless, if you want to make sure you get as exact a height as possible, loop through the spline-points and run a line-trace down and get the hit off the landscape. Move the spline point to the location of the hit, repeat for the rest of the spline. Be sure to use a 0-oriented loop as the first point is point-0.

On step 0, the first point, I also move the location of the spline itself so the ‘handle’ (Critter-icon) doesn’t get too far away from the spline points.

From there, you can use the WorldPosition node to in your material get the height of the spline.

As an additional-step, you can also get a reference to the landscape from the line-trace, cast, and then apply a spline to the landscape, and have it paint in a layer, in case you want to piggy-back any logic in your RVT onto/along-with the spline material; maybe make it paint in a dirt-layer so there is always dirt around your bricks, etc.

Be sure to add enough points to hug the ground, run your trace/set on the points, then use whatever material you want to use.

Remember, the issue with the lack of height on slopes won’t ever go away because all we ever get out of the RVT is an XY-projected texture for reference; you need an actual mesh to get away with any kind of concave surface detail.

So basically your approach is to use the spline points as reference for the terrain height by making them super close to the landscape, then the value of WorldPosition in the spline material, returning the spline height, will also return the terrain height? Well, it will return an “approximation” of the terrain height, I experimented with this earlier and that is not a suitable solution, because the landscape has many more height variations along the width of the spline that the latter has. The spline is basically flat, however when projected on the RVT, it tightly follows the terrain height in every detail. So using the spline point as height for reference may work in very favorable cases when the terrain has no slope along the width of the spline, but else it does create very bad displacement which do not follow the terrain shape.

There are probably ways to get this issue addressed but it would probably require the addition of new mechanics for landscape RVT. Knowing the landscape information is central to landscape RVT, it would make sense some of it (here, the height) is accessible outside of the landscape material alone.

This is where adding additional spline-points (increasing the sampling-rate) will help.

Will be exact, 100%? No, of course not, we’re trying to make two independent things talk to one another via materials so we’re not going to be able get pixel-perfect fidelity.

I use a decent amount of deformation and I can imagine one might want the spline to follow every small nook and cranny but that might be an unreasonable expectation given the way it currently works. My suggestion about adding spline-points would be to follow the deformations in the landscape, not the landscape-material.

OR, a thought, if you REALLY want to communicate pixel-perfect (and I do understand that particular kind of drive…) you COULD try (I’ve not used it but thinking out loud…) using a scene-capture/render-target to get the depth of/to the landscape and use the RT in your material?

This article has something along the lines of what I am thinking of insofar as the scene/depth capture.

1 Like

It helps only along the spline length, not the spline width. The wider the spline, the less it will conform to the terrain regardless of how many spline points are used.

This is a very interesting idea, if we can read the scene capture from any material then this could work I guess. I don’t know this area at all but it looks like and interesting path.

No it does not. Only suggestions here might be to use a gradient out towards the edge of the spline and gradually drop the height in the material so it fades out/down into the landscape as it moves towards the edges.

Otherwise, with this kind of limitation in-mind, was my suggestion to apply a spline to the landscape so you could use a painted layer to help smooth out the landscape where the road would appear; attack the problem from both ends as it were: if the concern is getting the spline to deform as close as possible to the layout of the landscape, try and at least make the landscape as favorable to the spline as possible.

Good luck!

Besides the render target option you mentioned, the other options discussed may somewhat reduce the issue if adopting some constraints but are not really “solutions” in my opinion. In the current state I prefer not using the height mesh field at all instead of going into crazy complications to get something half-good. The render target is really worth trying though, I’ll probably check it out some day. Thanks for the discussion @Frenetic

FWIW I can say from experience the heightmesh can give some very workable and pretty results. As well, one is able to use the scene-capture and interact w/height there-in.

I use the tutorial I passed over in conjunction with my snow-layer (run in the heightmesh) for deform-able snow-trails, no tessellation needed. Works like a charm.

1 Like