Hey guys, I wrote an article on my personal blog describing some of the issues I have encountered with Unity’s implementation of terrains (or rather, heightmaps in general, as pointed out by one of the fair patrons of the IRC channel):
Heightmaps are outdated - Yes, they are the industry standard, but we can probably do better–I mean, no caves?
Splatmaps are ugly on cliffs - Ever tried texturing a sheer cliff using Unity’s terrain splatmaps? It isn’t the most sightly thing in the world…
Draw calls are ridiculous - Despite the fact that draw calls can sometimes be a misnomer when discussing measures of game performance, there’s still no excuse for the sheer number of draw calls used by Unity terrains–and I’m sure the mobile developers would empathize.
Documentation is sparse - The terrain documentation is very undetailed, especially when compared to other, more extensive parts of the docs.
I’m more or less asking for you guys’ opinions on the problems listed above, and I’m curious as to whether or not you have had some of the same problems.
(And if someone from Unity Technologies could offer an official comment on some of these issues, that would be absolutely wonderful, as I’m curious about UT’s stance on these issues.)
A nicely written piece about some of the common gripes with Unity terrain.
I do think, though that you have too easily given the impression of a “limit” or impossibility around things which are for the most part just not made as easy, or catered for as completely out of the box as other things in Unity.
I would have to agree that it would appear as if I have simply thrown Unity’s terrain engine aside after having so many issues with it. I just feel that some of these things (particularly the draw call and documentation issues, both of which being out of the designers’ reach) should have been fixed months ago, because workarounds–despite their creative nature–are indeed just workarounds, and simply by the fact that they are called ‘workarounds’ implies that, at some point, we will no longer have to find such creative solutions.
In other words, why haven’t these things been given attention yet?
(Though, I will say, thank you UT so very much for adding multicore rendering to Unity 3.5)
With all due respect, I get the feeling that you didn’t actually read the content of the article.
In the article, I linked to the triplanar shader, stating that it fixes the cliff skewing issue, but that’s really the most useful feature (not necessarily the fault of the person who wrote the shader). Also, I was only using four textures in that sample terrain, and I was at 59 draw calls, with the default shaders.
Finally, if you read closely in the section about documentation, I was referring to the scripting documentation. Yes, Unity’s terrain system is easy to master, but when you need to access data about the terrain itself in a script, you have to go through a plethora of difficult hoops (mostly due to lack of documentation) before figuring out what does what.
I recognize that there are bigger and better things that the terrain engine could do, but the point of the article was to outline problems with the system already in place–as a programmer, I find giant feature requests annoying, but bug reports to be helpful, and hence, that’s why I didn’t request any features.
(Arguably, the cave/overhang section was a feature request, but other games are capable of producing overhangs and caves using their implementation of heightmaps–why not Unity?)
The reason for the draw calls is that the terrain is simply not one giant mesh.
I’ve not looked into it, but I’d imagine Unity terrain is using something similar to chunked LOD. A method that allows you to have large visible areas of terrains without drawing all the polygons of the whole terrain.
That’s not to say it might not be somewhat outdated, chunked LOD has been around for many years, but as gpu’s get more powerful techniques can be superseded or if not kept up to date, appear limited. For example ROAM used to be all the age, but due to the overhead of working at the triangle level its simply too inefficient for todays gpu’s as all the work is cpu side (though as a method it may still have its uses).
I think chunked LOD is still a valid technique, though it may be limited by the settings in Unity, e.g. max heightmap dimensions and possibly gpu’s today being able to handle more polygons per mesh. For example in the stats you show it would appear on your machine you can have a single 65k polygon mesh with no problems, yet in chunked LOD the highest polygon count per chunk might be 2048 (which is determined by the number of chunks you divide your terrain into). So it might be possible to double this number, increasing the smallest chunk from NxN pixels on the heightmap to (N2)x(N2) thus decreasing number of chunks and therefore drawcalls needed.
However that might not be a good idea, as with most things gpu related its all about a careful balance of drawcalls vs polygon count per call vs performance/capabilities of gpu etc. Indeed in most cases for terrain to work you NEED it split into a good number of draw calls (or rather in this case VBO’s) in order to make it efficient for when you standing in the middle of the terrain and thus limit the amount of polygons being sent to the card.
I would also question your statement that ‘mesh terrains are better’ as obviously a naive implementation is not going to be. However I suspect in your part 2 you’re going to have to create some form of chunked LOD system to support this statement, thus simply recreating what Unity Terrain does, but with the advantage that you could tweak number of chunks etc.
As for your other points…
I’d agree about shaders and uv stretching and though both can be worked around its a shame Unity haven’t got round to incorporating some simple changes to the terrain system to support these. However it may well be doing so could only be acheived by breaking backwards compatibility, something they may wish to wait to do so until they have a complete terrain rewrite.
As for overhangs and caves, historically they have always been difficult to solve especially for use in a generalised system, either requiring substantial additional data and/or affecting performance. Not to mention having a knock on effect for stuff like collision detection which is no longer ‘simple’
Not sure why you’re complaining about splat maps they are pretty much the standard, if its difficult for you to understand that’s you’re problem, not a problem with the tech. Of course regarding the tech Unity feels a little outdated here, it should be possible to have more than 4 splats per terrain, but then again you have to consider that its probably to support the min spec supported gpu’s.
From what the Unity veterans told me in the IRC channel, chunked LOD is what the terrain engine uses, however it is not clear to me how it handles materials within these chunks. I hypothesize that this is where most of the draw-call-whoring arises from–four textures per chunk is one draw call (two if you’re not lightmapped yet) per texture, and the larger the terrain gets, the larger the number of chunks, and therefore, eight textures per chunk on a map composed of an arbitrary number of chunks would start to accumulate draw calls very quickly (and possibly texture memory gets wasted as well).
In my experiments, a LOD-chunked mesh terrain (with occlusion culling and view frustrum culling employed), combined so that each chunk mesh uses the same two-pass-shader material* can yield up to 90% fewer draw calls than the same terrain generated through the engine. I don’t have any examples to back this claim up, though I’ll have a sample scene ready within the coming month to be used as a guinea pig map for Part 2.
The two pass shader found on the wiki was used for my experiments. In-game, I will be using one that combines the functionality of the toon ramp shaders with the two pass shaders, because of the art style I am working within.
Yeah, and the triplanar workaround is gorgeous when used correctly–however, I never really thought about the notion of backwards compatibility–perhaps with splatmaps being the default for terrains that import incorrectly when triplanar projections are used, they could achieve a sense of backwards compatibility?
I can attest to this; problems with heightmaps are not exclusive to Unity and I really shouldn’t be picking at just Unity for such a problem.
The remark in the article about “being lost” in regards to splatmaps was written more or less because I was having a hard time writing a simplified definition of what a splatmap does, so that people who have little experience within game engines would understand what is being said. I understand completely what a splatmap does.
Imposing arbitrary limits because of hardware that developers might not even have in the target audience is silly. If the developers of a game don’t want to support old hardware, they shouldn’t be forced to.
I’m not sure I follow you on some of these points as they don’t make much sense from my previous knowledge of terrains, but as I said i’ve not had an opportunity to real get into Unity’s Terrain system, so what you say might be true.
I guess it may come down to the min spec support again, if as you say lightmaps require two drawcalls per chunk. Mix in support for normalmaps and the min specs might bite you again. Its a shame since (off the top of my head) I believe dedicated gpu’s can support up to 16 texture units (TU), you could feasibly have 7 unique textures per chunk, (7 diffuse maps, 7 normalmaps, 1 lightmap, 1 basemap = 16).
Actually I can see now dropping down to a lower number of TU and you quickly run out of textures (diffuse, normal, lightmap, basemap) and forced to use additional drawcalls. In which case apart from increasing the min spec i’m not sure there is anything you can do about it.
I’d quite believe you could make it more efficient, though 90% seems a bit optimistic, especially as for chunked LOD to work you need a decent number of viewable chunks and usually each chunk would represent at least a drawcall. Of course you could merge low LOD chunks to reduce the number but thats back to the chunks vs num polygons balancing issue. Anyway will be very interesting to see what you come up with in part 2.
Possibly, but it depends what other knock on effects adding support might have, to the asset, the program etc. For example it just occurred to me that when I wrote my own tri-planar shader I think I was up against the limit for ShaderModel 2.x instructions. If it needed to support any other terrain specific code it might push it into SM 3 and/or require further drawcalls/passes.
Of course tri-planar also requires far more texture fetches than normal, I forget my exact implementation, but it could be 3 reads for every pixel as opposed to 1 normally, since the result is a blend of the 3 planar axis pixel values. It may be that you can delay the texture reads and only read the exact number needed, but regardless tri-planar has a much higher overhead for the gpu, though one which is probably mitigated these days due to sheer power of the gpu.
Ah, sorry to have misunderstood your point.
True, but sometimes I think you’re forced into arbitrary limits in order to ensure something works.
Its an interesting conversation, because normally people just talk about ‘what they want’ in a new terrain system. However in answering you and I would assume yourself creating an improved terrain system it brings to the fore a lot of practical questions such as how to actually implement a new system whilst maintaining min drawcalls, high polygon counts, large number of diffuse textures etc. Some of which may not be easy to answer.
For example with vertex texture fetch you could make the terrain almost entirely on the gpu, but I’m pretty sure that would increase the min spec of the gpu. For which the simple answer is to have a terrain system with fallbacks, but then you’ve suddenly got an exploding code base to deal with
If I were to look into terrains again i’d probably take a look at geo-clipmaps. Even though its from circa 2004 I don’t think there has been any newer competing method for terrains since then? The biggest problem I see with these systems (and chunk LOD) is how to incorporate your overhangs/caves within the mesh, whilst retaining efficiency. Perhaps efficiency is less of a problem though, (esp if you increase min spec) since its been 7 years. Perhaps even a ‘naive’ implementation would work just as well as spending weeks trying to come up with a clever, efficient system?
Out of interest, this paper outlines some of the 'state of the art’, with some very nice images of terrain with overhangs, though i’m unsure how practical they are. The images do look lovely though
edit:
BTW have you played with the terrain ‘pixel error’ setting? I’d forgotten about that feature. It effectively would allow you to tailor the number of chunks/drawcalls being used, though obviously is a trade off against other aspects such as polygon count/performance.
If you want to achieve some visual quality, you need at least 6-8 textures per terrain. I dont understand, why everybody here is focused on 1995 level graphics. People, it is 2011, start to look around yourself, check features of other engines and wake up. Unity is really behind in the level of visual quality. Take your assets, use in other engine and you will be really surprised (as I was).
Agree. Other side is technical documentation about performance, working with terrain using code, etc. But this is problem of whole Unity, not only terrrain engine.
Agree. Heigtmaps are OK, you can use mesh rocks, like any modern game (skyrim). I only miss hole cutting tool (like CE or EE have). Usully people, who are not able to model decent rocks are crying, that they need voxel terrain. But they are forgetting, that they have to model rocks anyway using that voxel tool, so they will have crappy terrain anyway if they lack modelling skills.
I know. Splat information is stored in ARGB splat map, each channel is one texture. So each 4 textures mean one additional ARGB splat and so other pass.
I only commented that suggestion of keeping 4 textures, that nowdays it is quite ridiculous.
Whilst I would agree that keeping to 4 textures is not ideal, there are practical considerations to take into account as already mentioned. More so when you consider Unity supports a wide range of hardware. My point being on the face of it, most of the suggestions for improvements seem simple, especially when taken in isolation, its when you try to combine everything into a single engine component that things start to get tricky, pushing min-spec upwards or having more drawcalls, fallback code paths etc.
I guess after some consideration i’m beginning to understand why perhaps UT haven’t updated terrain previously
Well, every other engine has terrain system far more advanced and up to date. So no excuse for Unity, especially when Unity advertise itself as engine suitable for AAA visual quality and performance.
Sure, but i dont really think that with currect splat system terrain would be possible to get some huge number of splats with decent performance. The only way i see it is with completly new system like ID software did, 2 additional splat textures dont mean anything.
In case of Unity there is some specularity on, so ignore this difference. Anyway in case of Unity you can notice shadows artefacts on the mesh (left picture) + some other artefact near right window (right picture, probably other bug).
Visual difference is tremendous, just of out of box feautres of engine. Same assets, same textures, same color settings for the lightning, both deferred mode…Btw, render in 3ds max is very similar to that other engine I used for comparison, and this is how that asset really should like (correct colors, etc…). I really dont understand why is Unity messing visual quality so much.
In the course of drafting out the terrain “engine” (or rather, workflow, since it’s less of an engine and more of a creative process) I’m about to field-test, I wasn’t anticipating that Unity 3.5 would have a built-in LOD system. Before I continue using the LOD script I came up with on-the-fly a few months back, what is the general consensus on how good (or bad) the 3.5 beta terrain engine is? I ask mostly because I’d rather not deal with re-inventing the wheel.
90% is indeed very optimistic, but all things considered, a ratio of 2:59 (mesh terrain draw calls versus Unity terrain draw calls) confirms that mesh terrains use less than 4% of the draw calls that Unity’s built-in terrains do, disregarding any draw calls incurred by detail meshes, props, trees, and so forth.
I am currently on the road, so I can’t make any progress in Unity at this time to show my work, but here’s the basic inner workings of the draft terrain engine:
All terrain pieces, including sheer cliffs (which are typically separated into their own GameObjects) are divided down so that the entire terrain–depending on the size–is subdivided into “cells.” For example, a small terrain may be comprised of 3 cells by 3 cells, whereas larger terrains could potentially be up to 10 cells by 10 cells. This allows proper occlusion and frustrum culling to take place.
Each of the aforementioned “cells” has three levels of detail: LOD0, the most detailed variant, LOD1, a less detailed variant, and LOD2, the least detailed variant. Because there are certain points in gameplay where the player might be using a zoomed camera to view a piece of terrain that is at a lower level of detail, I am currently unsure as to how to tackle the issue of the player possibly noticing the lower detail chunks of terrain. Do you guys have suggestions?
Every terrain chunk will use the same material internally, but using clever UV mapping and vertex painting within the shader, thereby saving texture RAM. In the experiment shown within the article linked in the original post, the Unity terrain used 18MB of texture RAM, and the mesh terrain–because it used a single material throughout–used only 0.3MB, which is a substantial difference, suggesting that combining materials saves VRAM.
I am currently field-testing the efficiency of Unity’s Tree engine, though as it stands for now, I will be using Unity’s Trees–primarily because I don’t want to have to write a script that allows mesh trees to react properly to wind zones.
Using texture atlasing and mesh combining, all grass and detail meshes will derive from the same asset file and same material file. Unfortunately, this means that I either have to write an editor script allowing me to place these meshes procedurally, or I will have to manually place every single grass and detail mesh on the terrain (which I would really like to avoid doing).