Using a reflection vector to sample a 2d texture

I’ve been trying to use a reflection vector to sample a 2d texture for cheapo reflections.
I tried getting the necessary vector by reading the related docs but ran into rather
confusing errors:

The related lines are these:

float3 reflectionUVW = IN.worldRefl; //WorldReflectionVector (IN, o.Normal);
float3 finalReflection = tex2D(_ReflectionTexture, reflectionUVW.rg).rgb;

It doesn’t matter which way I get the reflection vector. As soon as don’t try to use the
reflection vector the shader works as expected.

EDIT: I’m using v3.5.

If I set #pragma target to 2.0 instead of 3.0 then the error message changes to

When a variable is not used in calculations related to output, the compiler usually completely removes (or perhaps ignores) the code that created and manipulated the variable. So you can’t be sure that the error is caused in the code that uses the reflection vector, with the test you mentioned. If you output the vector directly as color, you might get more clarity about what causes the error.

Good point. So it all boils down to this:

float4 finalAlbedo = tex2D(_MainTexture, IN.uv_MainTexture);

float4 reflectionUV = float4(WorldReflectionVector (IN, float4(0,0,1,1)), 1);
float4 finalReflection = tex2D(_ReflectionTexture, reflectionUV.rg * _ReflectionTiling);

o.Albedo = finalAlbedo.rgb + finalReflection.rgb;

If I use only finalAlbedo or only finalReflection in the last line then everything is fine. As soon as both of
them are referenced, the errors are back:

Here is the full shader for reference:

Shader "OMD/Coin"
{
	Properties 
	{
		_MainTexture("Diffuse map", 2D) = "gray" {}
		_MainColor("Diffuse color", Vector) = (1,1,1,0)
		_ReflectionTexture("Reflection texture", 2D) = "gray" {}
		_ReflectionTiling("Reflection tiling", Float) = 1
		_ReflectionColor("Reflection color", Vector) = (1,1,1,0)
		//_HighlightAmount("Highlight amount", Float) = 0
	}
	
	SubShader 
	{
		Tags
		{
			"Queue"="Geometry"
			"IgnoreProjector"="False"
			"RenderType"="Opaque"
		}

		Cull Back
		ZWrite On
		ZTest LEqual
		ColorMask RGBA
		Fog{}

		CGPROGRAM
		#pragma surface surf BlinnPhongEditor  vertex:vert
		#pragma target 3.0

		sampler2D _MainTexture;
		float4 _MainColor;
		sampler2D _ReflectionTexture;
		float _ReflectionTiling;
		float4 _ReflectionColor;

		struct EditorSurfaceOutput
		{
			float3 Albedo;
			float3 Normal;
			float3 Emission;
			float3 Gloss;
			float Specular;
			float Alpha;
			float4 Custom;
		};
			
		inline float4 LightingBlinnPhongEditor_PrePass (EditorSurfaceOutput s, half4 light)
		{
			half3 spec = light.a * s.Gloss;
			half4 c;
			c.rgb = (s.Albedo * light.rgb + light.rgb * spec);
			c.a = s.Alpha;
			return c;
		}

		inline float4 LightingBlinnPhongEditor (EditorSurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
		{
			half3 h = normalize (lightDir + viewDir);
			
			half diff = max (0, dot ( lightDir, s.Normal ));
			
			float nh = max (0, dot (s.Normal, h));
			float spec = pow (nh, s.Specular*128.0);
			
			half4 res;
			res.rgb = _LightColor0.rgb * diff;
			res.w = spec * Luminance (_LightColor0.rgb);
			res *= atten * 2.0;

			return LightingBlinnPhongEditor_PrePass( s, res );
		}
		
		struct Input
		{
			float2 uv_MainTexture;
			float3 sWorldNormal;
			float3 viewDir;
			float3 worldRefl;
			INTERNAL_DATA
		};

		void vert (inout appdata_full v, out Input o)
		{
			o.sWorldNormal = mul((float3x3)_Object2World, SCALED_NORMAL);
			float4 VertexOutputMaster0_0_NoInput = float4(0,0,0,0);
			float4 VertexOutputMaster0_1_NoInput = float4(0,0,0,0);
			float4 VertexOutputMaster0_2_NoInput = float4(0,0,0,0);
			float4 VertexOutputMaster0_3_NoInput = float4(0,0,0,0);
		}
			
		void surf (Input IN, inout EditorSurfaceOutput o)
		{
			o.Normal = float3(0.0,0.0,1.0);
			o.Alpha = 1.0;
			o.Albedo = 0.0;
			o.Emission = 0.0;
			o.Gloss = 0.0;
			o.Specular = 0.0;
			o.Custom = 0.0;

			// ALBEDO
			float4 finalAlbedo = tex2D(_MainTexture, IN.uv_MainTexture);
			//finalAlbedo = clamp(lerp((finalAlbedo * _MainColor), _MainColor, _MainColor.a), 0, 64);

			float4 reflectionUV = float4(WorldReflectionVector (IN, float4(0,0,1,1)), 1);
			float4 finalReflection = tex2D(_ReflectionTexture, reflectionUV.rg * _ReflectionTiling);
			//finalReflection = clamp(finalReflection * _ReflectionColor, 0, 64);
			//finalAlbedo = finalAlbedo + finalReflection;

			o.Albedo = finalAlbedo.rgb + finalReflection.rgb;
		}
		ENDCG
	}
	Fallback "Diffuse"
}
struct Input
{
	float2 uv_MainTexture;
	//float3 sWorldNormal;
	float3 viewDir;
	float3 worldRefl;
	INTERNAL_DATA
};

Removing “sWorldNormal” fixes it. Wtf?!

That’s not all that strange.
The error you were getting refers to the struct created by the surface shader, based on your input struct and I believe some other things too. (Add #pragma debug below #pragma target 3.0, and open the compiled shader, to see what happens). That struct is used to move data from vertex to fragment shader, using Semantics (e.g.: TEXCOORD0, POSITION, and others). There is only a limited number of these semantics. So when you removed sWorldNormal, one of these was freed up, and the shader no longer exceeded the limit.

Thank you for the explanation, it makes sense now. So I guess if I run out semantics
then I should start computing stuff in the fragment shader. In this case
Reflect(viewDir, sWorldNormal) or something like that.