Realistic grass w/ billboards

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
AW111
Posts: 82
Joined: Fri Jul 16, 2010 4:49 pm

Realistic grass w/ billboards

Post by AW111 »

The most common method of representing grass - textured planes crisscrossing each other at random positions - only looks realistic with huge numbers of planes, so that there aren't so many empty areas in between. Wouldn't it be more effective to use axial billboards, each representing a "clump" of grass, arranged in a regular grid pattern so that they fill the entire space without the need for colossal numbers of them - i.e., since they would always have the same width in the x axis (unlike thin planes), this method should greatly reduce the number needed to completely fill a given area. Or am I missing something?
I would need the grass clumps to be able to sway with the wind, which might create some difficulties. But the normal "planar" grass can only sway in a direction perpendicular to its angle, so that method also has a wind-related problem.
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

the problem with billboard for small thing like grass is when you look down from a higher place, for example, the billboard grass will tend to look very weird as if it's floating above the ground. i think the height of a character alone is enough to cause this problem unless your grass is super huge (which, will no longer call grass).
AW111
Posts: 82
Joined: Fri Jul 16, 2010 4:49 pm

Post by AW111 »

Virion wrote:the problem with billboard for small thing like grass is when you look down from a higher place, for example, the billboard grass will tend to look very weird as if it's floating above the ground. i think the height of a character alone is enough to cause this problem unless your grass is super huge (which, will no longer call grass).
But axial billboards - billboards which rotate only around one axis - should be no worse than the normal textured plane method, which also looks bad if you look straight downward. At least billboards should cover the entire area better than crossed planes.
(I would add that since I'm trying to simulate wild grass - not someone's mowed lawn - the grass will be up to several feet tall)
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

manually create the grass planes gives you more control over it. it doesn't necessarily crossed planes that aligned perpendicular with the ground, it could also be slanted or whatnot to make it look good even from above or any angle

look at the grass model that I did:
Image

i will post the wireframe here when I get home. it's manually adjusted to make it look good at any possible angle.

when it renders in irrlicht, it looks like this: http://www.youtube.com/watch?v=G80fToIoMrQ

not perfect, but much better than perpendicularly-crossed planes.
AW111
Posts: 82
Joined: Fri Jul 16, 2010 4:49 pm

Post by AW111 »

That grass model looks good, and has the type of dense coverage I'm trying to achieve ... but my software needs to place the polys at run-time since the terrain is procedurally generated. I suppose there must be a way to mathematically position the grass "planes" in a way which produces the same effect that you've created manually, but that sounds somewhat difficult.
VeeZed
Posts: 14
Joined: Wed Oct 27, 2010 8:04 pm
Location: Novosibirsk, Russia

Post by VeeZed »

First of all, I would like to say that it would be really interesting to look at this bush in wireframes. As I understand, there are just a several quads intersected at "random" angles and each of them represents the "line of leafs". Am I correct?

If it is so, the texture should contain a lot of alpha. And the alpha-check function is enabled, so that transparent areas do not fill z-buffer at all.

I think it's possible to generate such geometry procedurally. The main idea should be to put the "bottoms" at some predefined positions (may be with some variation), and the "tops" should be placed with random slide in the normal direction to the quad surface. Moreover, to achieve "curve" direction of the leafs, I would breakdown the quad into several horizontal stripes. Additionally, the generated geometry for the square block on terrain can be put into VBO, so that it can be rendered using a single call, but maintain the frustum test at the same time.

Therefore, the last question will be about "response to wind". When I spoke about VBO you might think that "it wouldn't be possible to remake VBO each frame, too heavy for the bus". But, if we could add a vertex shader, not pixel (!) just vertex one, that can displace the quads in a correct manner, it should be pretty awesome - nice animation plus effectiveness of static VBO. So the only question is whether such shader is possible (and how).

Actually, it's a pretty intriguing task and I will definitely need something like this for my own project (at some point). So I think I'm going to put this into the list of "tasks for me" and see what I can do. The only problem is to make it in irrLicht way :( I used to pure-opengl and in that terms I already see the possible solution. But now I decided to finally get into some framework, so I need to rebuild my approaches in 3D.
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

First of all, I would like to say that it would be really interesting to look at this bush in wireframes. As I understand, there are just a several quads intersected at "random" angles and each of them represents the "line of leafs". Am I correct?
true

the wireframe
Image

in-game render
Image
VeeZed
Posts: 14
Joined: Wed Oct 27, 2010 8:04 pm
Location: Novosibirsk, Russia

Post by VeeZed »

Looks like I've made the initial implementation of my "grass generator".

*** Implementation ***

The basic idea behind the scene is the following (just like I said in my previous post):

0. Create the initial texture that contains several "leafs" in it. The more leafs are inside the texture, the more weird it will look (but take less time to render). Leafs can be "green" or, actually, you can make them "white" (see 1.1).

1. Create random geometry of the "grass block". Make each "grass poly" a bit curve, so that it doesn't look too weird (i.e. like a narrow vertical poly). The code can produce any amount of "vertical steps", but it appears that even 2 or 3 steps are enough to get a good result. Each "grass block" is a STATIC geometry, so we can put it into a mesh and let irrlicht to store it as a VBO.

1.1. Bear in mind that you shouldn't stick only to "rotation" of the poly. Make each "grass poly" different in height (may be width too). Also, you can put some randomness into vertex colors, so each "poly" will be of a different color. I used green leaf and adjust green component from 0.5 to 1. It costs you nothing, but makes everything look better.

2. Repeat geometry creation for each block of terrain that you would like to cover. Since the "grass block" doesn't clipped exactly at some box, this will lead to uniform fill of the terrain. In my test app, I covered all terrain with the grass.

3. In my example, the overall amount of triangles created by "grass generator" is pretty big (about 1 million). Therefore, it will not be great to show all of them at once. However, there is no need to do this actually. Only nearby "leafs" will be more or less visible to the viewer. Therefore, you can add a distance check into the render method, and skip any "grass block" that is too far from the camera.

4. At this point, the main issue about the "disappearing" arises. Since we want to use VBO, the render method cannot setup per-poly alpha to make it fade out softly when the camera moves away. But, thanks to the good old vertex shaders, we can control it right within the GPU. Always remember, that even if you put some mesh into a VBO, you can still "control the geometry" without rewriting it from CPU. Especially if your action is a "procedural", i.e. it can be described just by several lines of code. So, we are simply adding vertex shader that calculates the distance between the "leaf poly" and camera (you can check that this calculation has very little effect on the FPS), and apply linear (or inverse linear) fading to the alpha. Everything becomes very smooth after that.

5. To complete our mission, we would like to add some "wind effect" to the our grass. This can be done within vertex shader we already have. We send some small "displacement" vector from the application to the shader and apply it to the geometry. We don't want the whole "leaf" to be affected, so we multiply the displacement vector by some value within the "leaf poly". This value should be 0.0f at the bottom and 1.0f at the top. We could use some vertex color component to do this (and substitute it with 1.0f in shader), but actually, we don't need it. We already have texture coordinates and vertical one perfectly suits for our needs.

5.1. If we apply the same displacement vector to "all grass in the world", it will not be totally cool. So, to make it a bit more nice, I marked each "grass block" with a random number [0..9]. And there are 10 displacement vectors calculated. All we need to do is to send correct vector to the particular "grass block". Of course, the grass within the same block will still act the same, but it isn't so bad, because we have some intersections between grass blocks (see 2).

*** Problems ***

And now lets talk a bit about the problems. First of all, this method requires huge amount of GPU memory (1 million triangles means that there are 3 million vertexes, and each has its own coordinates, texture coordinates, vertex color,...).

Actually, there is a way to make it better - create a pool of "grass blocks" and use it repeatedly. It seems that even a pool of 50 blocks will be enough to show only different ones at any particular moment. The only thing to solve is a "putting the geometry to the terrain". In the current implementation, "grass polys" are generated exactly at the height of the terrain, making them appear at the right place. "Standard grass block" will not fit to this well (unless some good interpolation is used). I'm going to think about this, may be there is a way to do this.

Of course, there are more things to be polished, like "wind movement" and "leafs near the camera" (that's a bit ugly, but I'm not an artist. May be good texture fix it somehow).

One more thing. To make it I had to do a small "hack" (low-level D3D call to setup the blending), so it works in DirectX only. The same "hack" can be made for OpenGL too (it's even easier), but anyway, this ruins the cross-platform compatibility. Please refer to this topic for the details:

http://irrlicht.sourceforge.net/phpBB2/ ... a703e20a38

*** Showtime ***

OK. I think everyone already fell asleep, so I'm going to show several screenshots:

"How does it look like?"

Image

"Feel the difference"
Image
Image

Of course, it's better to download the binaries and see the animation for yourself:
http://dl.dropbox.com/u/9070955/IrrLich ... tation.zip

Use Arrow keys to hover, hold Right mouse button to rotate camera, and wheel to zoom.

PS: I cannot provide the source code for this right now, since I played within my own test-application. Of course, the grass code is encapsulated within several classes, but currently they are using several other classes from my application. I'm going to extract the grass generator, clean it up and provide here (may be it would be interesing for someone).
Last edited by VeeZed on Sun Oct 31, 2010 10:12 pm, edited 1 time in total.
VeeZed
Posts: 14
Joined: Wed Oct 27, 2010 8:04 pm
Location: Novosibirsk, Russia

Post by VeeZed »

Almost forgot! It will be really appreciated if you provide your FPS results for grass/no-grass render.

My poor working laptop (with an integrated ATI RADEON XPRESS 1100) shows 42/68 FPS, but I'm pretty sure that more or less good hardware will have much-much better results.

OK. I made one more test on GeForce GTS 250 (not a hi-end card too). The results are 120/200 FPS. Therefore, I'm sure that I can add more (or even much more) grass to make it look better near the camera.

PS: and don't follow the tough guys. They are doing their own business :)
ent1ty
Competition winner
Posts: 1106
Joined: Sun Nov 08, 2009 11:09 am

Post by ent1ty »

how's this :D

Image

It's taken on my rather sucky laptop with ATI mobility radeon 5470. As you can see, also includes per pixel spot light shader for up to 8 lights 8)
And still having 117 FPS :P

EDIT: here is a screen with better ambient lighting... so you can actually see the grass :)

Image
irrRenderer 1.0
Height2Normal v. 2.1 - convert height maps to normal maps

Step back! I have a void pointer, and I'm not afraid to use it!
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

mine only has less than 10 chunks of grasses in the scene so its not really fair to compare it with yours. i think instead of generating just 1 piece of grass like what you shown in the screeny, what about if you use the same method to procedurally place manually-made grass models around the terrain? i think it's still possible to apply wind effect to it using maybe vertex shader.
VeeZed
Posts: 14
Joined: Wed Oct 27, 2010 8:04 pm
Location: Novosibirsk, Russia

Post by VeeZed »

ent1ty wrote: how's this :D
It's taken on my rather sucky laptop with ATI mobility radeon 5470. As you can see, also includes per pixel spot light shader for up to 8 lights 8)
And still having 117 FPS :P
This looks pretty good :) Please bear in mind that 5470 is 4 years newer than mine, so it would be interesting to compare the results on the same app (i.e. your chipset is 5 times quicker than mine in terms of fillrate). So could you send me yours, or use mine? :)
VeeZed
Posts: 14
Joined: Wed Oct 27, 2010 8:04 pm
Location: Novosibirsk, Russia

Post by VeeZed »

Virion wrote:mine only has less than 10 chunks of grasses in the scene so its not really fair to compare it with yours. i think instead of generating just 1 piece of grass like what you shown in the screeny, what about if you use the same method to procedurally place manually-made grass models around the terrain? i think it's still possible to apply wind effect to it using maybe vertex shader.
Yes, actually, it is quite possible. I.e. the only thing to be changed is a generation place (i.e. put them all around the same point, not everywhere).

Could you lend me your texture for the grass, so I can play with it in the tests?
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

VeeZed wrote:
Virion wrote:mine only has less than 10 chunks of grasses in the scene so its not really fair to compare it with yours. i think instead of generating just 1 piece of grass like what you shown in the screeny, what about if you use the same method to procedurally place manually-made grass models around the terrain? i think it's still possible to apply wind effect to it using maybe vertex shader.
Yes, actually, it is quite possible. I.e. the only thing to be changed is a generation place (i.e. put them all around the same point, not everywhere).

Could you lend me your texture for the grass, so I can play with it in the tests?
check pm
ent1ty
Competition winner
Posts: 1106
Joined: Sun Nov 08, 2009 11:09 am

Post by ent1ty »

VeeZed wrote:This looks pretty good :) Please bear in mind that 5470 is 4 years newer than mine, so it would be interesting to compare the results on the same app (i.e. your chipset is 5 times quicker than mine in terms of fillrate). So could you send me yours, or use mine? :)
Ok, checked yours. Runs on 130 fps.

However, mine runs on 360 fps when i switch to default irrlicht lighting :lol:

But, yes, your map is a lot bigger

And you also have some AI and animated characters there.

So it's hard to tell. Mine looks a lot nicer though :P Also, your grass animates in a weird way. :)
irrRenderer 1.0
Height2Normal v. 2.1 - convert height maps to normal maps

Step back! I have a void pointer, and I'm not afraid to use it!
Post Reply