Shader "DBV/Kristo/InstancedGrassShader" { Properties { _MainTex("Albedo (RGB)", 2D) = "white" {} _Glossiness("Smoothness", Range(0,1)) = 0.5 _Metallic("Metallic", Range(0,1)) = 0.0 [Space] _ColorA("Color A", Color) = (1,1,1,1) _ColorB("Color B", Color) = (1,1,1,1) [Space] _Size("Size",float) = 1 [Space] _AlphaCutoff ("Alpha cutoff", Range(0,1)) = 0.05 } SubShader { Tags { "RenderType"="Instanced" } LOD 200 Cull Off CGPROGRAM #pragma surface surf Standard vertex:vert //addshadow #pragma multi_compile_instancing #pragma instancing_options procedural:setup lodfade #pragma target 4.5 sampler2D _MainTex; struct Input{ float2 uv_MainTex; }; struct GrassElement { float3 position; float rotation; float size; float colorBlend;//0-1 }; struct custom_appdata { float4 vertex : POSITION; //float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; //float4 texcoord3 : TEXCOORD3; //fixed4 color : COLOR; UNITY_VERTEX_INPUT_INSTANCE_ID }; //Note //StructuredBuffers are good when there are loads of data that needs to be read at different places by different threads //Constant buffers are good when there isent too much data and threads read the same data #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED StructuredBuffer grassBuffer; #endif //https://forum.unity.com/threads/rotating-mesh-in-vertex-shader.501709/ float3x3 YRotationMatrix(float degrees) { float alpha = degrees * UNITY_PI / 180.0; float sina, cosa; sincos(alpha, sina, cosa); return float3x3( cosa, 0, -sina, 0, 1, 0, sina, 0, cosa); } //USAGE: pos.xyz = mul(YRotationMatrix(degrees),pos.xyz); void rotate2D(inout float2 v, float r) { float s, c; sincos(r, s, c); v = float2(v.x * c - v.y * s, v.x * s + v.y * c); } half _Glossiness; half _Metallic; fixed4 _ColorA, _ColorB; float _AlphaCutoff, _Size; void setup () { #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED GrassElement data = grassBuffer[unity_InstanceID]; //Scale the mesh float size = _Size * data.size; unity_ObjectToWorld._11_21_31_41 = float4(size, 0, 0, 0); unity_ObjectToWorld._12_22_32_42 = float4(0, size, 0, 0); unity_ObjectToWorld._13_23_33_43 = float4(0, 0, size, 0); //position the mesh unity_ObjectToWorld._14_24_34_44 = float4(data.position.xyz, 1); //No idea what this does unity_WorldToObject = unity_ObjectToWorld; unity_WorldToObject._14_24_34 *= -1; unity_WorldToObject._11_22_33 = 1.0f / unity_WorldToObject._11_22_33; #endif } void vert (inout custom_appdata v) { #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED GrassElement data = grassBuffer[unity_InstanceID]; //Rotate v.vertex.xyz = mul(YRotationMatrix(data.rotation),v.vertex); #endif } void surf (Input IN, inout SurfaceOutputStandard o) { //Clip the grass fixed4 c = tex2D (_MainTex, IN.uv_MainTex); clip(c.a - _AlphaCutoff); #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED GrassElement data = grassBuffer[unity_InstanceID]; float blend = data.colorBlend; fixed4 col = blend * _ColorA + (1-blend) * _ColorB; #else fixed4 col = _ColorA; #endif // Albedo comes from a texture tinted by color c = c * col; o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }