- Home /
Add transparency to sprite shader with cast shadows and receive shadows and lighting
Alright... I give up and I preface this with saying I know next to nothing about writing shaders. The following is a frankenstein conglomerate of some examples I found people post. I need a shader for my 2.5D game for sprites that casts and receives shadows, has ZWrite On, is affected by lighting, and allows transparency
Right now, it seems to do all but allow transparency.
Any help is appreciated!
Shader "Sprites/Bumped Diffuse with Shadows"
{
Properties
{
[PerRendererData] _MainTex ("Color (RGB) Alpha (A)", 2D) = "white"{}
//_BumpMap ("Normalmap", 2D) = "bump" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
_Cutoff ("Alpha Cutoff", Range (0,1)) = 0.5
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
LOD 300
Cull Off
Lighting On
ZWrite On
Fog { Mode Off }
CGPROGRAM
#pragma surface surf Lambert alpha vertex:vert addshadow alphatest:_Cutoff
#pragma multi_compile DUMMY PIXELSNAP_ON
sampler2D _MainTex;
sampler2D _BumpMap;
fixed4 _Color;
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
fixed4 color;
};
void vert (inout appdata_full v, out Input o)
{
#if defined(PIXELSNAP_ON) && !defined(SHADER_API_FLASH)
v.vertex = UnityPixelSnap (v.vertex);
#endif
v.normal = float3(0,0,-1);
v.tangent = float4(1, 0, 0, 1);
UNITY_INITIALIZE_OUTPUT(Input, o);
o.color = _Color;
}
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
o.Albedo = c.rgb;
o.Alpha = c.a;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
Fallback "Transparent/Cutout/Diffuse"
}
It depends what kind of transparency you need. If you don't require any areas to be semi-transparent, then using alphatesting / clipping will allow for this. Otherwise, there isn't that much we can do. The way transparency is drawn, receiving shadows, depth and the such aren't compatible. It is true that by using multiple passes you can receive shadows but this comes with its own issues. It does appear (from your fallback) that you want to do alphatesting. In which case, you should remove the "alpha" from the surface shader declaration. Also, you will want to remove the shader from the transparent queue, and put it in:
Tags { "Queue"="AlphaTest" }
Along with the other tags.
So it's pretty much impossible to have a semi-transparent diffuse shader with shadows? Explains why I've been having so much trouble finding it.
Answer by tanoshimi · Jun 06, 2016 at 04:46 PM
This is a hard problem to solve (and it's not specific to Unity). I'll try to explain my understanding of it:
The shadowing process which Unity follows is firstly to loop through each light and calculate the shadows it casts to create a shadow "buffer" in screenspace. Then, when objects that receive shadows are rendered, they sample from this buffer, again in screenspace. The assumption is therefore that any given pixel drawn to the screen corresponds to a unique position in the world, and this is what the shadow buffer uses to represent whether a point lies in shadow or not.
The problem is that, as soon as you introduce semi-transparent objects, this assumption no longer holds true: any given pixel when seen through a semi-transparent object is a composite of at least two objects at different depths, but the shadow buffer is unable to represent this. In the rendering pipeline, the problem is solved by transparent objects being sorted furthest to closest before rendering to make them appear correct, but the shadowmap processes lights in an arbitrary order - no sorting is done.
The reason why Transparent/Cutout shaders work is because they have no transparency, as such - they're opaque but with some discarded fragments.
It is possible to fix, but it's not on the current Unity roadmap, and the performance might be horrible. Aras has said that it certainly won't be coming any time in the next few months. See here for a full discussion.
there's an option for "shadows only" on a sprite. so theoretically, couldn't i duplicate every sprite, have one set up for shadows only, and then have one set up with the sprites-diffuse shader? sounds terribly inefficient
"there's an option for "shadows only" on a sprite" Is there? What version of Unity are you using? To my knowledge, that option is hidden for a sprite renderer (except for in Debug view) specifically because the standard sprite shader doesn't support shadows. If you use your own shader then you can of course enable this option via script or using debug mode, but you won't get shadows other than as a transparent cutout. Would love to be proved wrong if you have different results though!
yes i was talking about in debug. under "Cast Shadows" there's a "Shadows Only" option.
Your answer
Follow this Question
Related Questions
Is it possible to avoid writing to certain g-buffers? 1 Answer
Shader issue with a 170 upper angle 0 Answers
UnityObjectToClipPos is inverted? 0 Answers
post shader: reconstruct worldspace plane coordinates 1 Answer
Shader Color 1 Answer