[RELEASED - FREE] Surreal PBR Grass Shader

***************************************************************
Beta Release - FREE
So I’ve decided to give back to the wonderful Unity community and make this a free asset for you guys. If any of you make custom updates, give it to me and I will update the source code.

Git:

Setup Tutorial (no audio):

If anyone has questions, please feel free to ask. I’m not a good tutorial giver, so… But it’s pretty easy to setup, I think.

NOTE 1: If you use a density map, make sure to make it read/writable in the import settings.
NOTE 2: This does work on meshes, just make sure your Target GameObject has a collider. This uses raycast, so whatever your collider(s) looks like along the Y axis will be the footprint of the grass.
NOTE 3: The tutorial video is choppy when I pressed play, that’s due to the recorder, you can see in the stats screen that I get good framerates.
NOTE 4: I’m in the process of figuring out the LOD/Distance culling for this shader. I’m not a shader wizard so if anyone wants to help tackle that part, be my guest. Occlusion culling works out of the box, just set the “*_SGRenderer” object to “Occludee Static” and include all children. However, this is the type asset that will (should) be sprinkled throughout your scene. So make sure to use the Density map feature. Density map works on a grayscale, so if the color hit is Gray to Black, it will draw grass.

Cheers, Everyone!
***************************************************************

So I am currently working on a Grass Shader, rendering each blade of grass. I am using a point cloud technique to get the positions of each blade of grass. This has turned out to be a very efficient way of rendering grass. This is a PBR geometry shader which uses Albedo, Metallic, Roughness, AO, and Emission.

Different lighting scenarios. All images are 240,000 blades of grass with Post Processing Stack AA (Quality). This is about a 20m square area of grass. I think a final product could handle maybe a 40m (which would be about a million blades of grass) square area before falloff (or LOD). That would be adjustable of course.

Ambient Wet



https://www.youtube.com/watch?v=4_amNm0yikQ
Ambient Dry

https://www.youtube.com/watch?v=qIm9TH_lbWk
Dawn Wet

Dawn Dry

Mid-day Wet

Mid-day Dry

Point lights Wet

Point lights Dry

Spot light Wet

Spot Light Dry

Notice the grass spawns on top of the terrain, conforming to the topology. This also works on meshes, however, it’s not a “fur”. It cannot spawn around a solid mesh. For example if you applied it to a sphere, only the top hemisphere will spawn grass. It works like rainfall. So anything point on the mesh that can be raycasted vertically in the -Y direction will spawn grass.

As you can see in the images and video that the performance on this is EXCELLENT. In both the image and the video, I have the Post Processing Stack applied with AA set to “Quality”, Bloom, and Vignette.

Current settings for the shader include:

Grass Blade 1
Albedo Map
Normal Map
Roughness Map
Distribution Weight
Tint

Grass Blade 2
Albedo Map
Normal Map
Roughness Map
Distribution Weight
Tint

Grass Blade 3
Albedo Map
Normal Map
Roughness Map
Distribution Weight
Tint

Root Settings
Tint
Tint Start Height
Tint Spread

PBR Settings
Metallic
Ambient Occlusion Map
AO Strength

Advanced Settings
Alpha Cutoff
Grass Height
Grass Width
Wind Speed
Wind Strength
Randomness Noise Texture

The whole reason why I started this is because I needed a backyard lawn grass for my game and I got tired of looking for one, so that’s what this is meant for. Obviously, it can be expanded to accommodate other grass types. However, theoretically, you could give it whatever grass texture you wanted currently. In the shader settings, you can set the width and height of the grass.

Here are the current shader settings (this is not final):


Setup Utility:

I plan to provide 3 different grass blade textures with their PBR maps in the final product.

I might provide the Shader in two forms - Unlit and PBR. Unlit actually looks decent and would probably run a little smoother in an end product. This is a DX11 shader and uses Deferred rendering only.

The stats screen in the images and video above was rendering on my PC:
i7-2600K (old… very old)
24GB RAM (why didn’t I just get 32??)
GTX 1060 (I’m told it’s comparable if not slightly under an XBOX One X.. ?? Please correct me if I’m wrong)

I must say, developing this shader and the point cloud technique was inspired by Sam Wronski. He has a great channel on YouTube (World of Zero) that I highly recommend - it’s about everything programming:

7 Likes

This looks super cool! How does it look in VR?

1 Like

Lol I have no idea. I don’t even own a VR thingy. Do the VR thingys even support DirectX 11?? This is DirectX11 only. Also, this is PBR materials with high polycount. This will certainly be desktop and console only.

Released, see OP for details.

1 Like

UPDATE - due to density map, grass objects that have no mesh will be deleted instead of remained empty.

Thanks for the free Beta release. I have a great use case for this type of shader (especially if I can make it efficient on mobile,etc.)

Getting these errors on startup:

Assets/SurrealGrassShader/SurrealGrassCreator.cs(100,41): error CS1502: The best overloaded method match for `UnityEditor.EditorGUILayout.Popup(UnityEngine.GUIContent, int, UnityEngine.GUIContent[], params UnityEngine.GUILayoutOption[])' has some invalid arguments

Assets/SurrealGrassShader/SurrealGrassCreator.cs(100,96): error CS1503: Argument #3' cannot convertstring[]' expression to type `UnityEngine.GUIContent[]'

Thanks.

I’m not too sure you would want to do this on mobile because of hardware requirements (if you even can). This shader requires DirectX11 for the geometry piece.

As far as your error:
I had a moment last night to take a look at this and could not find a solution. I’ll have more time tonight and will take a look. It really seems like a Unity bug. The “EditorGUILayout.Popup” class has not changed from 2017 to 2018, it’s literally no different as far as I can tell and it works fine for me on 2018. it appears 2017 is not detecting the correct overload. Maybe I can find a way around the issue.

Tried this in unity 5.6 had the same error just // out the line and it worked …well at least spawned the grass but its all white and doesn’t react to the wind. The shader doesn’t throw any error messages so either its a unity version issue or the edited out line is the cause? or my crappy computer (32 bit) and old graphics card are at issue.Im in gamma space and direct x11

Very curious how do u get the grass working like you have. There’s very few batches(under 100) and no saved by batching at all yet 10 of thousands of blades of grass?

As for it being white, make sure your camera is set to “Deferred” rendering and HDR is ON. For the wind, I think the default mat has wind speed set to 0. Try playing with the material settings for that.

Someone correct me if I’m totally wrong on this, but as for the batching, your CPU is not involved with the rendering of this grass at all. All it’s sending to the GPU is a point cloud with minimal information (points and normals). All this point cloud is used for is to tell the GPU where to create the blade of grass. Everything else happens on the GPU, the mesh is created on the GPU. Typically, your model’s mesh has to be sent to the GPU with a lot of extra info, this is where batching comes into play. It’s CPU dependent. With this grass, the mesh is created by the GPU, therefore, not requiring batching.

This is different from GPU instancing, where your CPU copies a mesh and sends it to the GPU instead of instantiating a new mesh (this is what I understand of it anyway). Instancing is still CPU dependent.

GPU geometry shaders are awesome! They are pretty hard to create, but the payoff is huge. In my tutorial, when I add the grass to the terrain (without the density map), that is rendering more than 6 million blades of grass! And you can see my framerate is jumping between ~120 and ~200 (with PBR lighting!) and batching stays around 100.

It wouldn’t be practical to create complex meshes on the GPU, but I figured it would be perfect for grass. The grass in this shader is only 6 triangles per blade of grass.

Hi LSUT you were right on all counts hdr deferred and wind str at 0 so working now nice thx.Really BOSS of you to share this with the community…I have a entry lvl Gforce 610 GC so its not going to perform anything like yours at 4 mil tri’s i think that would be 600k+grass blades my fps was at 2.2 lol.so i think i need to get a better GC when able well and windows 64 and extra ram and just a new computer really.Think a huge benefit with this is that instancing is constantly having to run in update so even the things you don’t see are using up processor power whereas here i dont think thats the case when i looked away from the large area of grass my fps jumped above 200.Very nice work you have done here

The community has a done a lot for me over the past year or so, so I owe it to you guys. Thank you very much. Glad you like it.

Yeah I would advise to get a new PC if you’re wanting to do game development. I would say keep that one though, it’s good for doing lower-end testing.

You could also help the rendering a ton by using Occlusion culling and Camera.layerCullDistances.

If you look in the “Scripts” folder in my project, you will see a script for the camera. This script allows you to set cull distances for every layer. So if you set your grass objects to a layer by themselves, and set the cull distance to like 20-30, it will only render the grass objects within 20-30 meters of the camera. That combined with occlusion culling will help your frame rate tremendously.

Ah didn’t make the texture read/write just went over the original post to see if i missed something.I really want to make my game run on 32 bit as well as 64 machines but unity uses so much memory that u’d have to squeeze everything into a 800mb total size and im aiming for at least 2.5 gigs so yea 64 bit will have to come at some point.I think this grass would be especially great in small tuffs like around wells or houses.At present im using GO’s for my grass.Created them in 60k vert batches works ok for large areas but not so much in a town.

Yeah, the whole reason why I made this shader was because I needed a lawn grass for a neighborhood. But everything I found was either too tall of a grass texture or just didn’t work well at high density. This works well for me though.

UPDATE - I made a change to address the following error:
Assets/SurrealGrassShader/SurrealGrassCreator.cs(100,41): error CS1502: The best overloaded method match for `UnityEditor.EditorGUILayout.Popup(UnityEngine.GUIContent, int, UnityEngine.GUIContent[ ], params UnityEngine.GUILayoutOption[ ])’ has some invalid arguments

Can you guys try this out. The change only effected the SurrealGrassCreator.cs file.

Error is gone in 5.6 .well done!. What did that line do i just commented it out when it had the error but I don’t see any difference with it working?

That’s where you select the “working” layer for the Creator tool. The target object has to be on a layer by itself in order for it to work correctly. The creator works like rainfall, so if it ran with multiple objects on the layer, you would have grass spawn on other objects along with the target object. The dropdown to select the layer in the Creator tool only contains a list of all your empty layers. Once the tool runs, it moves your Target Object back to its original layer and also puts your grass objects on the same layer as the target object.

Great Job! Any idea how to port this to the new HD RenderPipeline?

Not currently. When they release documentation for that, I’ll give it a shot. It’s still a DirectX11 shader, however, in the shader I use some of Unity’s builtin shader functions for the lighting. I would think those could change a bit for HDRP.

Made some updates for you.

  • Added forward version and added shadow support.

Pull request on the git.

2 Likes

Awesome! Thanks for contributing.

2 Likes