Grass with wind effect in Unity

No matter the kind of game you are working in, if you are modeling a 3D outdoor scenary, sooner or later you will need to drop some grass or bushes in it. In this mini tutorial I will show you how to create a low poly, 3d, animated bush, that will your landscape more alive at a very low cpu cost.

You can find many tutorials (and more complex) out there, actually I learned from them, but took me a several days to comprehend how the basic of the shaders work, and many hours tweaking parameters to get them to work properly in Unity. Shaders are a very complex matter, and I feel that I just grasped the tip of the iceberg.

What we will do is to create a bunch of vertical planes, and asign them a transparent texture, so it will look like a real 3d bush. This is a common and cheap trick used in videogames, so probably you have seen that previously in many of them.

First of all, you need to model the bush. In my case I use blender. Create several vertical planes, and play with the scale and rotation to get an even distribution. Remember that in Unity, you can only see one face of the plane depending on the normal alignment. So to make sure you can see the both faces, you just select all the planes (press A), and duplicate them (Shift+D and enter), now in the faces menu, click on flip normals.

Now we find a texture of a bush with a transparent background. I used this:

Import your blender file in Unity. Import also the bush texture, make sure you mark “Alpha is transparency“.

Now we are going to create a custom shader that will do two things: first will show our texture and keep the alpha transparency. And second, it will manipulate the vertex of the mesh to create a oscillating effect to simulate wind.

In your materials folder create a new shader->Standar surface shader. I called mine GrassWind. This is the code:

Shader "Custom/WindGrass" {
Properties {
// Surface shader parameters
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0

// Wind effect parameteres
_WindFrecuency("Wind Frecuency",Range(0.001,100)) = 1
_WindStrength("Wind Strength", Range( 0, 2 )) = 0.3
_WindGustDistance("Distance between gusts",Range(0.001,50)) = .25
_WindDirection("Wind Direction", vector) = (1,0, 1,0)

SubShader {
Tags { "Queue"="Transparent"
LOD 200


#pragma surface surf Standard vertex:vert alpha:fade
//#pragma target 3.0

sampler2D _MainTex;

struct Input {
float2 uv_MainTex;

half _Glossiness;
half _Metallic;
fixed4 _Color;

half _WindFrecuency;
half _WindGustDistance;
half _WindStrength;
float3 _WindDirection;

// our vert modification function
void vert( inout appdata_full v )
float4 localSpaceVertex = v.vertex;
// Takes the mesh's verts and turns it into a point in world space
// this is the equivalent of Transform.TransformPoint on the scripting side
float4 worldSpaceVertex = mul( unity_ObjectToWorld, localSpaceVertex );

// Height of the vertex in the range (0,1)
float height = (localSpaceVertex.y/2 + .5);

worldSpaceVertex.x += sin( _Time.x * _WindFrecuency + worldSpaceVertex.x * _WindGustDistance) * height * _WindStrength * _WindDirection.x;
worldSpaceVertex.z += sin( _Time.x * _WindFrecuency + worldSpaceVertex.z * _WindGustDistance) * height * _WindStrength * _WindDirection.z;

// takes the new modified position of the vert in world space and then puts it back in local space
v.vertex = mul( unity_WorldToObject, worldSpaceVertex );


void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;

FallBack "Diffuse"

This is where the magic happens, basicly what we do is moving horizontally the vertexes according to a sinusoidal function, so we get the illusion of an oscillation. We also do it according to its Y coordinate, so the bottom vertexes are not moving. And at last, we introduce a X coordinate, to make the effect of a wind gust moving along the scenery, if we dont do that, all the bushes will move at the same time, and that doesn’t look real.

Once we have the shader, create a new material GrassWind and select the shader we just created. You should see now the different parameters of the shader, so in Albedo, select the bush texture we created before. And remember to mark “Enable GPU instancing” to avoid weird stuff happening in the render.

Now you can assign this material to your bush mesh and play with the different parameters to find the animation that suits you more. You can animate it by clicking the little play icon over the material preview at bottom right.

So you are ready now to create a prefab with your bush and place it now and here, remember to rotate and scale them randomly so it will look more natural. Have fun!


6 comments to “Grass with wind effect in Unity”

You can leave a reply or Trackback this post.
  1. Goblin - December 12, 2019 Reply

    Hi, I think the shader doesn’t work well. Plants also move at the base.

  2. Stilisthome - March 31, 2020 Reply

    You can enable the Billboard A textured 2D object that rotates as it, or the Camera, moves so that it always faces the Camera. More info See in Glossary property of a textured quad so that it automatically faces the camera. This is a very common way to achieve a good grass effect in game development.

  3. cby - April 11, 2020 Reply

    The wind effect is working but sadly the alpha isn’t. There is a black transparent box around the grass, the alpha doesn’t seems to work in 2018 unity.

  4. John - May 29, 2020 Reply

    Thanks for providing this, but I’m wondering if I’m doing things wrong, as I cannot replicate the effect you show in your video. As mentioned in another comment, it doesn’t seem anchored to the base. It almost seems like the pivot point is far below the base of the grass, such that the entire grass texture moves far from its original position. Any advice would be appreciated. Thanks!

    • chemari - June 3, 2020 Reply

      Sorry for the late answer John.
      Keep in mind that this shader is working in local coordinates. So make sure the object you are applying the shader is not rotated in unity.
      If you created the plane in Unity and rotated it later, the coordinates will be wrong and the animation wont look anchored to the bottom.
      You can check this by applying this shader to a cube and trying to rotate it later.
      I hope this helps!

Leave a Reply

Your email address will not be published.