Search Unity

[RELEASED] DirectX 11 Grass Shader

Discussion in 'Assets and Asset Store' started by Nonakesh, Aug 17, 2015.

  1. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    That's exactly how it works. It splits each triangle into many sub triangles. Each of the generated vertices is than used as a base for the blades of grass. That's why the grass density is dependent on the size and form of the base geometry.
     
  2. JonDadley

    JonDadley

    Joined:
    Sep 2, 2013
    Posts:
    139
    I've been getting an issue where the fix for the SSAO only works in a built player if I include the custom Camera-DepthNormalTexture shader in the list of 'Always Included Shaders' in the Graphics Settings menu in the editor. The SSAO still works in the editor game view however. I assume that Unity is automatically stripping the shader out for some reason.

    The problem is, when I include the custom Camera-DepthNormalCamera in the 'Always Included Shaders' list it increases my build time by over 30 minutes!

    Any ideas on how to resolve this issue? I really need the SSAO fix but the massively increased build times are a huge problem :(
     
  3. Enoch

    Enoch

    Joined:
    Mar 19, 2013
    Posts:
    198
    I am thinking seriously about this shader for my current project. But I am concerned. I know I will need to modify the shader as I have some special needs. First I need all 4 input grass types to have density controlled at the vertex level (using UV or color vertex data).

    I also (and this is the weird one) I need to control ambient lighting through a vertex variable as well. I have smooth voxel world where I build geometry at runtime. I use color.a as an ambient modifier, this is so when on the surface we can pass color.a =1 and everything gets full light. When underground we can pass color.a = 0 and now shadows will turn everything black (no ambient). So basically when color.a = 0 I need the grass to be completely black when in shadow, when color.a = 1 it needs to work as normal (getting full ambient).

    Since I generate my geometry at runtime anyway, my approach is to build special grass geometry by using the same triangles I generate for terrain for the grass geometry. Will your shader take that geometry, generate grass geometry but not render the original grass geometry in anyway?

    Given that, how hard do you think it would be to modify one of the shaders to support these requirements. I don't mind the doing some shader work, but if I need to basically rewrite you whole shader to support what I need, its probably better for me to write from scatch myself. Thanks for any help you can give. This looks like it will be a fantastic performance boost (I generate my grass quad by quad now when generating my terrain geometry so lots of geometry on the pipeline that I hope I can tessellate instead).
     
  4. Freddy888

    Freddy888

    Joined:
    Sep 13, 2014
    Posts:
    165
    I'm getting pink too, could you please tell me how to fix it ?
     

    Attached Files:

    • pink.jpg
      pink.jpg
      File size:
      128.1 KB
      Views:
      1,064
  5. Freddy888

    Freddy888

    Joined:
    Sep 13, 2014
    Posts:
    165
    Should add that is is working fine in the editor, it just does this on the build.
     
  6. Freddy888

    Freddy888

    Joined:
    Sep 13, 2014
    Posts:
    165
    Fixed it - I had done something weird to my main terrain, had lost the splat textures some how. User error, sorry to bother you.

    Really great asset, I like it a lot :)
     
    Nonakesh likes this.
  7. micuccio

    micuccio

    Joined:
    Jan 26, 2014
    Posts:
    143
    Hi there!
    I purchased your asset some months ago and I am using it right now. Is really nice but I think I may have a little issue.
    As soon I put one of the prefabs (crop plane or the grass one), I get a sensible drop of framerate.
    From the profiler I can see that Gfx.WaitForPresent message is the first.

    I use Unity Free and my GPU is : NVIDIA® GeForce GTX 960M 4gb

    Am I missing something?

    Thanks in advance and Best regards,

    Dom
     
  8. ninjaboyjohn

    ninjaboyjohn

    Joined:
    Mar 30, 2014
    Posts:
    23
    Question about a non-traditional use-case for this shader. I'd like to have an animated object covered in grass, imagine a "grass monster" covered almost like a fur shader.

    I can get good looking results using this shader (with object space mode on, use normals turned on, and all wind vars zero-d out) as long as the character doesn't animate. With animation turned on, the grass position fluctuates wildly anywhere there is movement - I assume this is because the shader isn't expecting vertices to move and does a lot of complicated LODing for the normal use case.

    Is it possible to "fix" the position of grass blades in this case or am I attempting something that is fundamentally incompatible with this grass shader approach?

    Thanks!
     
  9. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    I guess Unity will always include ALL shader variants, which right now are about one hundred or something. I've not tried it, but in later Unity versions, there's a option to change Unity's CameraNormals shader in the graphics options, maybe that would do the trick. But if you aren't using the Unity 5.4 beta, you'll probably still want a fix, which should be quite easy actually:

    Just open the Camera-DepthNormalTexture shader, scroll to the bottom and replace all the "#pragma shader_feature" lines with "#define THE_FEATURE_YOU_WANT", if you want to deaktivate a feature ("__"), just don't write a define.
    Here's a example how that could look like:

    Code (CSharp):
    1.  
    2.             // ================= Shader_feature block start =================
    3.             #define shader_feature SIMPLE_GRASS THREE_GRASS_TYPES
    4.             #define PBR_GRASS_LIGHTING
    5.             #define GRASS_RENDERTEXTURE_DISPLACEMENT
    6.             // ================= Shader_feature block end  =================
    This example would leave you the choice between simple and 3 texture grass mode, have the fake grass PBR lighting and use RenderTexture displacement. Just configure all your use cases here and the compile times should be reduced significantly!

    Ok, so first of all, doing that is definitely possible! And I'm sure that rewriting the shader would be a lot more work that modifying mine. The main problem would be that you'll have to push your vertex splat-map and your ambient color from the vertex shader through all the shader steps (vertex->tessellation->geometry->fragment), so it's a bit of work. For the lighting you could probably use the unlit mode and just multiply the output with your ambient color, at least that would be the easiest way. I could help you with the whole thing later this week.

    The shader will use the geometry it's on to generate the grass, but it won't render the floor at all, there's no way to do both in one shader, at least I haven't found one. If you want the grass and a ground model, just create a second object for the grass. I think you could also use a submesh, with a second material if you want to reuse the vertices, but I haven't tried that.

    How extreme is the drop? Gfx.WaitForPresent is probably just how the profiler interprets the shader doing what it does. You should keep in mind that the shader needs a lot of performance if your grass density is too high. With the right settings you could get even the highest end graphics cards to their limit, but I've got it working on old laptops as well. With very low grass density of course.

    I think the problem is that the shader is using the local position as basis for random calculations. You look at all the GrassVertex.shader and replace the object space position with the uv position of the vertex, so line 7 should look like this: "v.objectSpacePos = v.uv;"
    Oh and you'll probably have to move the whole #ifdef block below "v.uv = TRANSFORM_TEX(v.uv, _Density);", or you won't get the right values.
    But I'm not sure if this will work, a grass monster really isn't what I had in mind when I made the shader! ;)
     
  10. micuccio

    micuccio

    Joined:
    Jan 26, 2014
    Posts:
    143
    Thanks for the quick reply.
    I am not very familiar with the tool, but reading the manual I noticed that are required two cameras (one for the grass displacements and another for the rest).
    Could you tell me the reason for that?

    Thanks
     
  11. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    Yes, the first camera is your main camera that renders the grass, nothing special about it. The second camera is the displacement camera, it renders a bird-eye view of all the displacement objects (objects or textures that move the grass around, for example it could be a trail behind your character). The rendered image from that camera it then taken by the shader and used to move around the geometry, so the grass actually looks like their's a trail behind your character.

    If you don't like the second camera, you can always use the old system that manipulates textures directly, but that's slower and harder to work with in my experience.
     
  12. micuccio

    micuccio

    Joined:
    Jan 26, 2014
    Posts:
    143
    thanks for the explaination.
    Could be that the reason for the dropping framerate?
    just to tell my situation :
    with one moving character and just a Unity Terrain I get circa 900 fps (Vsynch off)
    and as soon i add the grass shader i drop to 200 pfs.

    really strange no?

    I hope you can help me with this issue.
     
  13. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    The second camera shouldn't be the problem here, it doesn't render anything expensive. You could just disable it to see how much performance it takes.

    On another note: the difference between 900 FPS and 200 FPS isn't that large. I actually think milliseconds (ms) are a better measurement for performance, they're displayed right next to the FPS. The difference between 900 and 200 FPS is actually only 4ms. You could have 4 times of that performance cost and still have 50FPS, which is playable in my opinion.
    In other words: The difference between 900 and 200 FPS is the same as between 200 and 100 FPS, so while it sounds like a lot, it's not really that much.
     
  14. micuccio

    micuccio

    Joined:
    Jan 26, 2014
    Posts:
    143
    Thanks for the reply.
    I should not worry then.
    My current number of ms is around 2-3 after that the Grass shader is on.
    is that a normal number according to you experience with the shader?
     
  15. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    That seems very normal to me, even on the better end. My test scene, with admittedly very large terrain, have from 5ms to 25ms (for trailer scenes, so I didn't care about the performance) on my PC.
     
  16. GoGoGadget

    GoGoGadget

    Joined:
    Sep 23, 2013
    Posts:
    864
    Just picked this up, looks like a great shader overall, but wasn't expecting the enormous (unusable) performance cost of using it with a Unity terrain? I can deal with popping, but I can't deal with an extra ~12ms on the GPU (even with pixel error @ 5 instead of 1). Made sure to de-tick 'draw' trees as well, but it's spending a huge amount of time in the profiler drawing the grass material terrain and writing it to depth... I'm hoping there's some magic checkbox I'm missing? (Using deferred/DX11/PC)
     
  17. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    Well, I think it was always clear that the shader is a mid to high end effect, but you should be able to use it on almost any DirectX 11 hardware by adjusting the Density Falloff and Max Density settings.

    If the grass is still very dense, even with high falloff and low max density, you probably set the terrain polycount too high. The higher the polygon count of a mesh, the higher the grass density will be. So try to decrease the resolution of the terrain (or whatever the setting is called) and you'll have more control over the actual grass density.
     
  18. GoGoGadget

    GoGoGadget

    Joined:
    Sep 23, 2013
    Posts:
    864
    Ah, thanks, those density settings were the "Magic Checkbox" :) Managed to get it to ~4.3ms now, which I guess is as much as can be expected with Unity terrain, only issue now is the very slow workflow painting the density texture - would be great to have it work a bit smarter; ie, grab the detail splatmap from the terrain that the grass is on.
     
  19. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    I've heard that some people did manage to do just that! I haven't tried it myself, but you should be able to get the splatmap textures from here: http://docs.unity3d.com/ScriptReference/TerrainData.html

    You could also use any splatmap painting asset from the asset store, these could also be used for custom meshes. Or you could just use a image manipulation software (i.e. Photoshop), but that might be a bit tricky.
     
  20. JonDadley

    JonDadley

    Joined:
    Sep 2, 2013
    Posts:
    139
    I followed your example and while it did increase my build times dramatically, I no longer seem to have the SSAO fix in the my build. Here's what my shader block looks like:

    Code (CSharp):
    1.  
    2.  
    3.             // ================= Shader_feature block start =================
    4.             #define shader_feature SIMPLE_GRASS
    5.             #define PBR_GRASS_LIGHTING
    6.             #define UNIFORM_DENSITY
    7.             #define GRASS_WIDTH_SMOOTHING
    8.             #define GRASS_TOP_VIEW_COMPENSATION
    9.             #define GRASS_RENDERTEXTURE_DISPLACEMENT
    10.             // ================= Shader_feature block end  =================
    11.  
    and here's what my shader settings look like:



    Have I done something wrong? Is there something special I need to do to get both the fast build times and the SSAO fix working together?
     
  21. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    Can you try changing these settings in both the Grass.shader and the CameraNormalDepth shader file? In the grass shader those settings exist multiple times, all of them have to be the same. By the way, you'll overwrite the settings from the inspector with that, so you won't be able to change them there any more.
     
  22. micuccio

    micuccio

    Joined:
    Jan 26, 2014
    Posts:
    143
    Talking about performances, is more efficient one big "area" of grass (big like a 250x250 terrain) or small patches?
    Thanks in advance
     
  23. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    If you optimize the smaller patches, so those far away are disabled, you might have better performance with that. Otherwise a big area is slightly better because multiple objects have a slight overhead in Unity.
     
  24. Enoch

    Enoch

    Joined:
    Mar 19, 2013
    Posts:
    198
    I finally got around to purchasing this. I have been looking through your shader and it looks like the changes I need will be pretty simple. As for the density I am thinking of adding verrtex color to appdata and then some where in GrassVertex.cginc do:
    Code (csharp):
    1.  
    2. _DensityValues = v.color;
    3.  
    I might be over simplifying it and I don't think I can actually write to _DensityValues like that and have it propagate down. I will likely need to just pass v.color into the geom function in GrassGeom.cginc and replace all the Density00, Density01, etc with vertexcolor.r, vertexcolor.g, etc. I am a little less knowledgeable about geom and tessellation function so I have to figure those out first.

    As for my ambient coloring issue thats even easier I think after looking at your surface shader. I simply need to crank the strength of my main light's shadows up to 1 (so fully black in shadows), then I simply set the emission to gi.indirect * my ambient value
    ie:
    Code (csharp):
    1.  
    2. o.Emission = gi.indirect * uv.u;
    3.  
    In this case I am burying my ambient multiplier in the uv.u coordinate when I generate the geometry since I won't using those coordinates for a density map.

    Loving this asset, I couldn't be happier. Assuming all this works out eventually, you've saved me hours and hours of time and probably given me a foliage look I couldn't have achieved otherwise. As a thought I doubt I am the only one who would want to control density through vertexcolor, you might consider making this a full feature.
     
    Nonakesh and GoGoGadget like this.
  25. GoGoGadget

    GoGoGadget

    Joined:
    Sep 23, 2013
    Posts:
    864
    Just wanted to echo this, would be very handy to have density controlled by vertex color as a built-in option.
     
  26. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    I'm glad you like it!

    I'll look into it! It doesn't seem too hard to do, but I'm a bit short on time right now so I can't promise a timeframe. But I'll probably implement it sometime in the next two weeks.
     
  27. Patatus

    Patatus

    Joined:
    Mar 21, 2016
    Posts:
    5
    Hello Nonakesh,

    There is something i don't understand with density. Here are some pîcs

    Scene.jpg
    Material.jpg

    I don't know why there is no grass on color because each color represents a density right ?
     
  28. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    That's right! You shouldn't think of the texture as having a color, but as having 4 values per pixel. Every color channel represents the density of one grass type. In your case where there is only one grass type only the first channel (red) is relevant, you can fill them with whatever you want. In other words, when the red channel is 1 you have full density, when it's 0 you have no grass at all. There is grass in the white areas because white has the color value (1, 1, 1, ?)
     
  29. Patatus

    Patatus

    Joined:
    Mar 21, 2016
    Posts:
    5
    Ah okayyyy! This is not what I imagined lol. So for a terrain I can convert my hightmap to red (or let it white ?) to have grass where I want ? Maybe edit a litte bit. And if I make a gradient the density will therefore be based on it?
     
  30. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    Yes exactly!
    Also if you want to use a texture to change the color of the grass or it's height, you can use the Color Texture (RGB), Height (A) field in the shader settings. As the name says, the RGB channels control the color and the Alpha channel controls the grass height. 0 and you won't have grass, 1 and it's at the max height.
     
  31. Patatus

    Patatus

    Joined:
    Mar 21, 2016
    Posts:
    5
    I've just tested it and it works perfectly ! Now I'm good to go ! A last question. Does it work if I paint red texture on the mesh ?
     
  32. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    If you mean painting red into the texture, yes, you could even change it at runtime. If you mean change the vertex color, not yet, but I'm planning to add that soon. If you have any other problems or questions feel free to ask!
     
  33. Patatus

    Patatus

    Joined:
    Mar 21, 2016
    Posts:
    5
    Thank you very mush !
    No I mean paint a duplicate mesh with for exemple a mesh painter (wich I can probably find in the asset store).
     
  34. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    Yes, you could easily paint the grass like that. If you want to be able to paint the color channels separately you should look for a splat map painter, I'm sure there are some on the asset store. A splat map is basically the same thing as the density texture.
     
  35. Patatus

    Patatus

    Joined:
    Mar 21, 2016
    Posts:
    5
    I'm in paradise. Thanks again and keep your good work guy !
     
    Nonakesh likes this.
  36. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Whoa, it's beautifull! Tell me plz, does it work with shperical surfaces? I mean something like a planet =)
     
  37. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    Yes it does, but with a few problems. Wind can be a bit strange and displacing grass (like in the picture) doesn't work out of the box.

    You could use this asset, if you want something that looks like a planet, when you're using that, everything should work as expected: https://www.assetstore.unity3d.com/en/#!/content/26165
     
  38. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    As I understand Curved World just make some kind of "illusion" of spherical world, but it is not "real planet". I'm interesting in pretty look grass on tiny planets :)
     
  39. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    As long as you don't want the displacement feature and are OK with the wind being a bit weird at the border of the planet (when seen from above), it works quite well.

    Here's a screenshot I made when I implemented that feature:

     
    Patico likes this.
  40. kookyoo

    kookyoo

    Joined:
    Apr 19, 2010
    Posts:
    53
    Hi,
    Sorry for asking that here, but it seems some people here tried with no success to make this shader working on PS4. I understand that DX11 isn't implemented on Sony's console but is there any way to get Geometry shaders working on it ? Shaders are compiling but nothing's rendered on PS4 as soon as I set a geometry shader pragma.
    If you have any information about that I would love to hear about it.
    Thanks everybody
     
  41. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    I don't have a PS4 so I can't test it myself, but I haven't heard of a way to get them to work there. Neither with OpenGL in general as far as I know.
     
  42. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Thanks for comments. Very impressive, I will consider about buying it :)
    And my congratulations, your asset is #1 in TopPaid! =)
     
  43. x4000

    x4000

    Joined:
    Mar 17, 2010
    Posts:
    353
    This may show my ignorance of shader technology at each SM level, but I figure it doesn't hurt to ask -- who else would better know but you?

    Anyhow: do you think it would be possible to create a features-scaled-back-some version of this for DirectX9 and equivalent?

    Rationale: I'm personally rocking a great rig, but if you look at the steam hardware survey, it's a very small sliver of users that can support DX11. Given your approach is so different from any other grass out there, trying to implement something that works in DX9, and then yours separately in DX11, would be rather a nightmare.

    The ideal solution from my point of view would be to have a feature-limited version of this for DX9 and so forth that is basically the fallback shader. So, yeah, it doesn't look quite so awesome on DX9 -- but it's still basically the same concept and I don't have to recode some completely other solution. And then on DX11 it switches to this shader in its full glory.

    I absolutely love the idea of having the super top-end graphics for those who can run it, but I also don't want to completely exclude the DX9 crowd, either.

    It may just be infeasible with this approach because of the lack of tesselation in DX9 or some other limitation that I'm not aware of (instruction count, etc). But I figured I'd ask. :)
     
  44. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    A rather small sliver of users? Last time I checked it was about 80%. I think it's actually becoming reasonable to develop for DirectX 11, or at least make some features only available to those who support them.

    Anyway, the thing is, the shader uses tessellation and geometry shaders (which are DirectX 11 only, or the OpenGL equivalent of that) so porting it to DX9 hardware just isn't possible.

    It would be possible to have grass on those systems by doing most of the work on the CPU, but that's a completely different thing. And there are some assets on the asset store that do just that. Arguably not as good looking (at least in my opinion, but I'm based ;) ), but you could use a combination of both, switch when you detect that DX11 is not supported. You could even use the default Unity terrain grass, but that looks dreadful in my opinion. Also keep in mind that anything that looks good, will use enough power that a DX9 GPU might not be able to handle it, even if it theoretically supports all the needed features.
     
  45. x4000

    x4000

    Joined:
    Mar 17, 2010
    Posts:
    353
    Huh! Something got skewed with the steam hardware survey recently, and it's reporting only 14% instead of the 80% it said just a few months ago. I had not looked at the historical data: http://store.steampowered.com/hwsurvey/videocard/

    I'm not sure what the heck is going on with the more recent data, and why that is clearly messed up. Even if that was counting non-windows machines that's nowhere close to being right.

    Totally understood on the CPU-based solutions, and yes I definitely agree they don't look as good. I'll have to look around at some of the games of late in genres similar to mine and see how many of them require DX11. You're right that it really does look like it's finally a viable thing to develop for -- those without the DX11 cards might not have the other minimum requirements anyway (CPU/memory) for my game.

    I'm used to developing in 2D and targeting it running on a toaster, so it's new to consider excluding anyone by minimum hardware specs. ;) Anyhow, just wanted to say fabulous work!
     
    Nonakesh likes this.
  46. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
  47. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    Any news on getting this working for PS4?
     
  48. KyleOlsen

    KyleOlsen

    Joined:
    Apr 3, 2012
    Posts:
    237
    We're experiencing some poor performance using Unity's terrain with the grass. When following the documentation it tells us to duplicate our terrain and swap to the custom grass shader. However duplicating the Unity terrain is causing some terrible performance for us. We've tried smaller terrain sizes down to 128x128 resolution and still have this hit every frame:



    Each grass terrain is taking massive CPU cycles in Terrain.GenerateBasemap. Is there some other way to get grass working well with Unity terrain? Our goal is to render a maximum of 9 terrain tiles at any given time, however if we are eating 35-40ms just due to duplicating Unity terrain that won't be possible :(

    P.S. Mesh based terrain is not an easy option for us because we are procedural generating our terrains at runtime.
     
  49. Nonakesh

    Nonakesh

    Joined:
    Aug 27, 2011
    Posts:
    576
    No progress there. I'll definitely try to get this working, but as far as I'm aware it's up to Unity to support the right features with OpenGL.

    To be honest, that sounds more like a problem with changing the terrain at runtime. I don't really understand why you'd prefer to use Unity terrain instead of just generating a mesh yourself. I mean if you're generating everything procedurally, Unity terrain has no advantages (like a more or less decent modelling tool) left, none that I am aware of anyways.
     
  50. lazygunn

    lazygunn

    Joined:
    Jul 24, 2011
    Posts:
    2,749
    You might find the Mesh Materializer asset helpful with this

    @Nonakesh - a lot of useful assets are based around unity terrain which could make taking another approach to terrain inordinately time consuming