Skip to content

Instantly share code, notes, and snippets.

@AlexMerzlikin
Last active April 6, 2022 20:42
Show Gist options
  • Select an option

  • Save AlexMerzlikin/66bec9a472c3f5be8fa3839a7cdfba3e to your computer and use it in GitHub Desktop.

Select an option

Save AlexMerzlikin/66bec9a472c3f5be8fa3839a7cdfba3e to your computer and use it in GitHub Desktop.
A starting point for the Tutorial How To Make An Interactive Grass Shader In Unity @ https://gamedev.center/tutorial-how-to-make-an-interactive-grass-shader-in-unity/
//Grass shader based on tutorial by Roystan: https://roystan.net/articles/grass-shader.html
Shader "Grass"
{
Properties
{
[Header(Shading)]
_TopColor("Top Color", Color) = (1, 1, 1, 1)
_BottomColor("Bottom Color", Color) = (1, 1, 1, 1)
[Header(Blade Properties)]
_BladeWidth("Blade Width", Float) = 0.05
_BladeWidthRandom("Blade Width Random", Float) = 0.02
_BladeHeight("Blade Height", Float) = 0.5
_BladeHeightRandom("Blade Height Random", Float) = 0.3
_BladeForward("Blade Forward Amount", Float) = 0.38
_BladeCurve("Blade Curvature Amount", Range(1, 4)) = 2
_BendRotationRandom("Bend Rotation Random", Range(0, 1)) = 0.2
[Header(Tessellation)]
_TessellationUniform("Tessellation Uniform", Range(1, 64)) = 1
[Header(Wind)]
_WindDistortionMap("Wind Distortion Map", 2D) = "white" {}
_WindFrequency("Wind Frequency", Vector) = (0.05, 0.05, 0, 0)
_WindStrength("Wind Strength", Float) = 1
}
CGINCLUDE
#include "UnityCG.cginc"
#include "Autolight.cginc"
#include "CustomTessellation.cginc"
#define BLADE_SEGMENTS 3
// Simple noise function, sourced from http://answers.unity.com/answers/624136/view.html
// Extended discussion on this function can be found at the following link:
// https://forum.unity.com/threads/am-i-over-complicating-this-random-function.454887/#post-2949326
// Returns a number in the 0...1 range.
float rand(float3 co)
{
return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
}
// Construct a rotation matrix that rotates around the provided axis, sourced from:
// https://gist.github.com/keijiro/ee439d5e7388f3aafc5296005c8c3f33
float3x3 AngleAxis3x3(float angle, float3 axis)
{
float c, s;
sincos(angle, s, c);
float t = 1 - c;
float x = axis.x;
float y = axis.y;
float z = axis.z;
return float3x3(
t * x * x + c, t * x * y - s * z, t * x * z + s * y,
t * x * y + s * z, t * y * y + c, t * y * z - s * x,
t * x * z - s * y, t * y * z + s * x, t * z * z + c
);
}
float2 UV : TEXCOORD0;
float _BendRotationRandom;
float _BladeWidth;
float _BladeWidthRandom;
float _BladeHeight;
float _BladeHeightRandom;
float _BladeForward;
float _BladeCurve;
sampler2D _WindDistortionMap;
float4 _WindDistortionMap_ST;
float2 _WindFrequency;
float _WindStrength;
struct geometryOutput
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
geometryOutput VertexOutput(float3 pos, float2 uv)
{
geometryOutput o;
o.pos = UnityObjectToClipPos(pos);
o.uv = uv;
return o;
}
geometryOutput GenerateGrassVertex(float3 vertexPosition, float width, float height, float forward, float2 uv, float3x3 transformationMatrix)
{
float3 tangentPoint = float3(width, forward, height);
float3 localPosition = vertexPosition + mul(transformationMatrix, tangentPoint);
return VertexOutput(localPosition, uv);
}
[maxvertexcount(BLADE_SEGMENTS * 2 + 1)]
void geo(triangle vertexOutput IN[3] : SV_POSITION, inout TriangleStream<geometryOutput> triStream)
{
geometryOutput o;
float3 pos = IN[0].vertex;
float3 normal = IN[0].normal;
float4 tangent = IN[0].tangent;
float3 binormal = cross(normal, tangent) * tangent.w;
float3x3 tangentToLocal = float3x3(
tangent.x, binormal.x, normal.x,
tangent.y, binormal.y, normal.y,
tangent.z, binormal.z, normal.z
);
float3x3 facingRotationMatrix = AngleAxis3x3(rand(pos) * UNITY_TWO_PI, float3(0, 0, 1));
float3x3 bendRotationMatrix = AngleAxis3x3(rand(pos.zzx) * _BendRotationRandom * UNITY_TWO_PI * 0.5, float3(-1, 0, 0));
float2 uv = pos.xz * _WindDistortionMap_ST.xy + _WindDistortionMap_ST.zw + _WindFrequency * _Time.y;
float2 windSample = (tex2Dlod(_WindDistortionMap, float4(uv, 0, 0)).xy * 2 - 1) * _WindStrength;
float3 wind = normalize(float3(windSample.x, windSample.y, 0));
float3x3 windRotation = AngleAxis3x3(UNITY_PI * windSample, wind);
float3x3 transformationMatrix = mul(mul(mul(tangentToLocal, windRotation), facingRotationMatrix), bendRotationMatrix);
float3x3 transformationMatrixFacing = mul(tangentToLocal, facingRotationMatrix);
float width = (rand(pos.xyz) * 2 - 1) * _BladeWidthRandom + _BladeWidth;
float height = (rand(pos.xyz) * 2 - 1) * _BladeHeightRandom + _BladeHeight;
float forward = rand(pos.yyz) * _BladeForward;
for (int i = 0; i < BLADE_SEGMENTS; i++)
{
float t = i / (float)BLADE_SEGMENTS;
float segmentHeight = height * t;
float segmentWidth = width * (1 - t);
float segmentForward = pow(t, _BladeCurve) * forward;
float3x3 transformMatrix = i == 0 ? transformationMatrixFacing : transformationMatrix;
triStream.Append(GenerateGrassVertex(pos, segmentWidth, segmentHeight, segmentForward, float2(0, t), transformMatrix));
triStream.Append(GenerateGrassVertex(pos, -segmentWidth, segmentHeight, segmentForward, float2(1, t), transformMatrix));
}
triStream.Append(GenerateGrassVertex(pos, 0, height, forward, float2(0.5, 1), transformationMatrix));
}
ENDCG
SubShader
{
Cull Off
Pass
{
Tags
{
"RenderType" = "Opaque"
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 4.6
#pragma geometry geo
#pragma hull hull
#pragma domain domain
#include "Lighting.cginc"
float4 _TopColor;
float4 _BottomColor;
float _TranslucentGain;
float4 frag (geometryOutput i, fixed facing : VFACE) : SV_Target
{
return lerp(_BottomColor, _TopColor, i.uv.y);
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment