Basic Shader using only one channel of a texture (texture splat)

Hi everyone,

I’m just beginning to learn how to write my own shaders, and here’s what i came up with:

Shader "StrumpyShaders/Basic_AlphaMapSplatR - GLSL"
{
Properties 
{
_Color("Color", Color) = (1,1,1)
_AlphaMap("AlphaMap", 2D) = "black"
}
	
SubShader 
{		
Pass
{
Tags {"queue"="Transparent"}
Blend SrcAlpha OneMinusSrcAlpha
Zwrite Off
			
GLSLPROGRAM
			
varying mediump vec2 uv;
				
uniform lowp sampler2D _AlphaMap;
uniform lowp vec3 _Color;
   
#ifdef VERTEX
void main() 
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
uv = gl_MultiTexCoord0.xy;
}
#endif
   
#ifdef FRAGMENT
void main() 
{
vec4 AlphaMap = texture2D(_AlphaMap, uv);
vec4 AlphaChannel = AlphaMap.r;
gl_FragColor = vec4(_Color, AlphaChannel);
}
#endif   
ENDGLSL
}
}
}

So this is a GLSL shader as you can see, and the idea is to use only one channel of an image (here it is the red channel) as alpha map so that i could store up to 4 greyscale alpha textures in only one image.
It worked quite well back on the computer where i wrote this shader but when i came back home to use it on my own one, it doesn’t work anymore and i get the following error :
“No subshaders can run on this graphics card”
and
“GLSL Error in Fragment Shader: Fragment shader failed to compile with following errors: ERROR: 0:37: error(#160) Cannot convert from ‘high float’ to ‘highp 4-component vector of float’ ERROR: error(#273) 1 compilation errors. No code generated at line 0”

Thank you for your help :slight_smile:

Color properties are float4s (or vec4s in GL, I guess).

Also, you’re assigning your alpha channel to be a vec4 - it only needs to be one channel so you need it to be just a float. I think that’s what your error’s about.

I’m not really up on GLSL, but this might work better (bold bits are bits I’ve changed);

Shader "StrumpyShaders/Basic_AlphaMapSplatR - GLSL"
{
	Properties 
	{
		[b]_Color("Color", Color) = (1,1,1,1)[/b]
		_AlphaMap("AlphaMap", 2D) = "black"
	}
		
	SubShader 
	{		
		Pass
		{
			Tags {"queue"="Transparent"}
			Blend SrcAlpha OneMinusSrcAlpha
			Zwrite Off
						
			GLSLPROGRAM
						
				varying mediump vec2 uv;
								
				uniform lowp sampler2D _AlphaMap;
				[b]uniform lowp vec4 _Color;[/b]
				   
				#ifdef VERTEX
				void main() 
				{
					gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
					uv = gl_MultiTexCoord0.xy;
				}
				#endif
				   
				#ifdef FRAGMENT
				void main() 
				{
					vec4 AlphaMap = texture2D(_AlphaMap, uv);
					[b]float AlphaChannel = AlphaMap.r;
					gl_FragColor = vec4(_Color.rgb, AlphaChannel);[/b]
				}
				#endif   
			ENDGLSL
		}
	}
}

Thank you very much farfarer for this quick reply.
It’s working now :slight_smile:

I didn’t see this technique treated often so i’m wondering if it makes sense using it on mobile platforms such as iphone.
Do you think it’s worth doing such optimization ? Wouldn’t there be some drawbacks ?

Really not sure. I’d add a selector for which channel to use, otherwise you’ll only increase your draw-calls by needing one shader per channel used.

But then I’m not sure whether adding in if statements would affect the performance of the shader much.

I guess i should run some test to see how it affects performance. At least i hope it can saves on the texture size part.