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. Code (csharp): 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: Code (csharp): 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 } }