Looking for feedback in custom shader

I was trying to make a very simple shader for rendering transparent textures on a quad with no ilumination.

I have some experience in GLSL but after struggling for some time I have been unable to use it on my windows builds and decided to try shaderlab. This shader works perfectly but I was wondering if I’m doing something wrong, especially the lighting part as it “feels” a bit strange to me.

Shader "Custom/MobileTransparentNoLight" {
Properties {
	_MainTex ("Base (RGB) Trans(A)", 2D) = "white" {}
	_Color ("Main Color", Color) = (1,1,1,1)
}

SubShader {
	Tags {"Queue"="Transparent" "RenderType"="Transparent"}
	LOD 150
	Cull off
	
	CGPROGRAM
	#pragma surface surf None alpha
	
	half4 LightingNone (SurfaceOutput s, half3 lightDir, half atten) {
	  half4 c;
	  c.rgb = s.Albedo;
	  c.a = s.Alpha;
	  return c;
	}
	
	uniform sampler2D _MainTex;
	uniform float4 _Color;
	
	struct Input {
		float2 uv_MainTex;
	};
	
	void surf (Input IN, inout SurfaceOutput o) {
		fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
		o.Albedo = c.rgb*_Color.rgb;
		o.Alpha = c.a;
	}
	ENDCG
	}

}

I also don’t like all those surface shaders. In the end, they do some horrible assumptions which can slow down your game by a lot.
But guess what, you can define your own vertex and fragment shaders just like in any other shader compiler using #pragma vertex and #pragma fragment
There’s a tiny little tutorial about this riiight here: http://docs.unity3d.com/Documentation/Manual/ShaderTut2.html

Thanks for the tips :smile: Here’s a new version:

Shader "Custom/MobileTransparentNoLight" {
Properties {
	_MainTex ("Base (RGB) Trans(A)", 2D) = "white" {}
	_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
	
	Tags {"Queue"="Transparent" "RenderType"="Transparent"}
	Cull off
	
    Pass {
		Blend SrcAlpha OneMinusSrcAlpha
		
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "UnityCG.cginc"
		
		float4 _Color;
		sampler2D _MainTex;
		
		struct v2f {
		    float4  pos : SV_POSITION;
		    float2  uv : TEXCOORD0;
		};
		
		float4 _MainTex_ST;
		
		v2f vert (appdata_base v) {
		    v2f o;
		    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
		    o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
		    return o;
		}
		
		half4 frag (v2f i) : COLOR {
			
		    half4 texcol = tex2D (_MainTex, i.uv);
		    
		    return texcol*_Color;
		}
		ENDCG
		
    }
}
}

Hope this helps someone else.

Here fixed a bug and made it faster

Shader "Custom/MobileTransparentNoLight"
{

Properties 
{
    _MainTex ("Base (RGB) Trans(A)", 2D) = "white" {}
    _Color ("Main Color", Color) = (1,1,1,1)
}

SubShader
{
    Tags {"Queue"="Transparent" "RenderType"="Transparent"}

    Pass 
    {
     	Blend SrcAlpha OneMinusSrcAlpha
     	Cull off

     	CGPROGRAM

        #pragma vertex vert
        #pragma fragment frag
	#pragma fragmentoption ARB_precision_hint_fastest
        #include "UnityCG.cginc"

        fixed4 _Color;

        sampler2D _MainTex;
        float4 _MainTex_ST;

         struct v2f 
        {
            half4  pos : SV_POSITION;
            half2  uv : TEXCOORD0;
        };

        v2f vert (appdata_base v) 
        {
            v2f o;

            o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    	    o.uv 	= ( _MainTex_ST.xy * v.texcoord.xy ) +  _MainTex_ST.zw;

            return o;
        }


        fixed4 frag (v2f i) : COLOR 
        {
              return tex2D (_MainTex, i.uv) * _Color;
        }

        ENDCG

    }

}

}

To clarify the above post… You made it faster on some machines by adding the fragmentoption ARB_precision_hint_fastest pragma and fixed a bug by moving Cull off to inside the pass. Unless I missed something, all the other changes seem unnecessary.

  1. This line below is totally wrong in original code EDIT : ( i was wrong here didnt see the macro )

o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);

It should be…

o.uv = ( _MainTex_ST.xy * v.texcoord.xy ) + _MainTex_ST.zw;

  1. In original code below uses floats in the varyings, which is unnecessary and slow
    and should be half4 and half2

struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};

  1. The line in the frag shader below, mixes a half and float ( they should all be fixed precision there )
    using half and float is slow, mixing and causing a conversion is even slower.

return texcol*_Color;

  1. original code was returning a half4 in frag shader, which should be fixed4 ( fixed4 is faster )

BTW: I dont think the “fragmentoption ARB_precision_hint_fastest” does anything for vertex frag shaders just put it there by habit :slight_smile:

Original compiled frag shader is 8 cycles and more code

varying highp vec2 xlv_TEXCOORD0;
uniform sampler2D _MainTex;
uniform highp vec4 _Color;
void main ()
{
  mediump vec4 tmpvar_1;
  mediump vec4 texcol;
  lowp vec4 tmpvar_2;
  tmpvar_2 = texture2D (_MainTex, xlv_TEXCOORD0);
  texcol = tmpvar_2;
  tmpvar_1 = (texcol * _Color);
  gl_FragData[0] = tmpvar_1;
}

My compiled code below is 3 cycles and sexy as hell

varying mediump vec2 xlv_TEXCOORD0;
uniform sampler2D _MainTex;
uniform lowp vec4 _Color;
void main ()
{
  gl_FragData[0] = (texture2D (_MainTex, xlv_TEXCOORD0) * _Color);
}

Got a fair bit to learn old chum, should appreciate help wherever you find it, wanted or not. It’s the gracious thing to do :slight_smile:

The dude’s optimisations above are make it over twice as fast. That’s a big gain there, I’d say.

  1. What’s wrong with that line? It’s a macro from UnityCG.cginc that does exactly the same thing:
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
  1. Most of today’s GPUs completely ignore variable precision settings anyways, but fair point, I missed that one.
    3 and 4) The same thing… My target is usually modern GPU, so I often ignore the precision altogether.

“ARB_precision_hint_fastest” is not a Unity thing, it comes from openGL… now THIS actually controls the precision used:

From right here: http://developer.download.nvidia.com/opengl/specs/GL_NV_fragment_program4.txt

Most of the code you see there will be optimized away by the UMD, like all those unnecessary assignments. Even if it wasn’t optimized at all, as far as I know, assignments (even with conversion) are free and don’t cost you a cycle. But yeah, your compiled result is indeed sexier :slight_smile:
So there, I don’t believe there’s any actual performance improvement, but I agree it’s better to be safe.

And don’t get me wrong, I’ll really appreciate if you prove me wrong. Performance means a lot to me… I mourn every lost cycle.

ARB_precision_hint_fastest << I didnt know that was opengl thing i thought it was for unity shader optimizer thingy,I was just testing resulting compiled code always looked the same, so i put it in any shaders i write to be safe. ( good thing i do )

I rarely use the macros in the include files, didn’t catch that one
“o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);”

Id rather code it right, because like on Android you never know what it will get turned into
On my tests on Android and iOS, having a float where it should be a fixed did show a difference in speed.
( Im sure in some cases it dont matter, but others it gets turned into a lot more code )

Yeah, mobile platforms are hungry to cut off as much precision as possible, so they are using variable specific precision.

As I said, you have a point there, if you target mobile GPUs.

I’ve noticed that sometimes using a half2 for a uv leads to some weird texture mapping on iOS devices. You sometimes need the full floating point precision.

Also I’ve heard that casting between two types like a fixed * half leads to some performance degradation not sure if it’s true or not.

The precision is ignored on desktop GPUs though. You can easily prove this by setting a fixed precision variable and overloading it’s range (outside of -2, 2). It still has it’s correct value.