grass shadows

Started by
38 comments, last by Viny 17 years, 4 months ago
correcting a couple of errors here
A/ use billboards for the grass
B/ with shadowmaps this will give wrong results thus u have to have billboards for the lights viewpoint as well
C/ use GL_SAMPLE_ALPHA_TO_COVERAGE for the best quality looking grass
D/ pesonally im of the opionion the best results (quality vs speed) are grass recieves shadow but doesnt cast them
Advertisement
thx for the help.. ill try out some of the things suggested...

anyways.. u guys know any good gras textures/sprites i can use for billboards? ive tried doin my own in phosohop but it snot rly satisfying...
havent read the whole post but gpu gems 2 has great grass shadow trick in first article. however its to cast shadows onto the grass. you take 3 points on the billboard left middle right and see if they ar within the shadows of other objects, then you see of the 3 points how many are in shadow and then adjust accordingly this does a nice soft shadow from surrounding objects might help some. The university of central florida has http://www.irisa.fr/siames/GENS/kboulang/publications/grassSiggraph2006ppt.pdf

thats a pretty good algorithm and i expect to see it in upcoming football games as they said ea supported them with it
taking pictures of grass works fine. Then modify them with photoshop.
The problem with the GPU gem article is that it's for static lights else you have to recompute them every time the light changes. When you a SPU left you might be able to do this but else .. :)

This PDF looks indeed very nice but I wonder how many triangles you have to draw to make a normal piece of terrain look realistic. A few 100K I presume. And vertex and pixel shaders are not cheap either I think (with wind movement and heightmaps that is it).

Regards,
Kenzo
Quote:Original post by yoshscout
havent read the whole post but gpu gems 2 has great grass shadow trick in first article. however its to cast shadows onto the grass. you take 3 points on the billboard left middle right and see if they ar within the shadows of other objects, then you see of the 3 points how many are in shadow and then adjust accordingly this does a nice soft shadow from surrounding objects might help some. The university of central florida has http://www.irisa.fr/siames/GENS/kboulang/publications/grassSiggraph2006ppt.pdf

thats a pretty good algorithm and i expect to see it in upcoming football games as they said ea supported them with it


ive looked at that paper and tried to implement the model part... basicly i create 32x32 blocks in which i generate grass depending on a density map...

im storing each grass blade in a displaylist for performance.. but if im gonna store every blade in memory it would take massive amounts of memory.. how do i solve this?
I will try to answer some of your questions. I am the one who wrote the article for Siggraph.

I worked one year and a half on grass rendering and encountered many of your problems, particularly about performance.

In my approach, I use geometry for blades of grass in the foreground. I create patches of about 3000 grass blades. Since each grass blade is defined by a triangle strip, I do not use display lists for each grass blade, it is too expensive. I use a vertex buffer object for the whole patch of grass, I render it with a single display list, but I use the GL_EXT_multi_draw_arrays extension to make a single draw call for the 3000 triangle strips (this last extension multiplied the rendering speed by 4.5).

For grass that is farther, I do not use billboards, but a kind of volume rendering instead, based on slices. This allowed me to get very smooth transitions, and very good parallax effect (3D effect).

Quote:but how would i go for shadows? i need a way that each grass texture will cast shadows on both terrain and other grass textures...


For the shadows, I found a way to obtain approximative but very convincing soft shadows cast by grass blades to other blades. It is described in my technical report . To summarize, I use a cylindrical shadow mask around each blade of grass. This shadow mask is unique (here is the approximation), and rotated for each blade of grass to hide the fact that they are not real shadows. Here the kind of result I get:

Shadows cast on grass blades

I really encourage you to not use shadow maps. The resolution you need has to be very high, you have an additional render pass, you cannot use billboards with them.

To cast shadows on the ground, I use regular projected shadows on a plane. The use of stencil buffer removes the bugs due to overdraw. However, it has some performance impact. Recently, someone proposed me to use framebuffer objects rather than stencil buffer. I did not implement it yet, but I think it would be useful. Also, to cast shadows on curved terrains, I compute the projection matrix in the vertex shader rather than in the CPU, by considering that the terrain is locally flat compared to the size of a grass blade. I just give the normal of the terrain for each vertex I am processing. It looks expensive, but it is not really since the bottleneck was in another stage of the pipeline in my case.

Quote:im storing each grass blade in a displaylist for performance.. but if im gonna store every blade in memory it would take massive amounts of memory.. how do i solve this?


I use patches of 3000 grass blades and make use of instancing. A single patch is stored in memory, so it costs almost nothing. However, if I render grass patches over a uniform grid, repetition is visible, that is why I assign a random symmetry to each patch (stored in a map covering the terrain).

Quote:This PDF looks indeed very nice but I wonder how many triangles you have to draw to make a normal piece of terrain look realistic. A few 100K I presume. And vertex and pixel shaders are not cheap either I think (with wind movement and heightmaps that is it).


I use 8 triangles per grass blade, about 3000 grass blades per patch, so about 24K triangles per patch. Depending on the view angle, I have 0 to about 10 patches rendered per frame (the others are rendered with volume rendering). Roughly, I have about 100K triangles rendered per frame. However, with the VBOs and the multi draw array extension, I get really interesting performance. The proof is this image:

Park scene

rendered interactively (11 to 50 fps on a GeForce 7 depending on the view angle, at height of a human viewer) at a correct resolution with high antialiasing, anisotropic filtering, and high texture resolution. Also, the trees represent 600K alpha-blended polygons. The bottleneck was not coming from the geometric grass blades. The size of the terrain has almost no influence, because the rendering of far grass is very cheap. I rendered a football field of 627 million virtual grass blades at 60fps (250fps from a TV camera).

You can have more information on my webpage.
Quote:Original post by Viny

In my approach, I use geometry for blades of grass in the foreground. I create patches of about 3000 grass blades. Since each grass blade is defined by a triangle strip, I do not use display lists for each grass blade, it is too expensive. I use a vertex buffer object for the whole patch of grass, I render it with a single display list, but I use the GL_EXT_multi_draw_arrays extension to make a single draw call for the 3000 triangle strips (this last extension multiplied the rendering speed by 4.5).


i think i formulated my self wrong before.. i use a single display list for all teh grass blades in a patch... i do not quite uunderstand how u use GL_EXT_multi_draw_arrays if u store a patch in a buffer.. wouldnt the entire patch be drawn with only 1 call?

if ive understood correctly u only create 1 grass patch and then use the vertex buffer to displace all the grass patches to their correct position... but could u explain in more detail how u create asymmetry and also how u remove blades based on the density map.. does the vertex buffer have afunction for skipping vertexes or similar?

[qoute]

For grass that is farther, I do not use billboards, but a kind of volume rendering instead, based on slices. This allowed me to get very smooth transitions, and very good parallax effect (3D effect).



how do u generate these slices? do u use a single prestored texture or do u create it in a precomupting state when rendering the real grass blades from the side and storing the results in a texture?


Quote:but how would i go for shadows? i need a way that each grass texture will cast shadows on both terrain and other grass textures...

For the shadows, I found a way to obtain approximative but very convincing soft shadows cast by grass blades to other blades. It is described in my. To summarize, I use a cylindrical shadow mask around each blade of grass. This shadow mask is unique (here is the approximation), and rotated for each blade of grass to hide the fact that they are not real shadows. Here the kind of result I get:



ive been trying with a similar approach but instead of a cylinder i use a singe plane faceing the sun.. since my sun is always on one side of th grass... but my issue is how i generate the shadow mask?

Quote:
I really encourage you to not use shadow maps. The resolution you need has to be very high, you have an additional render pass, you cannot use billboards with them.

To cast shadows on the ground, I use regular projected shadows on a plane. The use of stencil buffer removes the bugs due to overdraw. However, it has some performance impact. Recently, someone proposed me to use framebuffer objects rather than stencil buffer. I did not implement it yet, but I think it would be useful. Also, to cast shadows on curved terrains, I compute the projection matrix in the vertex shader rather than in the CPU, by considering that the terrain is locally flat compared to the size of a grass blade. I just give the normal of the terrain for each vertex I am processing. It looks expensive, but it is not really since the bottleneck was in another stage of the pipeline in my case.

i dont understand qutie how this work.. ill just have to do some more readin


Quote:im storing each grass blade in a displaylist for performance.. but if im gonna store every blade in memory it would take massive amounts of memory.. how do i solve this?

I use patches of 3000 grass blades and make use of instancing. A single patch is stored in memory, so it costs almost nothing. However, if I render grass patches over a uniform grid, repetition is visible, that is why I assign a random symmetry to each patch (stored in a map covering the terrain).


as before.. how do u create the asymmetry? do u use this random seed to move teh grassblades in a random direction in the vertex buffer after uve move the entire patch?


Quote:This PDF looks indeed very nice but I wonder how many triangles you have to draw to make a normal piece of terrain look realistic. A few 100K I presume. And vertex and pixel shaders are not cheap either I think (with wind movement and heightmaps that is it).

I use 8 triangles per grass blade, about 3000 grass blades per patch, so about 24K triangles per patch. Depending on the view angle, I have 0 to about 10 patches rendered per frame (the others are rendered with volume rendering). Roughly, I have about 100K triangles rendered per frame. However, with the VBOs and the multi draw array extension, I get really interesting performance. The proof is this image:

rendered interactively (11 to 50 fps on a GeForce 7 depending on the view angle, at height of a human viewer) at a correct resolution with high antialiasing, anisotropic filtering, and high texture resolution. Also, the trees represent 600K alpha-blended polygons. The bottleneck was not coming from the geometric grass blades. The size of the terrain has almost no influence, because the rendering of far grass is very cheap. I rendered a football field of 627 million virtual grass blades at 60fps (250fps from a TV camera).

You can have more information on my webpage.



as another point i cant use VBOs for some reason my coputer crashes.. which is why im forced to use DL..

anyways thanks for answering my previous questions!
Viny, it looks awesome! DEMO PLEASE!!!
also do u use any kind of diffuse lighting?

ive been experimenting with defining normals for each vertex and then bending them towards the camera during rendering.. this way i get both lighting and self-shadowing... but im not sure if its rly necessary...
Quote:i think i formulated my self wrong before.. i use a single display list for all teh grass blades in a patch... i do not quite uunderstand how u use GL_EXT_multi_draw_arrays if u store a patch in a buffer.. wouldnt the entire patch be drawn with only 1 call?


I render each blade of grass with a triangle strip, so I cannot use one single draw call since I have to restart the primitive for each triangle strip. I could use degenerate triangles but I used a simpler approach. In OpenGL, I use glDrawArrays() to render one triangle strip (not glDrawElements since each vertex is processed only once), and I would need to call this function for each grass blade. However, with the GL_EXT_multi_draw_arrays extension, I give an array of arrays to render, reducing the patch rendering call to one glMultiDrawArrays() (about 4.5x speed-up). I am using VBOs at the same time (about 2x speed-up), and embed the rendring call in a display list (about 1.2x speed-up). The total speed-up is about 10x compared to traditional vertex arrays.

Quote:if ive understood correctly u only create 1 grass patch and then use the vertex buffer to displace all the grass patches to their correct position... but could u explain in more detail how u create asymmetry and also how u remove blades based on the density map.. does the vertex buffer have afunction for skipping vertexes or similar?


I displace each patch using a translation vector passed as an uniform variable in OpenGL Shading Language. For the orientation, it works like this:
- for geometric grass patches and vertical slices, I mirror them using an asymmetry vector, (-1,-1), (-1,1), (1,-1) or (1,1) passed as a uniform variable to the vertex shader. It is OK for these two types of patches since they are rendered individually
- for horizontal slices (faraway grass), I render them as macro-cells. I cover several cells of the terrain uniform grid with a single quadrilateral on which the texture is repeated. The problem is the management of the orientation. Hence I cover the terrain with an orientation map, where each texel corresponds to a patch of the terrain. This texture is not filtered (GL_NEAREST filter). The red and green channels give the asymmetry vector per rendered fragment, and for each fragment I multiply the current texture coordinates by this asymmetry vector. A modulo 1 gives me values for texture coordinates in [0,1).

You can have details in Section 4.1 of the technical report.

Quote:how do u generate these slices? do u use a single prestored texture or do u create it in a precomupting state when rendering the real grass blades from the side and storing the results in a texture?


Detailed in Section 3.3 of the technical report. To summarize, I render slices of a patch defined by geometry (between two clipping planes) for several view and light angles. I store this information in files (for faster loading of the application) under the form of a texture atlas for each slice. At rendering time, to render a given slice, I combine several images taken from the texture atlas to create the final fragments. I do this because the grass I am rendering is fully dynamically per-pixel lit. The program would run a lot faster without, but since I am doing researches, I am always working with the worst case.

Quote:ive been trying with a similar approach but instead of a cylinder i use a singe plane faceing the sun.. since my sun is always on one side of th grass... but my issue is how i generate the shadow mask?


Since the shadow mask approach is an approximation, you can use an approximation to create the shadow mask ! In my case, I render a slice of a patch of grass with geometry in black and white, seen from the side.

Quote:Viny, it looks awesome! DEMO PLEASE!!!


Thank you [smile]
On my webpage, in the downloads section, you can get a video of the demo (I advise to get the high resolution one if you can). For a live application, I did not release it yet because it uses a 3D engine I am developing that is still experimental. I have no guarantee it will work correctly on every computer. I am working on it.

Quote:also do u use any kind of diffuse lighting?

For the current version, I am using simple diffuse lighting without specular. I am searching for a better representation of the grass blades defined with slices to have this additional light component.

Quote:ive been experimenting with defining normals for each vertex and then bending them towards the camera during rendering.. this way i get both lighting and self-shadowing... but im not sure if its rly necessary...


I am sorry, I do not understand. How do you get self-shadowing by bending the normals ?

This topic is closed to new replies.

Advertisement