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:

</pre>
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"
"RenderType"="TransparentCutout"
}
LOD 200

CGPROGRAM

#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;
}
ENDCG

}
FallBack "Diffuse"
}
<pre>

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!

chemari

Has one comment to “Grass with wind effect in Unity”

You can leave a reply or Trackback this post.

Leave a Reply

Your email address will not be published.