LIGHT_ATTENUATION(i) not working with directional lights

Hey hey,

I am working on a shader and I got a problem with the shadows. It seems like LIGHT_ATTENUATION(i) returns the correct values for point and spot lights, but not for directional lights.

For directional lights it is always 1 → no shadow.

I simplified the shader for the pixellights as much as possible:

struct v2f {
	V2F_POS_FOG;
	LIGHTING_COORDS
	float2 uv : TEXCOORD0;
	float3	lightDirT;
};

uniform float4 _NormalMap_ST;

v2f vert (appdata_tan v)
{
	v2f o;

	PositionFog( v.vertex, o.pos, o.fog );
		
	o.uv = TRANSFORM_TEX(v.texcoord, _NormalMap);

	TANGENT_SPACE_ROTATION;

	o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );
	
	TRANSFER_VERTEX_TO_FRAGMENT(o);	

	return o;
}

uniform sampler2D _NormalMap;

float4 frag (v2f i) : COLOR
{
	float3 normal = normalize(tex2D(_NormalMap, i.uv).xyz * 2 - 1);
		
	half atten = LIGHT_ATTENUATION(i);
	
	i.lightDirT = normalize(i.lightDirT);
	half3 diffuse = dot( normal, i.lightDirT );
	
	diffuse = _ModelLightColor0.rgb * diffuse * atten * 2;
	
	return diffuse;
}

Any ideas? :cry:

Try changing this:

float2 uv : TEXCOORD0;

To this:

float2 uv;

That is, the problem might be that Cg gets confused when allocating interpolators. LIGHTING_COORDS itself declares a variable number of interpolators based on light/shadow type, so you don’t know whether it used 0, 1, 2 or 3 interpolators.

Hey Aras, thanks for your answer. I tried it, but unfortunately it didn’t solve my problem.

Ok, now I reduced the shader even further… here is the full shader:

Shader "testShader" {

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

Category {
	Tags { "RenderType"="Opaque" }

	SubShader {
	
		Pass {
			Name "PPL"
			Tags { "LightMode" = "Pixel" }

						
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#pragma multi_compile_builtin
		
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest 

#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct v2f {
	V2F_POS_FOG;
	LIGHTING_COORDS
};

v2f vert (appdata_tan v)
{
	v2f o;
	
	PositionFog( v.vertex, o.pos, o.fog );
		
	TRANSFER_VERTEX_TO_FRAGMENT(o);	

	return o;
}

float4 frag (v2f i) : COLOR
{
	half atten = LIGHT_ATTENUATION(i);

	half4 result = half4(atten, atten, atten, 1);

	return result;
}

ENDCG
			}
		}
	} 
}

In my test scene I have simply 2 cubes and on light.

Cube1 throws a shadow onto Cube2, which is visible with point/spotlights. But only if Cube1 has a normal shader (normal Diffuse or something).

But with directional lights Cube2 is simply white (independent of Cube1’s shader).

Strange thing… :roll:

178783--6385--$shaderproblem_directional_shadow_365.png

Now I had a look into the “AutoLight.cginc” where the shadowCoords are calculated for the different light types…

Spotlights / Pointlights use v.vertex, so basically something like:

a._ShadowCoord = mul( _World2Shadow, mul(_Object2World,v.vertex) );

And directional lights use o.pos like this, if I get it right:

a._ShadowCoord = unityTransferShadow( a.pos )

float3 unityTransferShadow( float4 hpos )
{
	float3x4 mat= float3x4 (
		0.5, 0, 0, 0.5,
		0, 0.5 * _ProjectionParams.x, 0, 0.5,
		0, 0, 0, 1
	);
	float3 coord = mul(mat, hpos);

	#ifdef SHADER_API_OPENGL
	coord.xy *= 0.5 / _ShadowOffsets[3].xy;
	#endif

	return coord;
}

Hmm, but shouldn’t be o.pos == v.vertex, anyway after PositionFog( v.vertex, o.pos, o.fog );?

Ohhh… I got it. Fallback! :sweat_smile:

I just added Fallback "VertexLit", 2 and now it seems to work.

But why? :o

You’re sure it’s not just falling back to the VertexLit shader, and ignoring yours altogether?

I am sure… the output of my shader is too weird to mix it up! :wink: But perhaps when rendering the shadowmaps, this fallback is needed? Hm, well acually the mesh has a different shader on it. It is rendered with the “RenderWithShader” Method. :roll:

Accually I am “baking” the light on the mesh into its texture each frame, apply some effects and render it on a different mesh on screen.
It works now, but I have some problems with the effects. Unity crashes all the time. I guess I do the GL stuff at the wrong time!?

On LateUpdate I do the following stuff:

  1. Step: RenderWithShader(the shader above) into a RenderTexture A
  2. Step: several fullscreen quad renders with another shader into a RenderTexture B

After that the mesh is rendered normally with my RenderTexture B.

Is LateUpdate ok for that? When are the shadowmaps calculated? I guess I find it in the documentation.

Is there any comprehensive example of RenderTexture usage?

But that will come tomorrow… enough for today. :slight_smile:

Thanks so far!

Fallback to VertexLit is needed because VertexLit contains passes that render object as “shadow caster” (as well as “shadow collector” for screen-space accumulated directional light shadows).

Just a quick aside, here: I thought that Fallback only did anything if none of the subshaders in a shader could run on the card. Does Fallback “VertexLit” work in this case because the shadow passes are looking for subshaders with certain tags?

I just had a look. The VertexLit shader has special passes for that, marked by tags…

Tags { “LightMode” = “ShadowCaster” }

Tags { “LightMode” = “ShadowCollector” }

Yes, I was just wondering whether those tags were important because the mesh is rendered multiple times, using a RenderWithShader() equivalent for shadows.