Shader optimization

Hi,

I made this shader for some simple terrain, and I was wondering if anyone could help me get it working in four texture operations rather than five. I keep running into gotchas when trying to figure it out, but I don’t have much experience writing shaders.

The shader simply mixes two detail textures according to a mask, and has the usual three passes defined.

Shader "Diffuse Two Detail" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Detail1 ("Detail 1 (RGB)", 2D) = "gray" {}
		_Detail2 ("Detail 2 (RGB)", 2D) = "gray" {}
		_Mask ("Mix Mask (A)", 2D) = "gray" {}
	}

	Category {
		Blend AppSrcAdd AppDstAdd
		Fog { Color [_AddFog] }
	
		SubShader {
			// Ambient pass
			Pass {
				Tags {"LightMode" = "PixelOrNone"}
				Color [_PPLAmbient]
				SetTexture [_Detail1] {
					combine texture
				}
				SetTexture [_Mask] {
					combine previous, texture
				}
				SetTexture [_Detail2] {
					combine texture lerp (previous) previous
				}
				SetTexture [_MainTex] {
					combine texture * previous double, texture
				}
				SetTexture [_MainTex] {
					combine previous * primary double, texture
				}
			}
			// Vertex lights
			Pass {
				Tags {"LightMode" = "Vertex"}
				lighting on
				Material {
					Emission [_PPLAmbient]
				}
				SetTexture [_Detail1] {
					combine texture
				}
				SetTexture [_Mask] {
					combine previous, texture
				}
				SetTexture [_Detail2] {
					combine texture lerp (previous) previous
				}
				SetTexture [_MainTex] {
					combine texture * previous double, texture
				}
				SetTexture [_MainTex] {
					combine previous * primary double, texture
				}
			}
			// Pixel lights
			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
	float2	uv[4];
	float3	normal;
	float3	lightDir;
};

uniform float4	_MainTex_ST,
				_Detail1_ST,
				_Detail2_ST,
				_Mask_ST;

v2f vert (appdata_base v)
{
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	o.normal = v.normal;
	o.uv[0] = TRANSFORM_TEX(v.texcoord,_MainTex);
	o.uv[1] = TRANSFORM_TEX(v.texcoord,_Detail1);
	o.uv[2] = TRANSFORM_TEX(v.texcoord,_Detail2);
	o.uv[3] = TRANSFORM_TEX(v.texcoord,_Mask);
	o.lightDir = ObjSpaceLightDir( v.vertex );
	TRANSFER_VERTEX_TO_FRAGMENT(o);
	return o;
}

uniform sampler2D _MainTex;
uniform sampler2D _Detail1;
uniform sampler2D _Detail2;
uniform sampler2D _Mask;

half4 frag (v2f i) : COLOR
{
	half4 texcol = tex2D(_MainTex,i.uv[0]);
	texcol.rgb *= lerp(	tex2D(_Detail1, i.uv[1]).rgb,
						tex2D(_Detail2, i.uv[2]).rgb,
						tex2D(_Mask, i.uv[3]).a);
	
	
	return DiffuseLight( i.lightDir, i.normal, texcol, LIGHT_ATTENUATION(i) );
} 
ENDCG
			}
		}

		// Fallback to vertex lit
		Fallback "VertexLit", 2

	}
}

I worked on this shader today in order to get it running on Geforce cards, which only expose four texture units to the fixed function pipeline. Unfortunately, I’m not sure how to go about writing the vertex lighting pass in a compatible way. All the helper functions in AutoLight are made for PPL. Here’s the shader in its current state:

Shader "Diffuse Two Detail" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Detail ("Detail (RGB)", 2D) = "gray" {}
		_Detail2 ("Detail 2 (RGB)", 2D) = "gray" {}
		_Mask ("Mix Mask (A)", 2D) = "gray" {}
		_Color ("Fallback Tint", Color) = (1,1,1,1)
	}

	Category {
		Blend AppSrcAdd AppDstAdd
		Fog { Color [_AddFog] }
	
		SubShader {
			// Ambient pass
			Pass {
				Tags {"LightMode" = "PixelOrNone"}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
					#pragma fragmentoption ARB_fog_exp2
					#pragma fragmentoption ARB_precision_hint_fastest
					#include "UnityCG.cginc"

					struct v2f {
						V2F_POS_FOG;
						float2	uv[4];
					};

					uniform float4	_MainTex_ST,
									_Detail_ST,
									_Detail2_ST,
									_Mask_ST;

					v2f vert (appdata_base v)
					{
						v2f o;
						PositionFog( v.vertex, o.pos, o.fog );
						o.uv[0] = TRANSFORM_TEX(v.texcoord,_MainTex);
						o.uv[1] = TRANSFORM_TEX(v.texcoord,_Detail);
						o.uv[2] = TRANSFORM_TEX(v.texcoord,_Detail2);
						o.uv[3] = TRANSFORM_TEX(v.texcoord,_Mask);
						return o;
					}

					uniform sampler2D _MainTex;
					uniform sampler2D _Detail;
					uniform sampler2D _Detail2;
					uniform sampler2D _Mask;

					half4 frag (v2f i) : COLOR
					{
						half4 texcol = tex2D(_MainTex,i.uv[0]);
						texcol.rgb *= lerp(	tex2D(_Detail, i.uv[1]).rgb,
											tex2D(_Detail2, i.uv[2]).rgb,
											tex2D(_Mask, i.uv[3]).a);
						texcol.rgb *= _PPLAmbient.rgb * 2.0;
	
						return texcol;
					} 
				ENDCG
			}
			// Vertex lights disabled for now
			// Pass {
			// 	Tags {"LightMode" = "Vertex"}
			// 	lighting on
			// 	Material {
			// 		Emission [_PPLAmbient]
			// 	}
			// 	SetTexture [_Detail] {
			// 		combine texture
			// 	}
			// 	SetTexture [_Mask] {
			// 		combine previous, texture
			// 	}
			// 	SetTexture [_Detail2] {
			// 		combine texture lerp (previous) previous
			// 	}
			// 	SetTexture [_MainTex] {
			// 		combine texture * previous double, texture
			// 	}
			// 	SetTexture [_MainTex] {
			// 		combine previous * primary double, texture
			// 	}
			// }
			// Pixel lights
			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
					float2	uv[4];
					float3	normal;
					float3	lightDir;
				};
				//texture scaling and tiling values (for TRANSFORM_TEX macro)
				uniform float4	_MainTex_ST,
								_Detail_ST,
								_Detail2_ST,
								_Mask_ST;

				v2f vert (appdata_base v)
				{
					v2f o;
					PositionFog( v.vertex, o.pos, o.fog );
					o.normal = v.normal;
					o.uv[0] = TRANSFORM_TEX(v.texcoord,_MainTex);
					o.uv[1] = TRANSFORM_TEX(v.texcoord,_Detail);
					o.uv[2] = TRANSFORM_TEX(v.texcoord,_Detail2);
					o.uv[3] = TRANSFORM_TEX(v.texcoord,_Mask);
					o.lightDir = ObjSpaceLightDir( v.vertex );
					TRANSFER_VERTEX_TO_FRAGMENT(o);
					return o;
				}
				
				uniform sampler2D _MainTex;
				uniform sampler2D _Detail;
				uniform sampler2D _Detail2;
				uniform sampler2D _Mask;
				
				half4 frag (v2f i) : COLOR
				{
					half4 texcol = tex2D(_MainTex,i.uv[0]);
					texcol.rgb *= lerp(	tex2D(_Detail, i.uv[1]).rgb,
										tex2D(_Detail2, i.uv[2]).rgb,
										tex2D(_Mask, i.uv[3]).a);
					texcol.rgb *= 2.0;
	
					return DiffuseLight( i.lightDir, i.normal, texcol, LIGHT_ATTENUATION(i) );
				} 
			ENDCG
			}
		}

		// Fallback to Diffuse Detail
		Fallback "Diffuse Detail", 2

	}
}