Foliage Vertex Shader

I’ve started working on a unity scene that’s going to involve a bit of shader, modelling and vfx work.

Today I worked on the foliage vertex shader. Its a pretty simple shader, with a sine wave doing a little wobble and two colour inputs to create a gradated albedo.


I picked up a couple of nice things on how to recalculate lighting and normal information from this tutorial by Hugo Scott-Slade.

Getting correct light info is actually very simple – you just need to add vertex:vert addshadow to your pragma. Initially I had it as vertex: vert and nothing worked, so worth noting that the lack of space is important!

#pragma surface surf Standard fullforwardshadows vertex:vert addshadow

To recalculate the normals, I started with a function that returns the new position that the vertex is going to be in.

I used this function with the vertex plus the tangent, then the vertex plus the bitangent, to approximate what the new tangent and bitanget will be.

Image result for normal tangent bitangent
Image from showing the normal, tangent and bitangent.
Tested the recalculated normal on this metallic sphere – note h ow the specular highlight moves.

The appdata_full struct provided me with the tangent, and I got the bitangent by crossing the tangent and the normal.

Once I had the new tangent and bitangents, I crossed them to get the new normal and set that as the vert’s normal.

//creates new verts to approximate new position for normal recalculation

float3 getNewVertPosition(float3 p, float vertexColor) {
p.x += (sin(_Time.y * _SpeedX + p.y) * _AmountX) * vertexColor;
p.y += (sin(_Time.y * _SpeedY + p.y) * _AmountY) * vertexColor;
p.z += (sin(_Time.y * _SpeedZ + p.y) * _AmountZ) * vertexColor;
return p;

void vert (inout appdata_full v) {

//Change Vert Normal

float3 bitangent = cross(v.normal, v.tangent);
float3 position = getNewVertPosition(v.vertex, v.color.r);
float3 positionTangent = getNewVertPosition(v.vertex + v.tangent * 0.01, v.color.r);
float3 positionBitangent = getNewVertPosition(v.vertex + bitangent * 0.01, v.color.r);

float3 newTangent = positionTangent – position;
float3 newBitangent = positionBitangent – position;

float3 newNormal = cross(newTangent, newBitangent);
v.normal = newNormal;


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s