Shaderlab rejecting int property

I’ve run into a weird problem while trying to extend the functionality of a shader tutorial and need some understanding as to what’s happening.

When i declare my shader properties all is well until i declare an Int type property, at which point the shader inspector reports the property as a float and not an int, as well as then throwing an undeclared identifier error when i try to use the property.

According to the docs (Unity - Manual: ShaderLab: defining material properties) i should be able to use an Int type in the properties section.

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Post Outline"
{
    Properties
    {
        _MainTex("Main Texture", 2D) = "black"{}
        _SceneTex("Scene Texture", 2D) = "black"{}
        _hltColor("Highlight Color", Color) = (0,1,1,1)
       
        _hltThickness("Highlight Thickness", Int) = 4

    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            sampler2D _MainTex;

            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _MainTex_TexelSize;

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;};
            
            v2f vert (appdata_base v) {
                v2f o;
                
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos = UnityObjectToClipPos(v.vertex);
                
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                
                return o;}
            
           half4 frag(v2f i) : COLOR {
                //arbitrary number of iterations for now (Outline Thickness)
                int thickness = _hltThickness;
                //split texel size into smaller words
                float TX_x=_MainTex_TexelSize.x;
                //and a final intensity that increments based on surrounding intensities.
                float ColorIntensityInRadius;
                //for every iteration we need to do horizontally
                for(int k = 0; k < thickness; k++)
                {
                    //increase our output color by the pixels in the area
                    ColorIntensityInRadius += tex2D(_MainTex, i.uvs.xy + float2((k - thickness / 2) * TX_x, 0)).r / thickness;
                }
                return ColorIntensityInRadius;
            }
            
            ENDCG
        }

        GrabPass{}

        Pass{
            CGPROGRAM
            sampler2D _MainTex;
            sampler2D _SceneTex;
            
            //we need to declare a sampler2D by the name of "_GrabTexture" that Unity can write to during GrabPass{}
            sampler2D _GrabTexture;
            //<SamplerName>_TexelSize is a float2 that says how much screen space a texel occupies.
            float2 _GrabTexture_TexelSize;
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uvs : TEXCOORD0;
            };
            
            v2f vert (appdata_base v)
            {
                v2f o;
                
                //Despite the fact that we are only drawing a quad to the screen, Unity requires us to multiply vertices by our MVP matrix, presumably to keep things working when inexperienced people try copying code from other shaders.
                o.pos=UnityObjectToClipPos(v.vertex);
                //Also, we need to fix the UVs to match our screen space coordinates. There is a Unity define for this that should normally be used.
                o.uvs = o.pos.xy / 2 + 0.5;
                
                return o;
            }
            
            
            half4 frag(v2f i) : COLOR
            {
                //arbitrary number of iterations for now (Outline Thickness)
                int thickness = _hltThickness;
                //split texel size into smaller words
                float TX_y = _GrabTexture_TexelSize.y;
                //and a final intensity that increments based on surrounding intensities.
                half ColorIntensityInRadius = 0;
                //if something already exists underneath the fragment (in the original texture), discard the fragment.
                if(tex2D(_MainTex, i.uvs.xy).r > 0)
                {
                    return tex2D(_SceneTex, float2(i.uvs.x, i.uvs.y));
                }
                //for every iteration we need to do vertically
                for(int j = 0; j < thickness; j += 1)
                {
                    //increase our output color by the pixels in the area
                    ColorIntensityInRadius += tex2D(_GrabTexture, float2(i.uvs.x, 1 - i.uvs.y) + float2(0, (j - thickness / 2) * TX_y)).r / thickness;
                }
                //this is alpha blending, but we can't use HW blending unless we make a third pass, so this is probably cheaper.
                //half4 outcolor=ColorIntensityInRadius*half4(0,1,1,1)*2+(1-ColorIntensityInRadius)*tex2D(_SceneTex,float2(i.uvs.x,i.uvs.y));
                half4 outcolor = ColorIntensityInRadius * _hltColor * 2 + (1 - ColorIntensityInRadius) * tex2D(_SceneTex, float2(i.uvs.x, i.uvs.y));
                return outcolor;
            }
            
            ENDCG
        }
    }
}

Without testing your shader Reahreic my first guess is that you have accidentally missed a define in both or one pass.
Try adding "int _hltThickness; " in after the CGPROGRAM line of each pass.
You may notice that even though “_Maintex” is listed as a property it still needs to be defined as a sampler2D.

Cheers
brn

… 2 ours of starting at it for a simple variable re-declaration… i wouldn’t have through (Shader Novice Here) that it’d need to be declared again after being initially set, but ok.

well that solves that problem, although now i have warnings about using gradient instructions in a loop with varying iterations. (The int is used to set the number of iterations in the loop from the editor, so at least it’s not a run time change that could cause out of range problems.)

Thank you.

1 Like

The properties block is just the definitions for the inspector. Everything else is the actual program.

1 Like

Sorry for the bump. I need to know which datatypes exactly does Unity support for the Properties block.

ATM, I’ve already tried with Float and Int, but, can I use lower precision types, like Byte, or UInt, etc?
The compiler brings me errors with all of these…

I want to pass a multiple choice for a property, but Enum limits me up to 7 values max…

The property is always serialized and treated as a float on the script side, regardless of it being a Float or Int. You can however define the uniform to be whatever type you want and Unity will cast the float value to that data type, assuming the shader API supports it.

1 Like

You can use a script based enum, like those defined in UnityEngine.Rendering, though I’ve never figured out how to drive the enum from a custom script enum. So usually the answer is to use a custom material editor.