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!


Full Shader Code:

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
    }
    SubShader
    {
        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
        }
    }

}

Thank you for reading!

5 views0 comments

Recent Posts

See All
Post: Blog2_Post
bottom of page