Unity custom terrain shader - height-based blending + triplanar projection + single pass
I've been working on this custom terrain shading system for Unity 5.5 to improve two aspects of the built-in Unity terrain: texture stretching on vertical terrain, and overly simplistic linear blending between textures.
This is used in our game, INFINITE
I'm thinking of possibly going open source with this, if it will help anyone else and if there is enough demand for this. Right now, it's not in any state to pass on to anyone, because the tooling isn't polished enough and the shader makes some hard-coded assumptions, like using 8 splat maps.
Please let me know your thoughts on this.
Background, and why a custom shader
There are some tools on the Unity Asset Store that is far more advanced - specifically RTP 3.3.
However, for 3 reasons I finally decided to create this from scratch, instead of using RTP:
- I had some some technical issues with RTP in Unity 5.5 that I ultimately was unable to resolve.
- RTP is very complex - probably too complex for what I needed for INFINITE.
- We use a custom lava shader on a plane that blends seamlessly into the terrain at its edge. This fake terrain edge has to exactly match the actual terrain look. The custom RTP shader would never exactly match that visually.
Technical / details
This shader can render the terrain with 8 splat maps in a single pass. It does this by taking the Unity terrain textures and packing them into various atlases and combined maps. So overall, the sampler count is reduced enough so that the terrain can be rendered in a single pass.
For the shader to function, you need not only the regular colour map and normal map, but also a height map. Optionally, you can add smoothness maps as well (usually placed in the colour map's alpha channel for the standard Unity terrain shader.) I'm using materials from gametextures.com, which includes everything that is required.
The overall blending is still controlled by Unity's splat blending maps, but the blending now also takes into account the relative height of any given pixel. The height based blending is based on a fairly simple approach of applying both a power and a multiplier to the height value to determine the blend strength relative to other textures.
This gets rid of any stretching by projecting the texture on 3 planes. Not much else to say about it really.
- Performance concerns. Optimisation is needed, although I'm still getting 90fps in INFINITE without any optimisations.
- Atlas rendering breaks at lower MIP levels. Will need to manually pick the MIP level.
- The system needs to work with a variable number of terrain textures, not just 8.
- The tools need some work.