Hi all.
I am relatively new to shader coding and have been working on a foliage geometry shader for a project. After a few excellent tutorials on the subject i have been trying to implement some lighting and shadows on the geometry from the shader.
Unfortunately i cant seem to work out how to stop the shadow from being obscured by transparent parts of my Albedo texture. I’m hoping it something simple and not going in totally the wrong direction. Any assistance with the would be greatly appreciated. Code attached and picture illustrates these issues in action.
FoliageGeometryShader
//-------------------------- T O - D O ------------------------------
// FIX SHADOWS!!
// ForwardAdd for point and spot lighting (Fire)
// Approximate translucency
// Subsurface scattering
//-------------------------------------------------------------------
Shader "Geometry/LitFoilage"
{
Properties
{
_Color("Color Tint", Color) = (1,1,1,1)
_MainTex("Base (RGB)", 2D) = "white" {}
_GrassHeight("Grass Height", Range(0.01,1)) = 0.25
_GrassWidth("Grass Width", float) = 0.25
_Cutoff("Alpha Cutoff", Range(0,1)) = 0.5
_WindSpeed("Wind Speed", Range(20,300)) = 25
_WindStrength("Wind Strength", Float) = 0.05
_DeformationMap("Deformation Map", 2D) = "green" {}
}
SubShader
{
Tags{ "Queue" = "Geometry" "RenderType" = "Transparent" }
pass
{
Tags{ "LightMode" = "ForwardBase" }
Cull Off
CGPROGRAM
#pragma target 5.0
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#pragma multi_compile_fwdbase
#pragma multi_compile_fog
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
sampler2D _MainTex, _DeformationMap;
struct v2g
{
float4 pos : POSITION;
float3 norm : NORMAL;
float4 uv : TEXCOORD0;
};
struct g2f
{
float4 pos : POSITION;
float3 norm : NORMAL;
float2 uv : TEXCOORD0;
LIGHTING_COORDS(1, 2)
UNITY_FOG_COORDS(3)
};
v2g vert(appdata_full v)
{
v2g OUT;
OUT.pos = v.vertex;
OUT.norm = v.normal;
OUT.uv = v.texcoord;
return OUT;
}
fixed4 _Color;
half _GrassHeight;
half _GrassWidth;
half _Cutoff;
half _WindStrength;
half _WindSpeed;
uniform float4 _LightColor0;
void buildQuad(inout TriangleStream<g2f> triStream, float3 points[4])
{
g2f OUT;
float3 faceNormal = cross(points[1] - points[0], points[2] - points[0]);
UNITY_INITIALIZE_OUTPUT(g2f, OUT);
for (int i = 0; i < 4; i++)
{
OUT.pos = UnityObjectToClipPos(points[i]);
OUT.norm = faceNormal;
OUT.uv = float2(i % 2, (int)i / 2);
TRANSFER_VERTEX_TO_FRAGMENT(OUT);
UNITY_TRANSFER_FOG(OUT, OUT.pos);
triStream.Append(OUT);
}
triStream.RestartStrip();
}
[maxvertexcount(24)]
void geom(point v2g IN[1], inout TriangleStream<g2f> triStream)
{
float3 perpendicularAngle = float3(0, 0, 1);
float3 normal = tex2Dlod(_DeformationMap, IN[0].uv);
float3 v0 = IN[0].pos.xyz;
float3 v1 = IN[0].pos.xyz + normal * _GrassHeight;
float3 wind = float3(sin(_Time.x * _WindSpeed + v0.x) + sin(_Time.x * _WindSpeed + v0.z * 2) + sin(_Time.x * _WindSpeed * 0.1 + v0.x), 0,
cos(_Time.x * _WindSpeed + v0.x * 2) + cos(_Time.x * _WindSpeed + v0.z));
v1 += wind * _WindStrength;
float sin60 = 0.866;
float cos60 = 0.5;
float3 quad1[4] = { v0 + perpendicularAngle * 0.5 * _GrassWidth,
v0 - perpendicularAngle * 0.5 * _GrassWidth,
v1 + perpendicularAngle * 0.5 * _GrassWidth,
v1 - perpendicularAngle * 0.5 * _GrassWidth };
buildQuad(triStream, quad1);
float3 quad2[4] = { v0 + float3(sin60,0,-cos60) * 0.5 * _GrassWidth,
v0 - float3(sin60,0,-cos60) * 0.5 * _GrassWidth,
v1 + float3(sin60,0,-cos60) * 0.5 * _GrassWidth,
v1 - float3(sin60,0,-cos60) * 0.5 * _GrassWidth };
buildQuad(triStream, quad2);
float3 quad3[4] = { v0 + float3(sin60,0,cos60) * 0.5 * _GrassWidth,
v0 - float3(sin60,0,cos60) * 0.5 * _GrassWidth,
v1 + float3(sin60,0,cos60) * 0.5 * _GrassWidth,
v1 - float3(sin60,0,cos60) * 0.5 * _GrassWidth };
buildQuad(triStream, quad3);
}
float4 frag(g2f IN) : COLOR
{
fixed4 c = tex2D(_MainTex, IN.uv) * _Color;
clip(c.a - _Cutoff);
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
fixed atten = LIGHT_ATTENUATION(IN);
fixed lambert = saturate(dot(normalize(IN.norm), lightDirection));
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 lighting = (ambient + lambert * atten) * _LightColor0.rgb;
c = fixed4(c.rgb * lighting, 1);
c.a += _LightColor0.a * atten;
UNITY_APPLY_FOG(IN.fogCoord, c);
return c;
}
ENDCG
}
//----------------- S H A D O W - C A S T E R ---------------------------------------------------------
Pass
{
Name "ShadowCaster"
Tags{ "LightMode" = "ShadowCaster" }
Fog{ Mode Off }
ZWrite On
ZTest LEqual
Cull Off
CGPROGRAM
#pragma target 5.0
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
#include "HLSLSupport.cginc"
struct v2g
{
float3 norm : NORMAL;
float4 uv : TEXCOORD0;
V2F_SHADOW_CASTER;
UNITY_VERTEX_OUTPUT_STEREO
};
struct g2f
{
float2 uv : TEXCOORD0;
V2F_SHADOW_CASTER;
};
v2g vert(appdata_base v)
{
v2g OUT = (v2g)0;
OUT.norm = v.normal;
OUT.uv = v.texcoord;
OUT.pos = mul(unity_ObjectToWorld, v.vertex);
return OUT;
}
#define TRANSFER_SHADOW_CASTER_NOPOS2(opos, vertex) \
opos = mul(UNITY_MATRIX_VP, vertex); \
opos = UnityApplyLinearShadowBias(opos);
void buildQuad(inout TriangleStream<g2f> triStream, float3 points[4])
{
g2f OUT;
UNITY_INITIALIZE_OUTPUT(g2f, OUT);
for (int i = 0; i < 4; i++)
{
OUT.pos = UnityObjectToClipPos(points[i]);
TRANSFER_SHADOW_CASTER_NOPOS2(OUT.pos, float4(points[i], 1.0));
triStream.Append(OUT);
}
triStream.RestartStrip();
}
sampler2D _DeformationMap;
uniform sampler2D _MainTex;
half _GrassHeight;
half _GrassWidth;
half _Cutoff;
half _WindStrength;
half _WindSpeed;
[maxvertexcount(24)]
void geom(point v2g IN[1], inout TriangleStream<g2f> triStream)
{
float3 perpendicularAngle = float3(0, 0, 1);
float3 normal = tex2Dlod(_DeformationMap, IN[0].uv);
float3 v0 = IN[0].pos.xyz;
float3 v1 = IN[0].pos.xyz + normal * _GrassHeight;
float3 wind = float3(sin(_Time.x * _WindSpeed + v0.x) + sin(_Time.x * _WindSpeed + v0.z * 2) + sin(_Time.x * _WindSpeed * 0.1 + v0.x), 0,
cos(_Time.x * _WindSpeed + v0.x * 2) + cos(_Time.x * _WindSpeed + v0.z));
v1 += wind * _WindStrength;
float sin60 = 0.866;
float cos60 = 0.5;
float3 quad1[4] = { v0 + perpendicularAngle * 0.5 * _GrassWidth,
v0 - perpendicularAngle * 0.5 * _GrassWidth,
v1 + perpendicularAngle * 0.5 * _GrassWidth,
v1 - perpendicularAngle * 0.5 * _GrassWidth };
buildQuad(triStream, quad1);
float3 quad2[4] = { v0 + float3(sin60,0,-cos60) * 0.5 * _GrassWidth,
v0 - float3(sin60,0,-cos60) * 0.5 * _GrassWidth,
v1 + float3(sin60,0,-cos60) * 0.5 * _GrassWidth,
v1 - float3(sin60,0,-cos60) * 0.5 * _GrassWidth };
buildQuad(triStream, quad2);
float3 quad3[4] = { v0 + float3(sin60,0,cos60) * 0.5 * _GrassWidth,
v0 - float3(sin60,0,cos60) * 0.5 * _GrassWidth,
v1 + float3(sin60,0,cos60) * 0.5 * _GrassWidth,
v1 - float3(sin60,0,cos60) * 0.5 * _GrassWidth };
buildQuad(triStream, quad3);
}
fixed4 frag(g2f IN) : COLOR
{
SHADOW_CASTER_FRAGMENT(IN)
}
ENDCG
}
}
//FallBack "Diffuse"
}
Unity 20171.1f1 DX11
Interesting resources
World of Zero Grass
Kyle Halladay - Getting Started With Compute Shaders In Unity Great resource for various shading techniques
Using shadow texture to recieve shadows (on grass) - Questions & Answers - Unity Discussions An apparent solution that i cant work out how to implement