In a shader are uniforms shared between vertex and fragment functions?

Hi guys sorry for the newb question, so I’m creating a basic fur shader and the problem I’m faced with is using the value from an uniform integer set in the vertex function in my fragment function.

In the following code _Level is always 0 in the frag function (I know this because my text code allays display black “fur”). However it is correct in the vertex function as when using it to calculate spacing it is correct.

	Properties 
	{
		_MainTex( "Main Texture", 2D ) = "white" {}	
		_MaxHairLength( "Max Hair Length", Float ) = 0.2
		_NoOfPasses( "Number of Passes", Float ) = 5.0
	}
	
	CGINCLUDE
	//includes
	#include "UnityCG.cginc"	
	
	//structures
	struct vertexInput
	{
		float4 vertex : POSITION;
		float4 normal : NORMAL;
		float4 texcoord : TEXCOORD0;
		float4 texcoord1 : TEXCOORD1;
	};
	
	struct fragmentInput 
	{
		float4 pos : SV_POSITION;
		half2 uv : TEXCOORD0;		
		half2 uv2 : TEXCOORD1;	
	};
	
	//uniforms
	uniform float _MaxHairLength;						
	uniform sampler2D _MainTex;
	uniform float4 _MainTex_ST;
	
	uniform sampler2D _SecondTex;
	uniform float4 _SecondTex_ST;
	
	uniform float _NoOfPasses;
	
	uniform float _Level;
	
	//functions
	inline fragmentInput LevelFragmentShader( vertexInput i, int level )
	{
		fragmentInput o;
		_Level = level;
		
		float movementDist = ( _MaxHairLength / _NoOfPasses ) * _Level;		
			
		float4 pos = ( i.vertex + ( i.normal * movementDist ) );			 
		
	    o.pos = mul( UNITY_MATRIX_MVP, pos );		
	    o.uv = TRANSFORM_TEX( i.texcoord, _MainTex );
	    o.uv2 = TRANSFORM_TEX( i.texcoord1, _SecondTex );

		return o;
	}
	
	inline half4 frag( fragmentInput i ) : COLOR
	{
		if( tex2D( _SecondTex, i.uv2 ).a == 0.0f )
		{
			return tex2D( _SecondTex, i.uv2 );
		}
		else
		{
//			half4 texColor = tex2D( _SecondTex, i.uv2 );
//			texColor *= float( 1.0f / _NoOfPasses ) * _Level;
//			
//			return texColor;

			half4 tmp;
			tmp[0] = _Level;
			tmp[1] = _Level;
			tmp[2] = _Level;
			tmp[3] = 255;
			
			return tmp;
		}
	}
	
	ENDCG

I have multiple passes that look like this the second parameter simple incremented.

		Pass
		{	
			CGPROGRAM
			// Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a surface program or both vertex and fragment programs.
			#pragma exclude_renderers gles
			#pragma vertex vert
			#pragma fragment frag					
			
			fragmentInput vert( vertexInput i )
			{
				fragmentInput o = LevelFragmentShader( i, 1 );				
				
				return o;
			}
			
			
			ENDCG
		}

Thanks in advanced :slight_smile:

“Uniform” shader variables are those passed in from the application (i.e. Those that correspond to the “properties” block at the top if your code). If you want a variable declared and set within the shader itself, don’t use the uniform keyword - just
float _Level;

I’m not a shader expert, but from my painful experience with shaders so far I suppose that uniform variables are kind of local: you can assign to them in a vertex program, but the operation only takes effect while the vertex is being processed. The GPU is a parallel machine: several vertices may be processed at the same time by different cores, thus operations that could affect other vertices can’t be allowed (the results would be unpredictable). The parallelism also extends to the fragment program, which isn’t allowed to modify other fragments than the one it’s processing.

The communication between vertex and fragment programs is done by the fragment input structure: the values that each vertex stores in it are interpolated by the GPU according to the fragment position relative to the triangle vertices. It’s a per-fragment operation, thus the values each fragment receives in the input structure may be different from the others. In your case, however, all vertices receive the same value during the pass - if passed in the fragment input structure, the values received by each fragment will be the same. You could for instance use the Z component of uv in order to pass this extra value:

struct fragmentInput 
{
   float4 pos : SV_POSITION;
   half3 uv : TEXCOORD0; // add the Z component to uv    
   half2 uv2 : TEXCOORD1;    
};

...

//functions
inline fragmentInput LevelFragmentShader( vertexInput i, int level )
{
   fragmentInput o;
   // use the argument level instead of variable _Level:
   float movementDist = ( _MaxHairLength / _NoOfPasses ) * level;     
   float4 pos = ( i.vertex + ( i.normal * movementDist ) );        
   o.pos = mul( UNITY_MATRIX_MVP, pos );
   // assign the transformed coordinate only to uv.xy:
   o.uv.xy = TRANSFORM_TEX( i.texcoord, _MainTex );
   // and assign the level value to uv.z
   o.uv.z = level; 
   o.uv2 = TRANSFORM_TEX( i.texcoord1, _SecondTex );
   return o;
}

inline half4 frag( fragmentInput i ) : COLOR
{
   if( tex2D( _SecondTex, i.uv2 ).a == 0.0f )
   {
     return tex2D( _SecondTex, i.uv2 );
   }
   else
   {
     half4 texColor = tex2D( _SecondTex, i.uv2 );
     // get the level value from i.uv.z:
     texColor *= float( 1.0f / _NoOfPasses ) * i.uv.z;
     return texColor;
   }
}

ENDCG

NOTE: The first uv coordinate pair is i.uv.xy, since i.uv.z is the level info.