grass shadows

Started by
38 comments, last by Viny 17 years, 5 months ago
Quote:once again thx for all ur help.. been reading ur report a bit and this is what ive come up with for the geometry...

got diffuse lighting, ambient based on height, and inter shadows with planar shadowsmasks

any further suggestions for improvement?


Sorry to be long to answer, I was out of town. I can give you some comments on your image (actually, it reminds me the beginning, when I started working on it ;-) ).

First, nice job, the blades of grass have nice shapes and intersections with neighbor blades are not visible, or you found a way to avoid them.

The ambient occlusion range should be reduced a bit I think, it is too visible. You know that the more subtle the effects are, the better they look. I see that you also modulate the color of each blade randomly, that is good but here it looks a bit unnatural because you gradually go from green to brown. Here is a proposition: choose a random number in [0,1), if this number is less than 0.05 (or another threshold), use a yellowish color for the blade, otherwise choose a random color from medium green to dark green. I got the best results using this algorithm, after having observed real grass.

As said zedzeek, you should enable multisampling and GL_SAMPLE_ALPHA_TO_COVERAGE, so you will get antialiased alpha testing (and no need to sort the blades from back to front, contrary to blending).

For the shadows, unfortunalety I do not see them at all. Did you forget to render them or is it just me ? And can you explain how work you planar shadow masks ?

Also, you are reading my research report (thanks by the way), but be careful. It is a version that I wrote for Siggraph in June, so it is not totally updated. After this report, I increased a lot the quality of the rendering, managed non flat terrains and improved a lot the density management. Unfortunately I cannot give details for the moment, the research paper is submitted in a research journal, and I have to wait for the answer before giving details.

For the image you shown, what graphics card do you use ? I see that you have 32 fps, I think it could be a bit more (if you work on a GeForce 7 class card). Do you use vertex buffer objects and multi draw arrays ? Do you use triangle strips (or quad strips) ?

Do you use textures for your grass blades ? They do not really appear, is it due to mipmapping. If you need to see the texture more, you can bias the level of mipmap in the fragment shaders (or using the fixed pipeline).

You can add an approximation of translucency, this gives a very nice effect when the sun is in front of you. You can add to the rendered color a component that is really green and depends on the angle with the sun.

After these small things, I do not think that you need a lot more to continue on other parts of the levels of detail management.

I hope it helped you.
Advertisement
Viny thats a very nice image on the last page (didnt see it before) beautiful
personally i believe yould be better off ditching multidrawarrays + just render all blades in a patch in one call ( with GL_TRIANGLES or GL_QUADS )
i tried multidrawarrays before + it was slower
Quote:personally i believe yould be better off ditching multidrawarrays + just render all blades in a patch in one call ( with GL_TRIANGLES or GL_QUADS )
i tried multidrawarrays before + it was slower


Actually, I am not sure, I should try.

My vertex shaders are quite heavy for the geometric grass blades, so I wanted to reduce the amount of work by using quad strips (or tri strips). However, it was too slow since there was a draw call per grass blade. I tried to put each grass blade of the base patch in a display list, and call every display list from another display list. Actually, using multi draw array, I multiplied the rendering speed by about 5 (and since there were other stuff displayed at the same time, I think that the speed-up was even more).

I have 8 quads per blade (so 10 different vertices). Using quad strips, the vertex shader should be called only 10 times (since strips are optimized this way). If I use triangles, there will be 8 triangles, so 24 vertices to process, and thus more than twice the work for the shaders. It will not be twice slower since there is a vertex cache in the GPU. For quads, 16 vertices have to be processed.

Maybe you are right, it could be faster, I should test it. However, my current bottleneck is at the slices rendering level for grass at intermediate distance from the viewer, so the framerate will be only slightly affected. If geometric grass rendering is faster, I could push the threshold between the levels of detail farther from the camera. It could be nice.
here my version from a few months ago

with tris or quads (personally i favour quads due to them looking better in wireframe)
the same number of vertices are gonna be processed as a strip
the reduction with strips is in the number of indices.

also above the intermediate distance grass, what i do is instead of rendering 7quads like up close i just have the single quad, it works surprisingly well even with the animation its hard to see a patch changeover from intermediate to close distance LOD.

is your grass animated btw? (ive found this my major bottleneck though ive greatly improved this now)
man... i rly like u ;)... thx again

Quote:Original post by Viny
Quote:once again thx for all ur help.. been reading ur report a bit and this is what ive come up with for the geometry...

got diffuse lighting, ambient based on height, and inter shadows with planar shadowsmasks

any further suggestions for improvement?


Sorry to be long to answer, I was out of town. I can give you some comments on your image (actually, it reminds me the beginning, when I started working on it ;-) ).

First, nice job, the blades of grass have nice shapes and intersections with neighbor blades are not visible, or you found a way to avoid them.

The ambient occlusion range should be reduced a bit I think, it is too visible. You know that the more subtle the effects are, the better they look. I see that you also modulate the color of each blade randomly, that is good but here it looks a bit unnatural because you gradually go from green to brown. Here is a proposition: choose a random number in [0,1), if this number is less than 0.05 (or another threshold), use a yellowish color for the blade, otherwise choose a random color from medium green to dark green. I got the best results using this algorithm, after having observed real grass.



sounds like a good idea.. will do

Quote:
As said zedzeek, you should enable multisampling and GL_SAMPLE_ALPHA_TO_COVERAGE, so you will get antialiased alpha testing (and no need to sort the blades from back to front, contrary to blending).


done

Quote:
For the shadows, unfortunalety I do not see them at all. Did you forget to render them or is it just me ? And can you explain how work you planar shadow masks ?


yea it doesnt work very well.. im still trying to figure out how to do this... i could use ur cylinder way but that only seems harder... im having problems with how to calculate the intersection with the shadow mask...

basicly i simple repeat the shadowmask over the patch.. like slices.. i put em 0.5 in fron of each blade and the cast a ray to it to get the tex coords..

here is a better pic showing the shadows... since im only using the sun as light source this should be simplier and faster calc than using a cylinder.. i think

Image Hosted by ImageShack.us

Quote:
Also, you are reading my research report (thanks by the way), but be careful. It is a version that I wrote for Siggraph in June, so it is not totally updated. After this report, I increased a lot the quality of the rendering, managed non flat terrains and improved a lot the density management. Unfortunately I cannot give details for the moment, the research paper is submitted in a research journal, and I have to wait for the answer before giving details.


ill be waiting

Quote:
For the image you shown, what graphics card do you use ? I see that you have 32 fps, I think it could be a bit more (if you work on a GeForce 7 class card). Do you use vertex buffer objects and multi draw arrays ? Do you use triangle strips (or quad strips) ?


yea i might not be using the best rendering method... as i said i cant use VBO cuzz for some strange reason my comp crashes... im using triangle strips in a displaylist... i dont even use degenerates... i start a new strip for each triangle... so what do u recommend?

Quote:
Do you use textures for your grass blades ? They do not really appear, is it due to mipmapping. If you need to see the texture more, you can bias the level of mipmap in the fragment shaders (or using the fixed pipeline).


well im using the texture that was in ur report... but im mixing it with the color green-yellow like mix(texcolor, grasscolor, 0.5). and yea mipmaping might also be a factor

Quote:
You can add an approximation of translucency, this gives a very nice effect when the sun is in front of you. You can add to the rendered color a component that is really green and depends on the angle with the sun.


i dont rly understand.. could u explain this a bit more in detail?

Quote:
After these small things, I do not think that you need a lot more to continue on other parts of the levels of detail management.


yea thx to u..

Quote:
I hope it helped you.


yeap


do u have any ideas how it would be possible to animate the grass?

and in ur demo how many grass blades do u have per 1x1... i have to use 300-600 blades (i think its 600 in the pic) to make it look dense... that means that the pic above has... 153600 blades

[Edited by - Dragon_Strike on November 26, 2006 4:21:36 AM]
Quote:Original post by zedzeek
the same number of vertices are gonna be processed as a strip
the reduction with strips is in the number of indices.


Indices ? Why do you use them ? Each of your index is used once, so just submit the array of vertices in the order you use the vertices and call glDrawArrays() (or glMultiDrawArrays()) rather glDrawElements() (if you use OpenGL).

And I really think that using quad strips rather than quads would reduce the work for the vertex shader (10 vertices to process for a strip of 4 quads rather that 16 with quads, or 24 with triangles). I know there is the vertex cache, but when you can give hints to the driver for optimizations, it is better to use them.

Quote:also above the intermediate distance grass, what i do is instead of rendering 7quads like up close i just have the single quad, it works surprisingly well even with the animation its hard to see a patch changeover from intermediate to close distance LOD.


It is good to know that it works well. I am just curious to know at what distance from the camera you switch from a level to another one because, even with my volume rendering approach, I can still distinguish the bending of grass blades.

Quote:is your grass animated btw? (ive found this my major bottleneck though ive greatly improved this now)


My grass is animated. Since my research topic was grass rendering and not animation, I did not work on it for a long time. Some people already worked on wind simulation for grass, and I just needed to show that it was working with my method. For each corner of the grass patches, I give a "wind vector" that allows me to skew the slices to distort the grass blades. For geometric grass, I just mimic the distortion of the patches (by adding a vector per vertex which is the wind vector multiplied by the vertex height relative to the blade height), and the transition between the LODs is perfect.

I have seen on your image that the grass bade polygons are camera-aligned. Is it really the case ? If yes, what kind of method do you use ?
Quote:Original post by Dragon_Strike
man... i rly like u ;)... thx again


I really appreciate. [smile]

Quote:yea it doesnt work very well.. im still trying to figure out how to do this... i could use ur cylinder way but that only seems harder... im having problems with how to calculate the intersection with the shadow mask...


I think that you would have more accurate results with the cylinder and it is easy and cheap to compute. I guessed you looked on the video on my website, it shows the results with a light rotating around the scene. I do not know if it would work well with your method.

First, transform the light vector in the space of the grass blade (with Y being the vertical axis in my case). A point (x,y,z) on the ray going from the current vertex you are processing (Vx,Vy,Vz) in the direction (Rx,Ry,Rz) can be expressed like this:

x = Vx + t.Rx     (1)y = Vy + t.Ry     (2)z = Vz + t.Rz     (3)


where t >= 0 is unknown.

Each point (x,y,z) on a vertical cylinder of radius R can be expressed like this:

x^2 + z^2 = R^2   (4)


Just substitute x and z from equation (4) by the equations (1) and (3). Solve to get t, with the condition that t >= 0. Then, use the resulting t in equations (1), (2) and (3) to get the intersection point that you convert in texture coordinates. Clamp the T coordinate in [0,1]. Fill the bottom row of your shadow mask with black and the top row with white in a preprocess.

Solving the equations give a really simple analytic form that is fast to evaluate in the GPU, since parts of the equations can be vectorized.

Quote:
basicly i simple repeat the shadowmask over the patch.. like slices.. i put em 0.5 in fron of each blade and the cast a ray to it to get the tex coords..


How do you choose the orientation of the slice ? If you use constant orientation, that means you need several slices, so it looks expensive to choose the one you need, and you will have distortions when far from the center of teh shadow mask. If you rotate the slice depending on the light direction, you cannot really get the shadow effect since the slice has to be the same along a blade (and so, for several vertices).

Quote:here is a better pic showing the shadows... since im only using the sun as light source this should be simplier and faster calc than using a cylinder.. i think


I am using the cylinder FOR the lighting from the sun (diffuse term). I manage shadowing from the environment (ambient term) using ambient occlusion.

Quote:
Quote:
Also, you are reading my research report (thanks by the way), but be careful. It is a version that I wrote for Siggraph in June, so it is not totally updated. After this report, I increased a lot the quality of the rendering, managed non flat terrains and improved a lot the density management. Unfortunately I cannot give details for the moment, the research paper is submitted in a research journal, and I have to wait for the answer before giving details.


ill be waiting


I should get the answer for the paper in late December or in January. After, it should be available online if it is accepted.

Quote:yea i might not be using the best rendering method... as i said i cant use VBO cuzz for some strange reason my comp crashes... im using triangle strips in a displaylist... i dont even use degenerates... i start a new strip for each triangle... so what do u recommend?


It is really too bad for the vertex buffer objects, it really accelerate the rendering (more than twice). But I do not know anyone that have VBOs crashing. I think you should really deeply check your code for a potential bug. It the crash happens when you call a rendering function, the problem comes probably from the data pointers (like NULL or arrays that are too short, the latter being difficult to debug but it happened to me, also check that the sizes you give are in number of vertices, float numbers or bytes, VBOs allocation being in number of bytes).

I do not use degenerate triangles, I use multi draw arrays. Since the rasterized primitive has to be restarted for each grass blade, glDrawArrays() should be called for each grass blades. By using multi draw arrays, I have a single draw call for an entire grass patch of about 3000 grass blades, and made the rendering speed multiplied by 5. This works with regular vertex arrays and for VBOs (but the speed up is really important with the VBOs).

Do not use indices, they are not really useful since each vertex is used once when rendering quad strips for grass blades.

Quote:well im using the texture that was in ur report... but im mixing it with the color green-yellow like mix(texcolor, grasscolor, 0.5). and yea mipmaping might also be a factor


That explains many things. You are making the texture "half visible" with your mixing method. I advise you to multiply the texture instead. Multiply the texture color by (1,1,1) to get the original color, about (1,1.1,1) for a more greenish color, (1,1,0.8) for a more yellowish color, etc. The values I gave you are arbitrary, use the ones you want, but keep in mind they have to be close to 1 to stay realistic.

I have seen on your picture that you change the color per vertex. The gradients that appear look a bit unrealistic. I have seen from observation of real grass that the color should be defined per blade rather than per vertex. Just choose a color randomly (see previous paragraph) and attributer the same color to each vertex.

Quote:
i dont rly understand.. could u explain this a bit more in detail?


Translucency is a bit expensive to compute. So I use a non-physically based approximation that gives convincing results. It is a slightly visible low-frequency effect but scenes look more realistic.

I use the diffuse term of the Phong BRDF to compute the reflected light:
materialColor * max(N . L, 0)

N is the normal of the blade on the side you are looking (I use two-sided lighting), L is the light direction. For transmitted light, I add the following component:
materialColor * (0.8,1.2,0.8) * max(-N . L, 0)

That means I am using a kind of Phong BRDF for the other side of the blade, and I multiply the value by (0.8,1.2,0.8) (you can tweak these values) to make it look more greenish.

When light is behind the viewer, the grass blades look blueish (due to ambient lighting particularly) and yellowish (due to the sun). When light is in front of the viewer, the grass blades look more greenish, which is the desired behavior.

Quote:do u have any ideas how it would be possible to animate the grass?


You can look at my previous post.

Quote:
and in ur demo how many grass blades do u have per 1x1... i have to use 300-600 blades (i think its 600 in the pic) to make it look dense... that means that the pic above has... 153600 blades


For the screenshot I gave, I use about 15,000 grass blades per square meter, with about 8 cm tall grass blades.
Quote:Indices ? Why do you use them ? Each of your index is used once, so just submit the array of vertices in the order you use the vertices and call glDrawArrays() (or glMultiDrawArrays()) rather glDrawElements() (if you use OpenGL).

ive found a lot of things that by common sense should be quicker in fact aint, ie the most common method in drivers is also usually the quickest (thus u should always benchmark, persoanlly i believe drawing the whole patch in one go with DrawRangeElements(..) will be the quickest method)

Quote:
And I really think that using quad strips rather than quads would reduce the work for the vertex shader (10 vertices to process for a strip of 4 quads rather that 16 with quads, or 24 with triangles). I know there is the vertex cache, but when you can give hints to the driver for optimizations, it is better to use them.

with strips theres the same number of vertice processed
eg a quad of indices 0,1,2,3 + then 4,5,2,3, will look up 2+3 from its cache ie it doesnt do the recalculation, ( with graphics cards the cache is ~20 of the most recent vertices ) thus in effect with quads or quad_strips there exactly the same number of vertices processed


Quote:It is good to know that it works well. I am just curious to know at what distance from the camera you switch from a level to another one because, even with my volume rendering approach, I can still distinguish the bending of grass blades

sorry i forget its been a while since i looked at it (from memory ~20% of blades are in the highest res range)

Quote:I have seen on your image that the grass bade polygons are camera-aligned. Is it really the case ? If yes, what kind of method do you use ?

yes since the grass is animated + needs to be recreated each frame i might as well billboard them ( im not to sure how, i can look it up if u wish) i think im prolly just using the initial up vector + the vert to camera_view_direction as 2 axises ( + the crossproduct for the side direction vector)
billboarding doesnt look as good as fixed blades but i find u can make do with 2-3x as less blades to give it a similar 'full grass field' effect (esp if the animation is the bottleneck then halving the number of blades helps greatly)
if youre running on a supercomputer like cell i wouldnt worry about billboarding just chuck the whole thing onto 1/2 SPE's that are lying around doing nothing
Hi Viny,

Many thanks for sharing your excellent grass research. Your results speak for themselves!

I have a couple of questions related to converting the grass methods to work for non-flat terrain. Thus far I haven't found much documentation to what you needed to change or compromise to get the grass to work on non-flat surfaces. So, if there is paper describing that transition could you point me to it?

The specific questions that come to mind are:

1. How does the non-flat terrain affect your shadow methods?
2. How does the non-flat terrain affect the volume rendering technique?
3. Are there any limitations to your non-flat implementation, such as the terrain being represented by a height map.

Thanks again and congratulations on such a fine (no pun intended) rendering! ;)

Eugene
Quote:Original post by EugeneFoss
I have a couple of questions related to converting the grass methods to work for non-flat terrain. Thus far I haven't found much documentation to what you needed to change or compromise to get the grass to work on non-flat surfaces. So, if there is paper describing that transition could you point me to it?

Unfortunately, I cannot give much information about that part. I did some work on it, and now it works well (you have seen the screenshots). The reason is, I am a researcher in a university. I submitted a research paper in a journal, and I am waiting for the answer. If the answer is positive, the paper will be available and all information regarding the management of non-flat terrains (just look at my website to stay informed). I think I should get the answer in January.
Quote:1. How does the non-flat terrain affect your shadow methods?
2. How does the non-flat terrain affect the volume rendering technique?

The non-flat terrains affect these two parts the same way: I have to change the coordinate frame I am using when doing the lighting computations. The slices have also to be distorted to follow the terrain.
Quote:3. Are there any limitations to your non-flat implementation, such as the terrain being represented by a height map.

Since I am rendering grass using rectangular patches, I am managing only heighmaps. It makes the implementation quite easy and efficient. Additionally, I do not think an approach different from a heightmap would be useful. If you want to create arbitrary shaped patches of grass, just use a locally defined rectangular grid of patches with a heightmap, and define a density map to create the shape of the grassy region.

This topic is closed to new replies.

Advertisement