ShadersRoom - Mix2Textures

先上一个效果图,如下:


MixTextures.gif

大致的实现思路是:
1.根据当前模型坐标的x取值和图片的分割位置比较,x坐标值小于这分割位置时显示第一张图片,大于则显示另外一张;
2.然后在分割点的两边做一个图片渐变的融合即可。

先实现第一步:
1.需要的属性三个:两张贴图和一个分割点的值:

    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _SecondTex ("SecondTex", 2D) = "white" {}
        _TextureMix("TextureMix",range(0,1)) = 0.5
    }

模型到顶点的结构体有两个,模型的顶点坐标和UV

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

顶点到片元函数的结构体需要得到模型空间下的坐标(只需要X,Y两个值)和两个需要采样的UV:

struct v2f
            {
                float2 uv1 : TEXCOORD0;
                float2 uv2 : TEXCOORD1;
                float4 vertex : SV_POSITION;
                float2 localPos : TEXCOORD2;
            };

在顶点函数中需要注意的是,需要将模型空间下的顶点坐标的范围做一下转化,如下面的代码注释:

 v2f vert (appdata v)
            {
                v2f o;
                o.localPos = v.vertex.xy + float2(0.5,0.5);  //v.vertex 范围在(-0.5,0.5)之间,加上0.5取值到0-1
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv1 = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv2= TRANSFORM_TEX(v.uv, _SecondTex);
                return o;
            }

最后在片元函数中输出:

 fixed4 frag (v2f i) : SV_Target
            {
                if(i.localPos.x < _TextureMix)
                {
                    return tex2D(_MainTex, i.uv1);
                }
                else
                {
                    return tex2D(_SecondTex,i.uv2);
                }

完成后可以看到,拖动分割的位置,两张图片会根据这个位置分别显示在面片上:


1.gif

2.继续第二步,需要在分割点上进行两张图片的融合,有一个渐变的过程看起来不那么僵硬:
在最后的片元函数中,先计算出需要 分割点模型位置x 的距离:

                fixed distanceFrontMixPoint = _TextureMix - i.localPos.x;

有了距离后,需要一个渐变的距离y,当距离这个分割点在y的范围内时,两张图片做一个融合显示,我用的是0.2,这个值可以根据自己的喜好调整:

                if(abs(distanceFrontMixPoint) < 0.2)   //取绝对值,因为左右两边都需要显示
                {
                    fixed mixFactor = 1 - (distanceFrontMixPoint + 0.2)/0.4;  //取得混合因子,这个记住就好了,如果修改了显示范围的话,分母需要修改长度的两倍
                    return lerp(tex2D(_MainTex, i.uv1),tex2D(_SecondTex,i.uv2),mixFactor);
                }

完成后可以看到,在滑动分割点时,图片出现了融合,但是有一个问题是在最左边和最右边(也就是0和1的位置)时,显示也出现了融合:


2.gif

什么原因呢,因为当在x在0的位置时,也满足进行混合的条件:

 if(abs(distanceFrontMixPoint) < 0.2) 

同样在1的位置也是一样,所以想要在0和1的位置显示完成的图片,修改一下分割点的范围即可(两边分别增加一个融合的范围,这里例子中是0.2):

_TextureMix("TextureMix",range(-0.2,1.2)) = 0.5

完成后就和开头实现的效果一样啦~~

git仓库:https://github.com/Looooooong/ShadersRoom

最后附上整体的源码:

Shader "ShadersRoom/MixTwoTextures"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _SecondTex ("SecondTex", 2D) = "white" {}
        _TextureMix("TextureMix",range(-0.2,1.2)) = 0.5
    }
    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 uv1 : TEXCOORD0;
                float2 uv2 : TEXCOORD1;
                float4 vertex : SV_POSITION;
                float2 localPos : TEXCOORD2;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _SecondTex;
            float4 _SecondTex_ST;
            half _TextureMix;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.localPos = v.vertex.xy + float2(0.5,0.5);  //v.vertex 范围在(-0.5,0.5)之间,加上0.5取值到0-1
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv1 = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv2= TRANSFORM_TEX(v.uv, _SecondTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed distanceFrontMixPoint = _TextureMix - i.localPos.x;

                if(abs(distanceFrontMixPoint) < 0.2)
                {
                    fixed mixFactor = 1 - (distanceFrontMixPoint + 0.2)/0.4;
                    return lerp(tex2D(_MainTex, i.uv1),tex2D(_SecondTex,i.uv2),mixFactor);
                }
                
                if(i.localPos.x < _TextureMix)
                {
                    return tex2D(_MainTex, i.uv1);
                }
                else
                {
                    return tex2D(_SecondTex,i.uv2);
                }

            }
            ENDCG
        }
    }
}

你可能感兴趣的:(ShadersRoom - Mix2Textures)