To kick things off, I’ve been trying to learn Unity Shader programming. I’m already familiar with node-based shader creation, but I wanted to push myself to learn the code side of things.

I’ve also been collecting a whole bunch of resources to read about shader programming, including websites and Youtube videos, which I’m putting into a playlist and will share soon.

So far I’ve realised that shader programming is no simple thing…

This shader I made is an unlit shader that outputs the worldspace normals, with an optional texture input that is then multiplied with it. I’ll try and break down each line with my understanding of what it is.

// Shader name and location in the Shader selection drop down inside material
Shader "Unlit/WorldSpaceNormalTexture"
{
	// List of visible properties that can be edited in a material
    Properties
    {
        // _Tint ("Tint", Color) = (0,0,0,1)
        // Property name in shader ("Property name in editor", type) = "default value"
        // Type "2D" is a 2D texture input
        // Colours like "white" can be put in, but also (R,G,B,A) values
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
    	// 'RenderType' tag categorizes shaders into predefined groups
        // e.g. an opaque shader, or an alpha-tested shader etc
        Tags { "RenderType"="Opaque" }
		
        // Start of pass, multiple can be used but costs more
        Pass
        {
        	// Starts the shader
            CGPROGRAM
            
            // You must list & name functions here first
            #pragma vertex vert
            #pragma fragment frag

			// Include a library for functions and things you can use
            #include "UnityCG.cginc"

            // Mesh data: vertex position, vertex normal, UVs, tangents, vertex colours
            struct vertexInput
            {
            	// POSITION is for the vertices position from origin
                float4 vertex : POSITION;
                // TEXCOORD0 is for the 2D UV coordinates
                float2 uv0 : TEXCOORD0;
                // NORMAL (or TEXCOORD1) is for the normal direction
                float3 normal : NORMAL;

            };

			// Outputs the vertex data 
            struct vertexOutput
            {
                float4 vertex : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                float3 normal : NORMAL;
            };

            // Variables from the exposed properties
            sampler2D _MainTex;
            float4 _MainTex_ST;


            // Vertex Shader
            vertexOutput vert (vertexInput v)
            {
                vertexOutput o;
                // UnityObjectToClipPos is from the library, it makes the position correct on a camera basically.
                o.vertex = UnityObjectToClipPos(v.vertex);
                // TRANSFORM_TEX basically scales the texture to the right size
                o.uv0 = TRANSFORM_TEX(v.uv0, _MainTex);
                o.normal = v.normal;

                return o;
            }

            // Fragment shader
            // SV_Target semantic.. i am unsure about.. 
            fixed4 frag (vertexOutput o) : SV_Target
            {

                float2 uv = o.uv0;

                // The normal range is -1 to 1, so i *0.5 and added 0.5, to remap to 0 - 1, so we can view all the colours
                // UnityObjectToWorldNormal, also from the library converts Object space normals to world space
                float3 normal = (UnityObjectToWorldNormal(o.normal.xyz) * 0.5) + 0.5;
                fixed4 texturecolor = tex2D(_MainTex, uv);
                
                // Changes a float3 to a fixed4 with the wrapper? brackets
                fixed4 colouroutput = fixed4(normal.xyz,0) * texturecolor;
                
                // .xxx puts x in all channels = greyscale instead of red
                return (colouroutput);
            }
            // Ends the shader
            ENDCG
        }
    }
}

So it’s a lot of stuff, and some things I cant currently explain but.. maybe soon!