Hello!
We use the nature pack trees in our project, but their shaders has no lighting and cast no shadow (and for some reason they use double polygons in all foliage, instead of turning off backface cull). So i thought it would be great to combine them with built in transparency diffuse cutout shader, since it looks much more juicy and gets illuminated by the lights. The main reason to combine them is the animation. Their trees is animated by vertex transformation in shader. I don’t know economywise how efficient this solution is, but it works fine and since some maps already contain their trees i think correcting the shader is the right thing to do.
I’ve deal with some simple shaders before, but this seems too complicated to me since these shaders works diffirently. I thought to mess up with passes and subshaders, but this is a mobile game and the solution got to be light and simple, si i’m asking for your help.
First of all - i can’t get which is the best - implement the animation cycle in surface shader, or try to use the lambent lighting model in 2-pass nature pack shader.
Also there’s one thing that disturbs me: i can’t get adequate source of information for shader programming. I mean the scripting in that case is pretty obvious, you have the issue, you google it, read about it and it works. In shader code it just isn’t, and i can’t get any information source that would tell me why that happens and how to fix it. All i get is extensive advices to read books, but since i’m a all-in-one person, i’m gonna blow my head this way, so it would be great if you have some adequate shader manuals and command lists.
So, the shader is
// - Unlit
Shader "atsGrass-Unlit-Wind" {
Properties {
_MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "LightMode"="ForwardBase"}
LOD 100
Cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
half4 _MainTex_ST;
float4 _GrassWind; //is not defined in terrainengine.cginc
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
inline float4 AnimateGrass(float4 pos, float3 normal, float animParams)
{
// animParams stored in color
// animParams = primary factor = blue
// Primary bending
// Displace position
pos.xyz += animParams * _GrassWind.xyz * _GrassWind.w; // controlled by vertex color blue
return pos;
}
v2f vert (appdata_full v)
{
v2f o;
float4 windParams = float(v.color.b);
// call vertex animation
float4 mdlPos = AnimateGrass(v.vertex, v.normal, windParams);
o.pos = mul(UNITY_MATRIX_MVP,mdlPos);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
ENDCG
Pass {
CGPROGRAM
#pragma debug
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
fixed4 frag (v2f i) : COLOR
{
fixed4 tex = tex2D (_MainTex, i.uv);
fixed4 c;
c.rgb = tex.rgb;
c.a = tex.a;
return c;
}
ENDCG
}
}
}
Thanks in advance!
So, for now i’ve managed to get the assets lighted correctly, cast and recieve shadows. But there’s a problem with blending and the shadows won’t move with the leaves, There’s temporary version. Still will appreciate any possible help.
Shader "Wind Trees" {
Properties {
_MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
_Color ("Main Color", Color) = (1,1,1,1)
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}
SubShader {
Pass {
Tags {"Queue"="Transparent+1" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
LOD 200
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
sampler2D _MainTex;
float4 _Color;
float4 _LightColor0;
half4 _MainTex_ST;
float4 _GrassWind; //is not defined in terrainengine.cginc
struct v2f {
float4 pos : SV_POSITION;
float3 lightDir : TEXCOORD0;
float3 normal : TEXCOORD1;
float2 uv : TEXCOORD2;
LIGHTING_COORDS(3, 4)
};
inline float4 AnimateGrass(float4 pos, float3 normal, float animParams)
{
pos.xyz += animParams * _GrassWind.xyz * _GrassWind.w; // controlled by vertex color blue
return pos;
}
v2f vert (appdata_full v)
{
v2f o;
float4 windParams = float(v.color.b);
float4 mdlPos = AnimateGrass(v.vertex, v.normal, windParams);
o.pos = mul(UNITY_MATRIX_MVP,mdlPos);
o.uv = v.texcoord;
o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
o.normal = normalize(v.normal).xyz;
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
fixed4 frag (v2f i) : COLOR
{
float3 L = normalize(i.lightDir);
float3 N = normalize(i.normal);
float attenuation = LIGHT_ATTENUATION(i) * 2;
float4 ambient = UNITY_LIGHTMODEL_AMBIENT * 2;
float NdotL = saturate(dot(N, L));
float4 diffuseTerm = NdotL * _LightColor0 * _Color * attenuation;
fixed4 tex = tex2D(_MainTex, i.uv);
fixed4 c = ((ambient + diffuseTerm) * tex.rgba) * _Color;
return c;
}
ENDCG
}
// Pass to render object as a shadow caster
Pass {
Name "Caster"
Tags { "LightMode" = "ShadowCaster" }
Offset 1, 1
Fog {Mode Off}
ZWrite On ZTest LEqual Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
float2 uv : TEXCOORD1;
};
uniform float4 _MainTex_ST;
v2f vert( appdata_base v )
{
v2f o;
TRANSFER_SHADOW_CASTER(o)
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
uniform sampler2D _MainTex;
uniform fixed _Cutoff;
uniform fixed4 _Color;
float4 frag( v2f i ) : COLOR
{
fixed4 texcol = tex2D( _MainTex, i.uv );
clip( texcol.a*_Color.a - _Cutoff );
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
// Pass to render object as a shadow collector
Pass {
Name "ShadowCollector"
Tags { "LightMode" = "ShadowCollector" }
Fog {Mode Off}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#define SHADOW_COLLECTOR_PASS
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_COLLECTOR;
float2 uv : TEXCOORD5;
};
uniform float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
TRANSFER_SHADOW_COLLECTOR(o)
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
uniform sampler2D _MainTex;
uniform fixed _Cutoff;
uniform fixed4 _Color;
fixed4 frag (v2f i) : COLOR
{
fixed4 texcol = tex2D( _MainTex, i.uv );
clip( texcol.a*_Color.a - _Cutoff );
SHADOW_COLLECTOR_FRAGMENT(i)
}
ENDCG
}
}
}
So, after some experiments i came up with this - surface shader that well lit, animated, casts and recieves shadow. HOWEVER… the shadows is not animated with the leaves. I still don’t know how to solve this. Should i modify the shadow caster(no need to tweak the shadow reciever, it works fine with the non-animated shadows saving some performance) or the main pass. Here’s the code:
Shader "Wind Trees2" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
}
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
LOD 200
Cull Off
CGPROGRAM
#pragma surface surf Lambert alphatest:_Cutoff vertex:vert
#pragma addshadow
sampler2D _MainTex;
fixed4 _Color;
float4 _GrassWind; //is not defined in terrainengine.cginc
struct Input {
float2 uv_MainTex;
float4 pos : SV_POSITION;
};
inline float4 AnimateGrass(float4 pos, float3 normal, float animParams)
{
pos.xyz += animParams * _GrassWind.xyz * _GrassWind.w; // controlled by vertex color blue
return pos;
}
void vert (inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input,o);
float4 windParams = float(v.color.b);
float4 mdlPos = AnimateGrass(v.vertex, v.normal, windParams);
// o.pos = mul(UNITY_MATRIX_MVP,mdlPos);
v.vertex = mdlPos;
// v.vertex.xyz += v.normal * v.vertex.xyz * _Cutoff ;
}
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
Fallback "Transparent/Cutout/VertexLit"
}
If you want some custom shadow caster/reciever you should add after the final ENDCG this:
// Pass to render object as a shadow caster
Pass {
Name "Caster"
Tags { "LightMode" = "ShadowCaster" }
Offset 1, 1
Fog {Mode Off}
ZWrite On ZTest LEqual Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
float2 uv : TEXCOORD1;
};
uniform float4 _MainTex_ST;
v2f vert( appdata_base v )
{
v2f o;
TRANSFER_SHADOW_CASTER(o)
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
uniform sampler2D _MainTex;
uniform fixed _Cutoff;
uniform fixed4 _Color;
float4 frag( v2f i ) : COLOR
{
fixed4 texcol = tex2D( _MainTex, i.uv );
clip( texcol.a*_Color.a - _Cutoff );
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
// Pass to render object as a shadow collector
Pass {
Name "ShadowCollector"
Tags { "LightMode" = "ShadowCollector" }
Fog {Mode Off}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#define SHADOW_COLLECTOR_PASS
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_COLLECTOR;
float2 uv : TEXCOORD5;
};
uniform float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
TRANSFER_SHADOW_COLLECTOR(o)
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
uniform sampler2D _MainTex;
uniform fixed _Cutoff;
uniform fixed4 _Color;
fixed4 frag (v2f i) : COLOR
{
fixed4 texcol = tex2D( _MainTex, i.uv );
clip( texcol.a*_Color.a - _Cutoff );
SHADOW_COLLECTOR_FRAGMENT(i)
}
ENDCG
}
and delete the Fallback line at the end.
Still hope someone can help me find the solution.