Often in game engines is used an approach when grass type (geometry or texture type) is chosen based on the landscape type. For example on the road we don’t want any grass at all because they can’t grow there, but for meadow we want a lot of very dense grass. This can be achieved with grass masking, but often we need not only binary value about need we grass or not but some variations. Another example grass with different textures to make grass and landscape belong each other. For this case we also need grass masking texture with values which indicate the kind of grass. This technique is not a new and it has been widely used for a long time in industry, but often we can see intersection between grass geometry and landscape geometry (look at the images below) even when we implemented this technique. This may happen when grass masking texture is not big enough or when grass geometry is relatively big (for choosing flora type we use only central point of this geometry, but geometry may be big enough to overlap neighborhoods areas with different materials) or when we have landscape with very rapid environment type transition. This issue happens always but in one games this is not a big issue and in another may make the final picture unbalanced.
Here I try to explain how we can achieve this picture with relatively small performance overhead.
As always the main idea is very simple. To make grass and landscape belong each other what we need to do is tint grass with the landscape color in the bottom-up direction. There are different methods for doing this (I know at least three) but the common stuff in all of them is access a texture which represents a color of the ground under the grass. Means we have to prepare this specific texture before we start grass rendering.
Ok let’s imagine that we have this texture before grass drawing. What we need to do with it.
Look at the image here on the left I drew typical flora geometry (a quad) which consist of two triangles (front view). Red points represent bottom vertices of the flora, blue points up vertices. On the right is flora geometry (side view) with the different slope against the landscape. For each vertex of the grass geometry we need to add an additional attribute with represents tint position (in object space) and the blend factor for doing right tinting (in the simplest case for bottom vertices it will be 1.0f and for the up vertices 0.0f).
Now I shortly explain each of these three techniques:
- For each grass chunk you have to find landscape textures under it. If you landscape uses blend textures for correct blending different layer’s textures you have to do the same calculation of the final color in the grass pixels shader. Yes, this may be expensive task. So think twice before doing it.
- Render landscape and all needed for grass coloring stuff into the texture with camera looking top-down and with orthogonal projection. Then use this texture in the grass pixel shader. This may me less expensive on the CPU side, but may introduce some artifacts. (of course it very depends on the engine capabilities)
- Do grass rendering as the last part of the rendering. Make copy of the already filled back-buffer. Then use this back-buffer copy as a texture for coloring in the grass pixel shader.
I prefer the third method because of its simplicity and efficiency on both CPU and GPU sides. In the vertex shader we calculate clips space position of the tint position and in the pixels shader we just sample back buffer with these calculated coordinates then we blend grass color with this sampled color by the tint blend factor. It’s very simple and efficient. And we don't have any additional work on the CPU side except that we need to send into the pixel shader back-buffer copy.
Someone may ask why not just blend grass color with the back-buffer color with standard hardware blending. The answer is simple because it’s not right if you will try to look through the flora you will notice that we blend bottom part of the grass with incorrect color because it may be located far away from the bottom part of the grass itself.