LOD grass in RTS

hunguptodry 101 Feb 18, 2012 at 03:51

I am having performance problems when drawing lots of grass zoomed out in an RTS like tropico.
Here is some background …

1) The grass is already very low poly. Basically a blade of grass is 2 triangles (4 since it is dual-sided).
2) When fully zoomed out I believe I’m drawing 8-1000000 blades of grass.
3) The world is divided into square zones. 16x16=256 of them.
4) Static objects including grass is rendered in a single call to glDrawElements for each zone.
5) I use some simple math to determine if a particular zone is in view and thus drawn.
6) This works well when I’m zoomed in but performance drags when I’m zoomed out and
have to draw too many zones.
7) My grass is built up from individual blades into clumps and then multiple clumps into patches.

Here is an idea swimming in my head …

1) When zoomed in, we obviously draw the grass in its dense glory. That is draw all the blades.
2) When zoomed out, it is probably OK to draw the grass much more sparsely.
3) Currently, the idea is to have less blades per clump of grass.

To achieve this …

1) Sort the elements (blades of grass) so that we draw in the following way. See example below.
2) Start with blade1, clump1, patch 1 (1,1,1) then blade (2,1,1), (3,1,1),(4,1,1),
(5,1,1),(6,1,1),(1,2,1),(2,2,1),(3,2,1),(4,2,1),(1,3,1),(2,3,1) …
3) Then onto the next patch and so on.
4) Now for high LOD (zoomed in) we draw more elements in glDrawElements.
5) For low (LOD) we simply draw less elements

What do u guys think of this scheme?

13 Replies

Please log in or register to post a reply.

Reedbeta 167 Feb 18, 2012 at 04:38

You should try drawing the grass as alpha-tested billboards with a texture that contains several blades of grass, when the grass is far away. You’ll have far fewer polygons and it should perform much better.

hunguptodry 101 Feb 18, 2012 at 07:49

1) billboards may not work very well with my orbiting camera system (like tropico).
and procedurally generated grass.

2) would really like to avoid the transitioning artifacts when switching between
billboard and actual 3D when zooming in and out.

Stainless 151 Feb 18, 2012 at 21:36

Search google, I cannot remember the URL but a guy has published his code for a really, really, really good grass system.

It works by having multiple levels for each voxel.

1) Long range textured quad
2) Medium range single billboard
3) Short range multiple billboards
4) Close range full 3d

The use of multiple billboards instead of a single billboard makes the transition between medium and close range really smooth.

Wish I could point you straight at the code

Vilem_Otte 117 Feb 18, 2012 at 23:46

#Stainless - you meant Kevin Boulanger’s work? http://www.kevinboul….net/grass.html His work is good and pretty realistic, indeed - I’ve written implementation based on his paper in 2010 - my video is here
(post-recorded application, after presentation at GA 2010)

I also worked on another “new solution” last year (it is merely the same as the last one), that should be more realistic - mainly focused on including more types of plants (using maps), as the current implementation still suffers from being too artificial (1), more realistic animation (as the previous still sucks a bit) (2), and higher resolution meshes, and heavy optimizations (3). And most important making some editing tool for this-like stuff (which is work-in-progress since as editor for our own game engine).

Note. For actual understanding, you need to know that our engine is designed as open-world game engine, that uses rectangular cells similarly like Creation engine in Skyrim does.

(1) Seems like quite easy to solve, and it actually is - you add plant models to plant-slot in single cell, where the engine reserves you 8 (also possible 16, 32 or 64) possible slots for different plants. You probably have the idea now - we use separate bits in integer texture map as mask for plants distribution. Note that we actually use just 8 (due to performance). The plants are also scaled on Y axis, where the scale is defined as bilinearly interpolated value of the texture. Easy to code and bloody effective.

(2) Quite a challange, as this one is subjective. We actually use something new, that we call “wind maps” that are artist created (hopefully some (realtime) navier-stokes in future :P) and say in which direction (standart xyz vector) the wind flows for each cell. It’s cheap trick to know the direction of wind, but it looks pretty nice. Then, some simple vertex shader and harmonic functions come into place.

(3) In shown demonstration, the grass plates are in grid optimization scheme - which is still a little slower than currently working quad-tree. Though just a few percents in performance. It actually is a little faster (even with the more trickery added - like wind maps and more layers of plants). Even though I think that Kevin Boulanger’s great idea on how-to-LOD-that-grass is giving the largest boost to this tech.

I hope this can help a bit in implementation of good grass system (not that my one is good - it still needs a lot of work).

hunguptodry 101 Feb 19, 2012 at 01:27

Thanks for pointing out Kevin’s paper. His volume rendering idea looks quite promising.
I can render each patch of grass as a single textured cube. 5 small textures per patch.
It also seems reasonable to have similar patches share textures. These should look
decent when zoomed out. Thanks again, guys.

Stainless 151 Feb 19, 2012 at 09:36


Yes that’s the one.

Good luck with real time wind effects, I have been trying for years to write a physically based cloud generation system for planets. The maths involved in atmospheric physics is very time consuming and doing it in shaders requires a lot of texture swapping. Yuck.

I am wondering if the wind effects mean you cannot do any short cuts based on instancing?

The last time I played with a grass system I had all my cells organised as batches and was able to instance many of them.

Do you modify the verts based on the wind in the shader?

Vilem_Otte 117 Feb 19, 2012 at 13:16

Just for informatino - Right now I don’t have much time, but I’ll find an hour or two to quickly build small demo of this to show…

Vilem_Otte 117 Feb 19, 2012 at 21:02

Okay, so here it is:

Linux + Windows binary, I tested it just on AMD gpus (but it should look also on NVidia, if it supports GLSL version 330). Some extensions are needed (including ARB_draw_instanced of course). I just put it quickly together (dropped out LOD as I didn’t have time to generate textures for it, also windmap is just quickly made, along with grass blades map(s) + mesh). It’s far from perfect (well whole data were built in 1 hour or so + I had to think off some shader constants and actually put it together) - it is just proof-of-concept.

Feel free to try and/or ask about anything.

Note, it needs ODE libraries and OpenAL libraries (+ OpenGL and system libraries - WinAPI on Win32 and XLib ob Linux). You can grab needed ODE dll here - http://www.otte.cz/ode_single.dll or build it from source - http://sourceforge.n…s/opende/files/. OpenAL installer is here - http://connect.creat…al/default.aspx

Also forgot to say - you actually see windmap direction generated sine waves (without turbulence), the important is shader code in data/shaders/grass.glsl (it’s not commented, but I think you can easily figure out what is what).

Stainless 151 Feb 20, 2012 at 09:14

crashes on my XP laptop

Unhandled exception at 0x00000000 in msvc.exe: 0xC0000005: Access violation reading location 0x00000000.

it’s on the call to …

mainret = WinMain(
#endif  /* WPRFLAG */
                       StartupInfo.dwFlags & STARTF_USESHOWWINDOW
                        ? StartupInfo.wShowWindow
                        : SW_SHOWDEFAULT

Looks like my Nvidia card does not support some extensions

NVIDIA Corporation

Error: GL_ARB_shader_objects and GL_ARB_shading_language_100 not supported
Error: GL_ARB_tessellation_shader not supported
Error: GL_ARB_vertex_array_object not supported
Error: GL_ARB_framebuffer_object not supportedError: GL_ARB_draw_instanced not supported


I write shaders all the time on this machine, but never use the ARB extensions

Vilem_Otte 117 Feb 20, 2012 at 19:57

Huh… sounds strange that you don’t have ARB_shader_objects + ARB_shading_language (maybe just few procedures are missing), but ARB_draw_instanced is needed here (it was also known as EXT_draw_instanced), maybe installing new drivers would help this (ARB_vertex_array_object and ARB_framebuffer_object and ARB_tessellation_shader are not needed in this one - it just tests for them).

Stainless 151 Feb 21, 2012 at 09:32

The drivers are up to date as I do a lot of OpenGLES 2.0 code and the IT guy is paranoid about drivers being up to date.

This is why I hate PC development, I have a really rotten 2gig 64 bit desktop that I dropped a £15 graphic card into, and it runs on that. Though the machine is so slow it might as well be steam powered.

This dual core 32 bit laptop cannot run it because the graphics card doesn’t support some of the extensions.


Vilem_Otte 117 Feb 22, 2012 at 16:35

Btw. may I ask what GPU (+ configuration) do you have on notebook?

Stainless 151 Feb 23, 2012 at 09:27

NVidia Quadro NVS 135M