Shader-based Grass (or Fur)

I’ll work on doing it that way, I pass in the bend factors each time because it computes the new bend factor based on the previous frame’s bend factor. I suppose I could just calculate the current bend factor based on the bend rate and the total time, though.



I would just ignore the error entirely but my framerate drops below 1 fps when I pass in different bend factors each time. Let me see what happens when I just give it the tpf and total time as uniforms.

Alright, so I simplified it so that I’m only passing in one bend factor float. If I was passing in the tpf every time it’d basically be equivalent, since the tpf value changes every time anyway.



I ran the Profiler two different times: once while the program is updating the bendFactor float every frame, and one where it is only set once. When the bendFactor is only set once, org.lwjgl.opengl.GL20.glLinkProgram is only called 62 times (which about correlates to the fact that I’m drawing 60 layers of one Geometry).



When the bendFactor is updated every frame, that same glLinkProgram is called 62 times every frame, taking up over half of the processing time. The next offender on the list is com.jme3.renderer.lwjgl.LwjglRenderer.updateUniformLocation, which was called over 500 times per frame.



The reason all of this is so strange is that, again, another float (Layer) is updated every layer of every frame, which is 60 times more often than the bendFactor, which is only updated every frame, and yet only updating bendFactor causes this problem.

Another update - tried removing the bendFactor code entirely and tried a couple of different things with the Layer variable.



Normally, Layer is set 60 times per frame, but it’s set to the same 60 things every frame. The game runs smoothly this way.

I changed it so that Layer is set to a random float. I get about 2 fps this way. No “not declared in shader” errors, just really terrible speeds.



Maybe if I make the grass wave the same way each frame, it will optimize it somehow and run much better? I’ll have to try that instead.

Figured it out.



I was using Material.setFloat each frame to change the layers and other parameters. I realized that this method probably purposely re-compiles the shader for you or something, so I searched for a way to update the shader variable directly.



I’m now getting the attribute ID using glGetAttributeLocation, then altering it using glUniform1f, from the lwjgl libraries. Framerate is MUCH better now!



I also did what you suggested about passing as little information as possible every frame and letting the GPU take care of more calculations. Thanks for the help, nehon :slight_smile:

Would love to see the updated code :).

The recompliation only happens if you alter a variable that effects a define, otherwise it should be as fast as modifying the uniform itself.

Are you using built-in materials only? Perhaps you can post a test case that shows the 2-fps issue

Momoko_Fan said:
The recompliation only happens if you alter a variable that effects a define, otherwise it should be as fast as modifying the uniform itself.
Are you using built-in materials only? Perhaps you can post a test case that shows the 2-fps issue


Ahh okay, I assumed that you had to put every parameter in the Defines section as well as the MaterialParameters section. I had all of my variables listed in the Defines area. After I removed it from the Defines area, using Material.setFloat works just as well as updating directly. When is it necessary to put a variable in the Defines area? When you need to use #ifdef?

Once I clean up the code a little and get some sort of culling in place I'll post some new code :)

If you want a uber shader wich does 500 things (kinda like the current light shader)



it has various defines like parralax normal ect.



but if you only set a color and everything else is not set (so all ifdefs return a false) then the shader recompiles it to a very basic shader that simply sets a color. (So the rest of the shader code is not run at all, it does not even exist for the gpu that renders in the context of the simple coloured geometry)

Okay, I’ve made some progress on it, especially in making the grass “wave in the wind”. :slight_smile:

EDIT: Youtube embed failed completely, here’s a link: http://youtu.be/fg31tSrLQ5k

And here’s the https://rapidshare.com/files/642455295/GrassShaderDemo.zip. Press ‘O’ to increase the wind rate, ‘L’ to decrease it.



Still need to work on distance culling, but I’m pretty happy with the rest of it. I added something at the last minute that makes the grass more transparent as you get closer to the top, it gives it a nice tapering effect:



@canis85 can you post you file to somewhere like DropBox.



RS causes a lot of problem.



thanks

Sure, I made a dropbox account and uploaded it. Here’s the public link: http://dl.dropbox.com/u/30519575/GrassShaderDemo.zip

Ati 3800 Series errors:

(seems like you are doing some not specifed things here)

normal = normalize((vec4(inNormal, 1.0))*g_WorldViewMatrix);

normal is a vec3, shaders do not allow implicit casts, while nvidia silently ignores such stuff ati’s error crash out.

vec3 vGravity = 0.0; → vec3 vGravity = vec3(0.0,0.0,0.0);

And some similar, I fixed erros untill the code compiled and the application run then I made a screenshot:



Changed code here : http://nh-game.net/grass/

http://nh-game.net/grass/grass.png

Ah thank you, I don’t use ATI in any of my machines so I didn’t know that was an issue. It does give warnings about implicit casts though, so I’ll make sure to fix them from now on before I release my code.



Thanks for the fixes :slight_smile:

I’ve got a small update that uses a really basic check to see how far from the camera the current geometry is, and decreases the number of layers rendered depending on how far away it is. Already this doubles the FPS I get using it on the entire terrain. I’m still hoping to find a way to decrease it more dynamically, but in order to do that I think I’ll need to get further down into the rendering code to check sections of the geometry before they’re rendered, rather than the whole geometry.



Code update here (as well as further code updates). This code also includes EmpirePhoenix’s ATI compatibility fixes. (EDIT: Fixed link)



On my todo list now is:

  • More granular distance checking for a smoother quality fade
  • Lighting support
  • Integration into the TerrainLighting material (maybe its own Technique? Something you could toggle on or off in the material)



    This picture shows the geometry check method. I still need to get rid of the black bars between TerrainPatches. You’d also want to use a texture that more closely matches your grass color :wink:

1 Like

very nice

I’m wondering, what are the black lines that we can see on each screen shots?

@nehon: It’s the copied surface of the same mesh as the shader applied mesh is push to the front in order to make the effect I think… May be some alpha issues still remain in the code for terrain???.. The same technique is considered by me a little bit while I want to go to make a fur cloth my self …

@canis85: What we really need is a culling system, a serious one for all kind of mesh before rendering…

Additional , as for rendering grass in the terrain , some idea flash in my brain, :stuck_out_tongue: the far grass may use other technique for a strain of grass, what about an simple texture :stuck_out_tongue: , you can’t see the strain anyway!!!

One intresting idea, since you currently use Quads, how about using only one Mesh you update constantly in GLPoints mode. Then useing a shader do the right view transformation (GLPoint behaves like billboard, probably not wanted here)



Kinda in the Idea of this:

http://www.shmup-dev.com/forum/index.php?topic=1870.0

@nehon atomix may be right, I really don’t know what causes them. All I know is that it moves with the grass blades on the very edge of each TerrainPatch. If you run the demo and move the camera really close to one of the black lines, it’s as though the pixels on the very edge of each patch are not transparent. The grass is still rendered, but where it should be transparent it draws black.



@atomix I agree using a simple texture once you get to a certain distance would almost definitely be faster. The only reason it still renders a couple of layers is in case your “ground” texture is something simple like dirt, then you wouldn’t have to change the texture and figure out how to blend the distance transition as smoothly. Plus, only rendering one or two extra layers really isn’t much of a performance hit.



@EmpirePhoenix I guess I’m confused as to what you’re suggesting. Right now, the “grass” is achieved by taking the mesh that you want grass on, and setting the material to the “Grassy” material. The LayerRenderManager then overrides the renderGeometry() method of the standard RenderManager, rendering the original mesh (by default) 60 times instead of only once. The first render pass renders a standard texture on the mesh, each further render pass renders (essentially) a different texture that is a set of random dots on a transparent background, slightly higher than the last render pass. The set of 59 dots creates the illusion of a single line, forming each blade of grass. I liked this method over other methods that use quads, because this way you don’t have to attach thousands of quads to your node tree to achieve a field of grass. See this page for the original idea that I based my implementation off of.



I seem to have (mostly) solved the black line issue by using terrain.setQueueBucket(Bucket.Transparent). You can still see them sometimes from certain angles, but it looks much better now:



@canis85: It looks great and have a good performance speed … Some lighting, and a little bit of shading improvement is need for more realistic grass … According to the articles from xdev.net, the texture use to render a grass layer can be modify a little bit for shadowing …



http://www.xbdev.net/directx3dx/specialX/Fur/images/interfur_shadows/shadows_explained.jpg



Anyway , you’re doing a great job man, keep rocking on!!