top of page
Search
• alexlpc2015

# [Shader Notes] #05 - Pixelating

Hi and welcome to my Shader Notes Series!

This is a comprehensive project with notes about shaders of nearly every common effect included (implemented in Unity). I will explain the key points and theories behind them for you to understand them thoroughly and then enjoy creating your own shaders with proficiency.

Let's start learning together!

## #05 - Pixelating

Difficulty: 3/10

Points covered:

• UV Tiling

Pixelating shaders can have interesting effects in games, such as a postprocessing layer that renders a 3D scene into a pixel graph. It can also serve as a foundation for more advanced shaders.

## Final effect: ### Setup:

Create a new material and attach it to an object.

Prepare the properties and declare them in CGPROGRAM.

```//Properties
_MainTex ("Main Texture", 2D) = "white" {}
_TileTex("Tile Texture", 2D) = "white" {}
_TileSize("Tile Size", Range(0, 100)) = 10
_DisplayModeID("Display Mode", Range(0, 4)) = 0

```

Vertex shader: nothing much to do.

```v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

```

### Process:

Having the tile size defined, we can fist get the sum of tiles along the X and Y axes. Note that _ScreenParams is a built-in unity shader variable. Its x is the width of the render target, and its y is the height.

```float2 TileSum = _ScreenParams / _TileSize;

```

Then we can group the uv coordinates by calling the ceil function and performing a division. Doing this will make all uv values be grouped into discrete segments.

```float2 uv_Mosaic = ceil(i.uv * TileSum) / TileSum;

```

Then, sample the main texture using the tiled uv.

```fixed4 col_Mosaic = tex2D(_MainTex, uv_Mosaic);

```

With the uv set up, we can designate a texture for the repeating pattern of the pixel, such as a circle or a square. We can sample the tile texture using the frac function to generate a repeating uv.

```float2 uv_Tile = frac(i.uv * TileSum);
fixed4 col_Tile = tex2D(_TileTex, uv_Tile);

```

Then, to make the tile texture more versatile, we can sample it from different color channels for different effects.

```switch (_DisplayModeID)
{
case 1:
col *= col_Tile.r;
break;
case 2:
col *= col_Tile.g;
break;
case 3:
col *= col_Tile.b;
break;
case 4:
col *= col_Tile.a;
break;
}

```

Complete!

```Shader "AlexLiu/Pixelate_1"
{
Properties
{
_MainTex ("Main Texture", 2D) = "white" {}
_TileTex("Tile Texture", 2D) = "white" {}
_TileSize("Tile Size", Range(0, 100)) = 10
_DisplayModeID("Display Mode", Range(0, 4)) = 0
}
{
Tags { "RenderType"="Transparent" "Queue" = "Transparent"}
Blend SrcAlpha OneMinusSrcAlpha

LOD 100

Pass
{

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

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

sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _TileTex;
uniform int _TileSize;
uniform int _DisplayModeID;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
float2 TileSum = _ScreenParams / _TileSize;

float2 uv_Mosaic = ceil(i.uv * TileSum) / TileSum;
fixed4 col_Mosaic = tex2D(_MainTex, uv_Mosaic);

float2 uv_Tile = frac(i.uv * TileSum);
fixed4 col_Tile = tex2D(_TileTex, uv_Tile);

fixed4 col = col_Mosaic;

switch (_DisplayModeID)
{
case 1:
col *= col_Tile.r;
break;
case 2:
col *= col_Tile.g;
break;
case 3:
col *= col_Tile.b;
break;
case 4:
col *= col_Tile.a;
break;
}

return col;
}
ENDCG
}
}

}

```