Vertex Fragment Shader Structure

Ahmed Schrute
Shader Coding in Unity from a to z
3 min readFeb 17, 2020

This article is a continuum of shader coding articles using Shader lab in Unity, I highly recommend you visit my two articles Understanding Mesh Anatomy in Unity and Shader Variables Datatypes for better understanding of this article.

In Unity, using shader lab, we can create surface shaders or vertex-fragment shaders.

Vertex-Fragment shaders provide more control over the geometry of the objects and the pixel view more than Surface shaders.

Vertex Shaders can be used for coloring vertices or manipulate vertices positions.

Fragment Shaders control per pixel colors and manipulate pixel (relative to the world) position.

The combination of Vertex and Fragment shaders enable a wide spectrum of morphing and manipulating the rendered view of 3d objects.

Vertex Fragment Shader Structure

Shader "VFShader/UnlitTextureShader" {     
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION; // vertex position
float2 uv : TEXCOORD0; // texture coordinate
};
struct v2f
{
float4 vertex : SV_POSITION; // clip space position
float2 uv : TEXCOORD0; // texture coordinate
};

v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}

sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}

Properties block (used to define properties you can set in the inspector)

Properties { 

SubShader Block (defines the rendering pass)

SubShader {

Pass Block (contains the rendering configuration)

Pass{

CG PROGRAM (directive to compile code in between into low-level shader assembly)

Every CG program starts with

CGPROGRAM

and ends with

ENDCG

Compiler directives

#pragma type name

These directives define the functions that are needed to run before the program startup, In our case, we will have two functions (vertex and fragment) therefore we need two compiler directives.

for vertex function

#pragma vertex vert

for fragment function

#pragma fragment frag

Including Unity Builtin Library makes life easier

#include “UnityCG.cginc”

Data Structures for holding our data

//used for the vertex function
struct appdata {}
//used for fragment shader
struct v2f {}

Vertex Function

v2f vert (appdata v) 
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}

This function returns v2f (data type) and takes input v of data type appdata and the name of the function as mentioned in the vertex compiler directive vert.

In this function, we start by declaring a variable of type v2f with the name o as a return variable.

Then, we start assigning values to the two attributes of v2f (vertex and uv).

For the vertex attribute, the main objective is to transform the position to clip space (3d to 2d), we are approaching this by multiplying the vertex position with the model*view*projection matrix.

For the uv attribute, we are passing down the uv mapping data from the mesh data to our v2f data structure. (Understanding Mesh Anatomy in Unity)

Before we move to the fragment function we declare a variable with the data type sampler2D with the name _MainTex same as _MainTex mentioned in the Properties which will hold the Texture we sat in the inspector.

sampler2D _MainTex;

Fragment Function

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}

The fragment function returns a fixed4 which represents the color of the pixel (r,g,b, a). (Shader Variables Datatypes)

frag, the fragment function takes an argument of type v2f which our vertex function returned. (SV_Target is a semantic signifier check the notes below)

In the fragment function, we are using the tex2D to map the texture(_MainTex) to the uv map passed from the v2f i.

Notes:

Shader code runs for every pixel so being efficient is crucial for GPU performance so if you don’t need don’t include it.

This being said, one of the perks you get by Including “UnityCG.cginc” is access to appdata_full, which includes different properties of the geometry.

struct appdata_full
{
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord0 : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
fixed4 color : COLOR;
};

Some extra properties of the V2F data structures that can be used in the fragment function

struct v2f 
{
float4 vertex : SV_POSITION;
float3 normal : NORMAL;
float4 uv1 : TEXCOORD0;
float4 uv2 : TEXCOORD1;
float4 tanget : TANGENT;
float4 color : COLOR;
};

Semantic Signifier

SV_POSITION or NORMAL (all of that syntax following the colon) are called semantic signifiers.

Semantic signifiers are used to make sense of the shader variables for the GPU, for the full description of semantics check the MSDN Shaders Semantics.

--

--