• Wang Tile的Shader简易实现


    在使用大面积的平铺纹理时,会导致重复感较强的贴图呈现在画面中。我们可以通过许多方法进行优化,WangTile就是其中一种。

    WangTile(王浩瓷砖)方法通过对每条边标记颜色,并在平铺时将相同颜色的边拼接在一起,最终铺满整个平面。

    参考《GPU Gems2》中的做法,但这里使用一组预先设定好的可循环组合值,以及一个4x4的瓷砖纹理。

    4x4纹理图:

    假设y坐标朝向为从下到上,x坐标朝向为从左到右,则索引(0,0)表示数字16的色块,索引(2,3)表示数字3的色块,以此类推。

    这里首先配置好可循环的组合,他们的x轴和y轴不同的序列为:

    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

    这个序列可以给不同的瓷砖贴图重复使用,我们把这个作为数组传入Shader,数组长度写死为21,其Shader如下:

    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));
                    //使用ddx,ddy参数去除接缝问题
                }
    
                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
            }
        }
    }

    传入数组的csharp脚本如下:

    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);
        }
    }

    最终效果:

    带贴图的效果(未做连续处理):

  • 相关阅读:
    因为这几个TypeScript代码的坏习惯,同事被罚了500块
    如何设计好分布式数据库,这个策略很重要
    线程、多线程和线程池,看完这些你就能全部搞懂了
    章方:征服耶鲁教授的算法大神程序媛
    从零开始学python | 使用Python映射,过滤和缩减函数:所有您需要知道的
    c# 优化代码的一些规则——用委托表示回调[五]
    mysql 重新整理——索引优化explain字段介绍一 [九]
    mysql 重新整理——索引优化explain简单介绍 [八]
    mysql 重新整理——索引简介[七]
    mysql 重新整理——七种连接join连接[六]
  • 原文地址:https://www.cnblogs.com/hont/p/12732570.html
Copyright © 2020-2023  润新知