No shadows visible on Transparency Shaders?!!

Hi,

I have some prefabs in my game using the Transparent/Bumped/Diffuse shader, and shadows do not appear on them even though my objects are set to rec. them.

All Transparency shaders are suffering from the same symptom.

Shadows appear fine with just a diffuse/Bumped shader.

Does anyone know of another Transparency shader I can use instead? I have searched the Wiki but nothing there to help.

The white areas of the alpha SHOULD have shadows on it.

Aras? Can you write up an alternative, or point me to where in the shader code I can add something to tell it to pick up shadows ?

Thanks.

1 Like

I know that Transparent/Cutout/Diffuse shader supports shadows.

If it was that easy, they would have done it already. :wink: Shadows with partial transparency is kind of non-trivial, and you won’t really find that in other engines either, that I know of. As Daniel says, you can use the cutout shaders.

–Eric

From my experience so far, I would say that transparency in itself is already not the most trivial thing inside a game engine :wink:

So I guess combining transparency and shadows is asking for trouble (or creating a really big challenge for yourself :wink: ).

Sunny regards,
Jashan

Like others have said, yes, Transparent shaders don’t cast or receive shadows. See trouble shooting shadows page. Transparent/Cutout shaders do cast receive shadows, because essentially they are opaque shaders, with just some pixels being “discarded” from rendering.

The long boring technical reason for this is:

Shadows work this way (simplified):

  1. render ambient lighting and any non-shadowed objects
  2. for each shadow casting light:
    2.1. render shadow map for this light
    2.2. render objects affected by this light

Note that in 2.2 step objects are rendered in arbitrary order; and the “for each light” in 2 step also happens in arbitrary order. The results will still be correct.

Now, enter transparency. The thing about transparency is that objects have to be rendered strictly back-to-front in order to produce correct results. That means in the above loop, neither 2. step can process lights nor 2.2. step can process objects in arbitrary order; everything has to happen back-to-front over the whole scene.

So in the worst case it could happen:

  1. render ambient lighting and non-shadowed objects
  2. for each transparent object, furthest to closest:
    2.1. for each shadowed light affecting this object:
    2.1.1. render it’s shadowmap (potentially whole scene!)
    2.1.2. render object with this shadowmap

In other words, performance here could be horrible. In general shadow case, the scene is rendered up to (light count * constant) counts. In the transparent case, the scene is rendered up to (light count * object count * constant) counts. And it would complicate the hell out of rendering code, which is quite complex already.

2 Likes

Fast foward four years…

We’re up to Unity 3.5 now, and alpha blended objects still can’t receive shadows. Will this be fixed soon?

Aras your response here is clever, but it only addresses the complexity of shadow-casting alpha objects. Shadow-receiving is much easier. In fact, it’s trivial, and doesn’t require any change to the rendering pipeline for generating shadowmaps.

So why can’t alpha objects receive shadows?

2 Likes

+1 for semi-transparent objects receiving shadows

Bump this… It shouldn’t be hard to get transparent with shadow receive… Maybe consider expose cascade shadow map in the future? Would be great to have these available for glass or particle with shadowing effects.

Hi there! That shader from other forum can receive shadow.

Shader "TransparentDiffuse"
{
        Properties
        {
                _Color ("Main Color", Color) = (1,1,1,1)
                _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
        }

        SubShader
        {
                Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
                blend SrcAlpha OneMinusSrcAlpha
               
                LOD 200
                ZWrite Off
                CGPROGRAM
                #pragma surface surf Lambert exclude_path:prepass
               
                sampler2D _MainTex;
                fixed4 _Color;
               
                struct Input
                {
                        float2 uv_MainTex;
                };
               
                void surf (Input IN, inout SurfaceOutput o)
                {
                        fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
                        o.Albedo = c.rgb;
                        o.Alpha = c.a;
                }
                ENDCG
        }
       
       
        SubShader
        {
                Pass
                {
                        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
                        ZWrite Off
                        Blend SrcAlpha OneMinusSrcAlpha
                        Material
                        {
                                Diffuse [_Color]
                                Ambient [_Color]       
                        }
                        Lighting On
                        SetTexture [_MainTex]
                        {
                                Combine texture * primary DOUBLE, texture * primary
                        }
                }
        }

Fallback "VertexLit"
}

But I no idea how this works, because terminating of (Fallback “VertexLit”) part turn of this ability. Manual say “If no subshaders can be run, fallback by used”, but obviously, subhader work fine, and no need to be use fallback. Anyone can explain this behavior?

“RenderType”=“TransparentCutout”
I think it is rendered as cutout,opaque object in fact, try debug it

I think it’s not that, if i change tag to transparent, it’s rendered in same way.

And little different with fixed function.

I’m try do debug, but I’m not familiar with stuff like that.

#pragma multi_compile_fwdbase
#define UNITY_PASS_FORWARDBASE
or
#ifdef SHADOWS_SCREEN

And not understand what’s going on.

Editing the shader like this worked for me (mind you I’m an artist, not a programmer, but this worked). I have a ground grass texture (png) with soft transparency at the edges and opaque in the middle, it has lightmaps generated by unity on UV2, and it correctly receives dynamic hard shadows generated from a directional light and a vertexlit shaded opaque object.

Shader "Custom/transparentwithshadow"
{
    Properties
    {
            _Color ("Main Color", Color) = (1,1,1,1)
            _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    }

    SubShader
    {
            Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="Geometry"}
            blend SrcAlpha OneMinusSrcAlpha
           
            LOD 200
            CGPROGRAM
            #pragma surface surf Lambert exclude_path:prepass
           
            sampler2D _MainTex;
            fixed4 _Color;
           
            struct Input
            {
                    float2 uv_MainTex;
            };
           
            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 "VertexLit"
}
1 Like

Not being able to receive shadows on semi-transparent object is a real problem in 2014 if you want to do some competitive rendering. I think the whole dynamic shadow system definitely needs an update. This screen space shadow collection seems like a very limiting system. Problems with MSAA, very poor shadow filtering, transparency issues…

Looking forward to an update on this engine part.

I agree, we need to do some updates to built-in shadows.

3 Likes

Bump for 5!

Alpha blended objects should at least receive shadow, for example particles in shadow. They don’t need to cast so it would be a nice tweak while things are still going.

1 Like

My issue is the other way around… I don’t care much about the receiving surface (it’s flat and opaque), but I want my casting surface, which is translucent, to cast colored/semi-transparent shadow.

3 Likes

This is close to what I need, but I need to have the entire geometry rendered as transparent, and then apply a shadow collector pass, and I’m not sure how to go about doing it. Is there a way to test if a pixel has a shadow on it, and then change that pixel alpha value to 0? :eyes:

Will there be anything on this for Unity5 launch? Any improvements to 2D Shadows/Shaders?

On PowerVR GPUs (like on iOS devices) you really want to avoid alpha-test (Alpha Cutout) shaders to keep the overdraw optimisation. Therefore it would be really nice if alpha blended geometry could at least receive shadows.

On the other hand, if you seek a solution that will not kill the performance for transparent shadow casters, why not using alpha-cut shaders for those. In that case you could still render everything from front to back or what ever. However the limitation would be that you could not cast semitransparent shadows. And again, on PowerVR devices you will destroy the fancy overdraw optimisation (deferred tile based rendering stuff). But at least for foliage / leafs or fences this should be acceptable.

I don’t get this argument. So on PowerVR GPUs alpha-tested surfaces are slower than opaque surfaces (true). But suggesting to use alpha blended surfaces as a replacement because of this? Bbbbut… alpha blended are just as slow!

i.e. I don’t think it’s some performance gain there from switching from alpha test → alpha blend. Or am I missing something?