Screen projected shader with lighting used to blend between textures

I asked this in Answers already, but I might have a better chance for input here…

I am currently trying to develop a specific look for a game, or rather the technical details for a look I created some 4-5 years ago for a short film I never finished, and I need a rather specific shader for that. I would need the shader to dismiss all UV informations of the models and use the screen coordinates instead. Also I would like to use the lighting to blend between at least three different textures (more would be even nicer), one for illuminated areas, one for half shaded, one for full shadows. The final output would be unlit, so it would show the raw color information of the textures.

I am not asking for a complete shader, I am just asking if anyone knows if it is possible to achieve all of the above and where I could start. The parts that give me the most headache is usng screen coordinates for UVs and blending via the lighting information…basic stuff like how to define properties and what a pass is, I know, but I don’t have any deeper knwledge in either shaderLab or CG…

How many light sources? Are you using Unity Pro? (A single light source is easy, more light sources would probably require Unity Pro or additional scripting.)

Screen coordinates are easy in surface shaders and GLSL shaders but I never figured out how to get them in Cg fragment shaders. (But it’s probably possible.)

Haven’t thought about the number of lightsources, yet, but if it is too hard to do with multiple I think I could get away with only one. I tried to create something using Strumpy’s Shader Editor, but I can’t figure out how to make the shader not use th lighting information for anything but blending the textures. The result is usable, but suboptimal, since the texture I want to use for the illuminated areas is nearly white and gets washed out completely with the additional brightness from the shading. But it has no limitation regarding the number of lightsources, without Pro.

Here is the code, if that helps:

Shader "ScreenProjectedTest"
{
	Properties 
	{
_MainTex("Light", 2D) = "white" {}
_Shadow("Shadow", 2D) = "black" {}

	}
	
	SubShader 
	{
		Tags
		{
"Queue"="Geometry"
"IgnoreProjector"="False"
"RenderType"="Opaque"

		}

		
Cull Back
ZWrite On
ZTest LEqual
ColorMask RGBA
Fog{
}


		CGPROGRAM
#pragma surface surf BlinnPhongEditor  nolightmap vertex:vert
#pragma target 2.0


sampler2D _MainTex;
sampler2D _Shadow;

			struct EditorSurfaceOutput {
				half3 Albedo;
				half3 Normal;
				half3 Emission;
				half3 Gloss;
				half Specular;
				half Alpha;
				half4 Custom;
			};
			
			inline half4 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 half4 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 {
				float4 screenPos;
float3 viewDir;

			};

			void vert (inout appdata_full v, out Input o) {
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;
				
float4 Tex2D1=tex2D(_Shadow,((IN.screenPos.xy/IN.screenPos.w).xyxy).xy);
float4 Tex2D0=tex2D(_MainTex,((IN.screenPos.xy/IN.screenPos.w).xyxy).xy);
float4 Luminance0= Luminance( float4(0.2125,.7154,0.072,0.0).xyz ).xxxx;
float4 Saturate0=saturate(Luminance0);
float4 Multiply0=Tex2D0 * Saturate0;
float4 Add0=Tex2D1 + Multiply0;
float4 Fresnel0_1_NoInput = float4(0,0,1,1);
float4 Fresnel0=(1.0 - dot( normalize( float4( IN.viewDir.x, IN.viewDir.y,IN.viewDir.z,1.0 ).xyz), normalize( Fresnel0_1_NoInput.xyz ) )).xxxx;
float4 Pow0=pow(Fresnel0,float4( 3,3,3,3 ));
float4 Invert0= float4(1.0, 1.0, 1.0, 1.0) - Pow0;
float4 Multiply1=Tex2D1 * Invert0;
float4 Master0_1_NoInput = float4(0,0,1,1);
float4 Master0_3_NoInput = float4(0,0,0,0);
float4 Master0_4_NoInput = float4(0,0,0,0);
float4 Master0_5_NoInput = float4(1,1,1,1);
float4 Master0_7_NoInput = float4(0,0,0,0);
float4 Master0_6_NoInput = float4(1,1,1,1);
o.Albedo = Add0;
o.Emission = Multiply1;

				o.Normal = normalize(o.Normal);
			}
		ENDCG
	}
	Fallback "Diffuse"
}

I don’t know what Strumpy’s Shader Editor is able to do. A way to start with programming surface shaders might be to go through some of the tutorials which were started recently, see the links on this page: Cg Programming/Surface Shaders - Wikibooks, open books for an open world

Little addendum: the last shade doesn’t really do, what I want…it gets the screen projection, but doesn’t do any blending based on the illumination…I got the screen projection down now, I think. I don’t really have enough knowledge of CG to have written this on my own, but it works…all I need now is the lighting…there has to be some way to use the amount of illumination on a model as a mask to blend between two or more textures…

Shader "Skribblez" {
    Properties {
		_MainTex ("Base", 2D) = "white" {}
		_Trans ("Transition", 2D) = "gray" {}
		_Shadow ("Shadow", 2D) = "black" {}
    }
	
    SubShader {
		Tags { "RenderType" = "Opaque" }
		
		CGPROGRAM
		
		#pragma surface surf Lambert
		struct Input {
			float2 uv_MainTex;
			float4 screenPos;
		};
		sampler2D _MainTex;
		sampler2D _Trans;
		sampler2D _Shadow;
	  
		void surf (Input IN, inout SurfaceOutput o) {
			float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
			screenUV *= float2(1, 0.75);
			
			o.Albedo = tex2D (_MainTex, screenUV).rgb;
			o.Emission = tex2D (_Shadow, screenUV).rgb;
		}
		
		ENDCG
		
    } 
    Fallback "Diffuse"
}

In a surface shader you have to use a custom Lighting… function, see http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLightingExamples.html
You would compute the level of lighting and then use it to blend between textures in the custom lighting function.

In a Cg vertex and fragment shader it would be a combination of computing the lighting and blending multiple textures:
http://en.wikibooks.org/wiki/Cg_Programming/Unity/Diffuse_Reflection
http://en.wikibooks.org/wiki/Cg_Programming/Unity/Layers_of_Textures