Update 133: 02/10/2018 TERRAIN SYSTEM REVAMPIf you've ever used the Unity terrain system, you'll know the workflow, performance, and quality is awful.
Previously, it would take me about 30 minutes to convert my levels from block mesh to terrain.
This was an arduous process which produced sub par results.
I decided to take time time to automate my terrain creation process, and also improve its artistic quality.
---
IMPROVING TERRAIN QUALITY, WITH STATIC MESHESPreviously, I was using height-maps and simple primitives to create my prototype terrain.
This suited the purposes for level design, but for actually creating terrain that looked decent the result was poor.
The terrain didn't actually look like terrain, it looked like simple shapes with procedural noise applied.
Pictures: Block Mesh, Old Converted Terrain I researched extensively on procedural algorithms to remedy the terrain's quality.
However, I came to the simple conclusion that my block-mesh which I was converting from simply wasn't good enough.
I decided to assemble levels with a combination of height-maps and static rock like meshes.
The results ended up considerably more visually appealing.
Pictures: Static Meshes, Static Mesh OverdrawFor a while I thought of abandoning Unity's terrain system entirely, and only using the static meshes.
However my new static-mesh based terrain created a considerable amount of overdraw and wasted rendering.
Eventually, I plan on writing my own terrain for Desolus, as the current Unity terrain still has lots of issues.
I researched many alternatives, hoping I could abandon Unity terrain entirely.
However, I decided the best approach for now was to write a sophisticated tool to convert my static meshes into Unity terrain.
---
AUTOMATING TERRAIN CONVERSIONFor conversion I previously was using the
'Object2Terrain' C# script, which is a free editor script.
This is great for a free tool, however this has some problems:
-The script only supports one mesh, and the static mesh terrain is composed of many meshes.
-It autosizes your terrain to the bounds of the mesh, meaning terrains never have the same resolution.
-It operates off of raycasts, which aren't great for quality conversion
-If you need to set additional parameters for your terrain, you have to do this manually.
I'll go through how I fixed the major issues.
It Only Supports One Mesh: The default script determines the dimensions of converted terrain with the mesh's bounds.
By default, this does not include children meshes and therefore only supports a single mesh.
In order to support multiple meshes, you can
encapsulate the bounds of children meshes into a single bounds object.
Consistent Terrain Resolution:Unfortunately, Unity's terrains only support resolutions which are powers of two. (Ex. 256, 512, 1024).
The default script behavior would scale the terrain based off of the mesh bounds. However, resolution would always be a power of two.
This lead to an inconsistency in the quality of terrain, based on the difference between their resolution and size.
The solution to this problem was to fix the raycasting bounds based on powers of two, and set both the terrain's size and resolutions to the same value.
This can be determined with
logarithms and base shifting.Improving Raycast Quality: To convert from meshes to terrain, the script relies off of
raycasting.
This is an intuitive approach, however it creates precision errors which result in jaggedness of terrain, as you can see in the picture below.
A solution to improving raycast conversion quality is through
super sampling the raycasts.
By this, I simply mean make more raycasts than needed (such as a factor of 8x).
Afterwards, average adjacent raycasts together when creating the terrain's height map.
To further improve quality from converted terrain, I used an erosion simulation with
terrain toolkit.
Pictures: Raycasting Error, Super Sampled Raycasting w/ Smoothing---
TERRAIN RESULTSThis process creates drastically more appealing and natural looking terrain, which is actually of higher quality than the original block mesh.
Conversion from static meshes into terrain seems to be an ideal method in creating appealing results.
This was a major victory, as terrain looks considerably better and workflow is vastly improved.
---
REPLACING THE UNITY GRASSIn addition to improving my base terrain mesh, I also created a tool and shader for procedural grass.
The default Unity grass is expensive, ugly, and needs to be manually painted. Therefore I sought a replacement system.
I researched various ways to generate good looking grass, taking inspiration from games like Flower and Breath of the Wild.
Pictures: Grass from Breath of the Wild and FlowerIn my research, I came across this
Dx11 Grass Shader which I used as reference for writing the Desolus grass.
The Dx11 grass shader was an excellent start, as it's a high efficiency geometry shader which produces great results.
However, I had two problems with it:
-The workflow is relatively poor, as it requires manual painting of grass in an unintuitive way.
-I had to rewrite most of it to fit with the game's art style, lighting, and alternate dimension mechanic.
For both the Unity grass and this Dx11 grass shader, a
detail map is painted on the terrain, which determines where grass grows.
I wanted a procedural solution as I spent a considerable amount of time painting grass, which is a waste of effort.
My solution to this was writing a tool which generates a procedural quad mesh to render grass.
The mesh is generated by raycasting the terrain at fixed intervals, and sampling the
normal of the terrain's height to determine a valid position.
A position is valid if: the normal is below a certain angle, there's no architecture or other obstructions, the grass is above sea level, etc.
If the raycast returns a valid position, a procedural quad is placed with the grass shader. To save resources, the quad meshes are combined into chunks.
Picture: Debug view of Grass RaycastsAfter I finished with the procedural quad meshes, I went on to rewrite the grass shader to fit Desolus.
This involved rewriting with my own custom lighting and shaders, for a consistent art style.
The most complicated aspect was getting the alternate dimensions working with the grass shader, but that's a discussion for another day.
The Final Grass Results!The shader turned out quite well, and performs considerably better than Unity grass.
---
CONCLUSIONThe terrain system still has a few issues which I need to fix, such as level of detail, performance, and proper occlusion culling.
However for the time being I'm very happy with the results. I vastly improved my terrain creation workflow and quality.
---