Simple implementation of Shader for Wang Tile

Keywords: Fragment

When using a large area of tiled texture, it will lead to a strong sense of repetition of the map presented in the screen. We can optimize it in many ways. WangTile is one of them.

The wangtile method marks each edge with a color, and splices the edges of the same color when tiling, and finally paves the entire plane.

Refer to GPU Gems2, but use a set of preset recyclable combination values and a 4x4 tile texture.

 

4x4 texture map:

 

Suppose y coordinate orientation is from bottom to top, x coordinate orientation is from left to right, then index (0,0) represents color block of number 16, index (2,3) represents color block of number 3, and so on.

First of all, the recyclable combinations are configured. Their different sequences of x-axis and y-axis are as follows:

X_seq: 1, 2, 2, 3, 0, 1, 3, 1, 2, 3, 0, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3
Y_seq: 0, 1, 2, 3, 0, 1, 3, 1, 2, 3, 1, 2, 2, 2, 3, 0, 1, 3, 0, 1, 3

 

This sequence can be used repeatedly for different tile maps. We pass this as an array to Shader, and write the array length as 21. The Shader is as follows:

Shader "Unlit/WangTileTesGPU"
{
    Properties
    {
        _TileTex("Tile Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        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 _TileTex;

            uniform float _WangTile_X_Seq[21];
            uniform float _WangTile_Y_Seq[21];

#define MAIN_TEX_TILE_SIZE half2(21, 21)
#define TILE_TEX_SIZE half2(4, 4)

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

            fixed4 SampleTile(half2 uv, half2 index, half2 mainTexTileTexSize, half2 tileTexSize)
            {
                float xIndex = _WangTile_X_Seq[index.x % 21] / tileTexSize.x;
                float yIndex = _WangTile_Y_Seq[index.y % 21] / tileTexSize.y;

                half2 large_uv = frac(uv * mainTexTileTexSize);
                half2 sub_uv = large_uv / tileTexSize;

                return tex2D(_TileTex, half2(xIndex, yIndex) + sub_uv, ddx(uv), ddy(uv));
                //Use ddx,ddy Parameter removal of joints
            }

            fixed4 frag (v2f i) : SV_Target
            {
                half2 sub_uv_index = floor(i.uv * MAIN_TEX_TILE_SIZE);//Index: 1,2,3,4...

                return SampleTile(i.uv, sub_uv_index, MAIN_TEX_TILE_SIZE, TILE_TEX_SIZE);
            }
            ENDCG
        }
    }
}

 

The csharp script of the incoming array is as follows:

public class WangTileGPU : MonoBehaviour
{
    public Material mat;


    void Start()
    {
        float[] index_x_loop = new float[] { 1, 2, 2, 3, 0, 1, 3, 1, 2, 3, 0, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3 };
        float[] index_y_loop = new float[] { 0, 1, 2, 3, 0, 1, 3, 1, 2, 3, 1, 2, 2, 2, 3, 0, 1, 3, 0, 1, 3 };

        mat.SetFloatArray("_WangTile_X_Seq", index_x_loop);
        mat.SetFloatArray("_WangTile_Y_Seq", index_y_loop);
    }
}

 

Final effect:

 

Effect with map (without continuous processing):

Posted by jannoy on Mon, 20 Apr 2020 10:09:16 -0700