Important Disclaimer:
I originally wrote this article nearly a year ago, and never had the intention of publishing it to a public blog. I wrote it when I was studying terrain shaders for my own personal projects and its purpose was to further my own 'ground-up' understanding of how advanced shaders work in game engines for terrain.
The information in this article isn't necessarily accurate or representative of modern terrain shader techniques. Nor should it be presumed to be all-encompassing of every possible shader technique for terrain shader building. Also, it was written to make sure I was able to comprehend the article for my own note-taking, and I never proofread or edited the article with the intention that anyone could pick it up, read it, and understand it. So please forgive any typos or grammatical errors.
Nor should it completely represent my current experience and knowledge on this subject or any other. As I said, I wrote this article nearly a year ago, and I have continued to experiment with these shader techniques and many others since then.
The reason I decided to publish this article on my blog is because of a terrain shader discussion that I'm involved in where I thought this information could be helpful to others trying to understand terrain shaders - as I was nearly a year ago.
Believable Terrain in Unity
01.23.2017
12:30 AM
─
Overview
Terrain in games, no matter the game engine, is always a challenge. Many games, indie and triple-A alike, will create basic terrain that functions for the game as necessary, but may not be pretty. While other game developers have taken on the challenge of creating convincing and believable terrain, sometimes even photorealistic such as the case was with DICE in Star Wars Battlefront (and perhaps in BF1).
This article is specifically meant to study and address the challenges with making believable or realistic terrain in Unity, although many of the principles and techniques here may be applied to other game engine tools.
Identifier Descriptions
The Terrain Model
Identifying the terrain model when discussing the subject of ‘terrain’ in games can be slightly confusing. To clarify, a terrain model in a game engine is usually one large, generally seamless, piece of geometry that is often derived from a heightmap.
Some game engine tools, such as Unity and Unreal, will have tools for generating a generic heightmap texture to start with. The resulting geometry can then be modified afterward with sculpting tools provided in the software, but these tools aren’t actually sculpting the geometry, but instead they’re painting the heightmap, and the heightmap is modifying the geometry.
The terrain model is the very foundation with which a convincing terrain in a game is built upon. The terrain model alone will never look convincing, but instead must be added onto with lots of models on top, such as boulders, grass, trees, bushes, rocks, moss etc.
Terrain Meshes or Objects
As mentioned in the terrain model description, in order to create a convincing terrain environment in a game, it must be built upon with many terrain meshes.
Even a highly detailed terrain mesh with tessellation is too simple to appear convincingly realistic, and tiling textures will be apparent without a needlessly absurd terrain material, which isn’t a realistic solution in any situation. To help create variation, a library of terrain meshes must be created. Whenever a terrain mesh library group is created for the purposes of realism, great research should be taken into consideration for the type of biome with which it’s being created. A desert terrain mesh group should contain only rocks, foliage, and other terrain objects that would naturally be found in that environment in reality. These should all be artistically balanced with the environment materials.
Terrain Materials
Materials for use on terrain are very specifically built for that purpose. They make heavy use of texture blending, preferably using height blending for realistic transitions. Masking is used to realistically layout topographical regions with their corresponding textures, such as rock walls, grass, mud, sand, etc.
As of 1/23/2017, the Amplify Shader Editor that I use does not have a layer blend node that is exactly like the layer blend node in the Unreal Editor. I believe that the same method can be achieved in Amplify/Unity by creating a template nodal setup containing a Lerp and a Heightmap Texture Blend, and a texture sample node containing the mask painted and/or derived from topographical data. Additional nodes of interest are the Layered Blend and the Weighted Blend. The latter nodes I mentioned may be a work in progress at this time, worth investigating through Amplify website or forum resources.
Terrain Shader Masking Techniques
Ramp based masking
Can create 3 masks based on RGB
Is procedural, uses ramp color node for 3 (RGB) masks in combination with the height map to drive high up masks, slope/angle-based masks, and lowest altitude masks
Can not be hand-painted
The masks will automatically update as the artist sculpts the terrain height map
Blending transitions between different textures can be driven by a height map (or any mask), giving a realistic transition instead of a generic 0-1 gradient. This part is not procedural and requires use of a texture sample.
Vertex color masking based on the terrain model’s individual Vertex RGBA values
Not limited in a 'data-driven' manner - it can be artistically hand-painted
Blending transitions between different textures can be driven by a height map (or any desired mask), giving a realistic transition instead of a generic 0-1 gradient
Can blend 4 channels with R, G, B, and Alpha
Theoretically 5 textures can be blended, with the base texture not needing a mask (could conflict with underlying textures)
If all textures require a vertex mask, then the limit would be 4 blended textures
Painted texture masking
Not limited to procedural data - can be artistically hand-painted, or driven by data taken from other sources if it is in a grayscale image form
Due to the large size of the terrain, and the inherently large size of the terrain mask textures, Sparse Quadtree Texturing (Mega-texturing) will be a necessary technique to utilize for saving memory [1]
There are some interesting plug-ins that deal with texture streaming in a seemingly better way than Unity’s built-in Sparse Texturing structure; Amplify Texture 2, ,
Each texture would need its own corresponding painted mask
Consumes more texture interpolators. This isn’t that much of a problem on Shader Model 4.0+ (which has a limit of 32 interpolators)
Not limited to 3 masks with RGB values, however it is limited by maximum texture interpolator allowance depending on the Shader Model being used. As well as possible performance issues in real-time
Combining all three of these texture blending methods in a terrain shader can facilitate a way for the dev team to create a realistic terrain model. This can then be used as a reasonably complex and good looking foundation to build upon with terrain meshes, and story-designed layouts in desired areas of the terrain.
Many of the masks used for texture blending could also be used to drive procedural placement of terrain meshes, like trees, rocks, bushes, etc. But further research is needed to discover how this can be accomplished in the Unity engine.
Triplanar UV Texture Projection
Simply having the terrain projected from one direction, in the Y direction for example (from above), will create significant texture stretching issues on steep slopes, like off the sides of cliffs.
To avoid this issue, triplanar projection must be utilized, which completely eliminates all stretching issues. The technique is pretty self-explanatory; the texture is being projected from all 3 UV directions, instead of just one. This is a well-documented and easy to implement shader function.
Here’s a decent overview of triplanar projection use for terrain texturing:
https://gamedevelopment.tutsplus.com/articles/use-tri-planar-texture-mapping-for-better-terrain--gamedev-13821
Here’s 3 different examples of a triplanar projection setup in Shader Forge:
http://acegikmo.com/shaderforge/wiki/index.php?title=Triplanar_Mapping
This technique is a bit costly when it comes to performance, because the textures that are being triplanar mapped are being rendered 3 times. It might be worth only triplanar projecting textures that are going to be used for slopes or potentially painted onto the slopes.
Terrain Objects
This section of the article will cover the technical considerations when authoring terrain objects which will be duplicated and/or instanced all over the terrain model.
TEMP: Notes
NOTE: Government websites that allegedly have terrain data are clumsy and incredibly difficult to navigate. It’s very hard to find the usable data that can be transferred to a heightmap for game engine use. Look for a way to get real life terrain-based heightmaps for terrain generation.
Resources
Sparse Quadtree Textures may be necessary for terrain shader texture painted masks. Information on implementation in Unity is available here
https://docs.unity3d.com/Manual/SparseTextures.html
Frostbite (Battlefield, Battlefront), large amount of information
http://www.frostbite.com/2009/08/terrain-rendering-in-frostbite-using-procedural-shader-splatting/
Place to get terrain data (Referred by [Redacted])
http://www.arcgis.com/features/free-trial.html?origin=arcgiscom-Desktop
Maybe the easiest way to download terrain data for importing heightmaps
http://terrain.party/
Witcher 3 developer documentation on Terrain
http://twvideo01.ubm-us.net/o1/vault/GDC2014/Presentations/Gollent_Marcin_Landscape_Creation_and.pdf
DICE presentation on Battlefront Environments and Photogrammetry
https://youtu.be/U_WaqCBp9zo
Potentially interesting presentation from the Firewatch team
http://www.gdcvault.com/play/1023191/Making-the-World-of
Interesting Dev write-up, includes Ramp node use in Shader Forge for Stylized terrain
http://popupasylum.co.uk/?p=779#prettyPhoto