Monday, November 4, 2013

Tech Feature: Terrain textures

I have lastly completed the part of the terrain rendering that I spent most time researching and thinking about: texturing. This is a really big difficulty, with numerous techniques offered, every single getting its personal pros and cons.

I was looking for some thing that gave a lot of freedom for the artists, that was fast and that allowed that the exact same algorithm could be employed in both game and editor. The last point was especially essential given that we had much success with our WYSIWYG-editor for Amnesia, and we did not want terrain to break this by requiring some complicated creation procedure.

Even once I began working on the textures, I was unsure on the exact method to take. I had at least decided to use some kind of texture splatting as the base. Nevertheless there is a lot of methods to go about this, the two key directions becoming to either do it all in real-time or to rendering to cache textures in some manner.

Prior to doing any suitable work on the texturing algorithm I wanted to see how the texturing looked on some test terrain. In the image beneath I am basically project a tiling texture along the y-axis.


Although I had checked other games, I was not certain how excellent this the y-axis projection would appear. What I was worried of was that there would be a lot of stretching at slopes. It turned out that it was not that poor even though and the worst case appears anything like this:

While visible it was not as bad as I first believed it would be. Seeing this produced me more confident that I could project along the y-axis for all textures, some thing that permitted for the cached texture method. If I did all blending in real-time I would have been in a position to have a particular uv-mapping for slopes, but now that y-axis projection worked, this was no longer crucial. Even so, before I could commence on testing texture caching, I want to implement the blending.

The plain-vanilla way to do is, is to have an alpha texture for every single texture layer and then draw 1 texture layer soon after yet another. As an alternative of having several render passes, I wanted to do as considerably blending in a single draw contact. By making use of a an RGBA texture for the alpha I could do a maximum of four at the very same time. I first deemed this, but then I saw a paper by Martin Mittring from Crytek named "Sophisticated virtual texture subjects" exactly where an exciting approach was suggested. By using an RGB texture up to 8 textures could be blended, by letting every single corner of an rbg-cube be a texture. A difficulty with this method is that each texture can only be nicely blended with three other corners (textures), restricting artists a bit. See under how texture layers are connected (a rapid sketch by me):

Side note: Yes, it would be feasible to use an RGBA texture with this method and let the corners of a hyper cube represent all of the textures. This would allow each and every texture sort to have four textures it could blend with and a maximum of 16 texture layers. Even so, it would make life fairly difficult for artists when getting to think in 4D...

When implemented it looks like this (note he rgb texture in the upper appropriate corner):


Nevertheless, I got into a handful of problems with this method, that I first believed where graphics card problems, but later turned out to be my fault. In the course of this I switch to using a number of layers of RGBA textures instead, blending four textures at every pass. When I found that is was my personal error (doh!), I had already decided on employing cache textures (far more on that in a jiffy), which put significantly less concentrate on render speed of the blending. Also this method seemed nicer for artists. So I decided on a fairly much plain-vanilla strategy, meaning some operate in vain, but perhaps I can have use for it later on as an alternative.

Now for texture caching. This strategy generally functions as the mega texture strategy employing in Quake Wars and others. But rather of loading pieces of a gigantic texture at run-time, pieces of the gigantic texture is generated at run-time. To do this I have a a number of render textures in memory that are updated with the content depending on what is in view. Also, depending on the geometry LOD I use, I differ the texture resolution rendered to and make it cover a bigger region. So texture close to the view use big textures and far away have considerably reduce.

I very first thought had to do some special fading in between the levels and was a bit concerned on how to do this. Nonetheless, it turned out that this was taken care of the trilinear texture filtering really nicely (specially when creating mipmaps for each rendered texture). When implemented the algorithm proved extremely rapidly as the texture does not have to be updated quite typically and I got very high levels of detail in the terrain.

Side note: The algorithm is truly utilized in Halo Wars and is mentioned in a good lecture that you can see right here. Seeing this also made me confident that it was a viable approach.

The algorithm was not with out issues though, for instance the filtering amongst patches (various texture caches) designed seams, as can be observed beneath:

(click to enlarge, else it will not be seen)

The way I fixed this was merely to let every texture have a border that mimicked all of the surrounding textures. Even though the idea was straightforward, it was truly non-trivial to implement. For example, I started out with a 1 pixel border, but had to have a 8 pixel border for the highest 1024x1024 textures to be in a position to shrink it. Anyhow, I did get it functioning, generating it look like this:

(Once more, click image to see complete size!)

Next up was improving the blending. The normal blending for texture splatting can be quite boring and rather of just making use of a linear blend I wanted to spice it up a bit. I found a really nice strategy for this on Max McGuire's weblog, which you can see here. Essentially every material gets an alpha that determines how rapidly every portion of it fades. The algorithm I ended up with was a bit diverse from the 1 outlined in Max's weblog and looks like this:

final_alpha = clamp( (dissolve_alpha- (1. - blend_alpha ) / (dissolve_alpha * (1-fade_start), ., 1.)

Exactly where final_alpha is utilised to blend the colour for a texture and fade_commence determines at which alpha worth the fade begins (this allows the texture to disappear piece by piece). blend_alpha is gotten from the blend texture, and dissolve_alpha is in the texture, telling when parts of the texture fades out.

So rather of possessing to have blending like this:


It can look like this:


Now next step for me was to permit just not diffuse textures, but also standard mapping and specular. This was accomplished by simply rendering to much more render targets, so every single kind had a separate texture. This would not have been achievable to do if I had blended in genuine-time as I would have reached the regular limit of 16 texture limits quite fast. But now I rendered them separately, and when rendering the final actual-time texture I only need to use a texture for each kind (taken from the cache textures). Here is how all this combined appear:

You can see small version of each cache texture at the best.

Now for a final thing. Considering that the texture cached are not rendered very typically I can do quite a lot of heavy stuff in them. And one particular point I was certain we necessary was decals. What I did was basically to render a lot of quads to the textures which are blended with the existing texture. This can be utilised to add all sorts of added detail to map and almost call for no extra energy. Here is an example:


I am pretty happy with these features for now though there are some stuff to add. One particular factor I want to do is some kind of real-time conversion to DXT texture for the caches. This would save quite a lot of memory (4 - 8 occasions less would be used by terrain) and this would also speed up rendering. Another factor I want to investigate is to add shadows, SSAO and other effects when rendering each and every cache texture. Added to this are also some negative visual popping when levels are changed (this only takes place when zooming out a steep angle even though) that I almost certainly require to repair later on.

Now my subsequent job will be to add generated undergrowth! So count on to see some swaying grass in the next tech function!

No comments:

Post a Comment