美文网首页
ShadersRoom - Mix2Textures

ShadersRoom - Mix2Textures

作者: 雨天到处晃 | 来源:发表于2019-11-20 12:09 被阅读0次

    先上一个效果图,如下:


    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
    

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

    最后附上整体的源码:

    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

          本文链接:https://www.haomeiwen.com/subject/arinqqtx.html