最初本来觉得这应该是一个比较简单的问题(哪怕我这种刚学shader的都感觉好像能解决),但是网上好像没有找到这方面的文章,问GPT也全给我乱答写了一堆错误的代码,因此决定自己实现以下并留下此篇笔记供人参考

整体思路

首先我们的目标很明确,我们能够拿到当前变换后的纹理uv坐标,
需要找到在原图中他应该对应的uv坐标)。
变换后变换前

这里我们先将问题给分解,从单独研究x(也就是u)方向的计算
在这里插入图片描述
我们分解为三个区域13区域就是我们九宫格保持不变的区域,1、3在原图是多少宽度那在变换后宽度也还应该是多少。

那么我们开始分区域讨论

当在区域1中

在区域1中的条件
当前与原点的距离=当前图片的宽度Wide×u 如果这个值小于 原图宽度BaseWide×九宫格左边的宽度,Left(自己设的值)那么我们就可以判定当前我们的x方向落在了区域1。

在区域1中映射的计算
已知区域1两边宽度一致,都是BaseWide×Left
当前与原点的距离Wide×u那么映射到原图上,也应该是原图第Wide×u像素的位置,在除以原图的总宽度,BaseWide,就能得到他在原图中的u坐标。

因此得出结论:

u'=u*Wide/BaseWide
当在区域3中

在区域3中的条件:(1-u)Wide<九宫格右边界的距离Right*BaseWide
区域3的映射计算和区域1基本一致,这里直接得出结论:

u'=1-(1-u)*Wide/BaseWide)
当在区域2中

在区域2中的条件:不在区域1,3中,
这个区域的计算相对比较麻烦。
我们的计算思路
在这里插入图片描述

破题的关键

我们破题的关键就在于AB的长度在区域2的占比,和A’B’的长度在区域2的占比应该是一致的。
A距离原点的距离u×Wide,AB的长度=A距离原点的距离-区域1的长度。
因此

AB=u×Wide-BaseWide*Left
BC=Wide-BaseWide*(Left+Right)

因此得出AB在BC中的占比=A’B’在B’C’中的占比=AB/BC

B'C'=BaseWide*(1-Left-Right)
A'B'=BC×占比(也就是AB/BC)

算到这里就已经很明朗了:

A'距离原点的坐标=A'B'+BaseWide*Left
那么新的u'=(A'B'+BaseWide*Left)/BaseWide
最后整理公式:
u'=((u*Wide-Left*BaseWide)/(Wide-(Left+Right)
     *BaseWide)*(BaseWide*(1-Left-Right))+Left*BaseWide)/BaseWide

y(v)方向的计算和x(u)方向的计算是完全一致的,这里就不再赘述了,
值得注意的是y方向的坐标原点是在下方

Shader "Unlit/Tshader" {
    
    Properties {
        _MainTex ("Texture", 2D) = "white" { }// 贴图
        _Wide ("Wide", float) = 1000//当前的宽度(在改变图片大小后需要传入的参数)
        _Hight ("Hight", float) = 259//当前高度(在改变图片大小后需要传入的参数)
        _BaseWide ("BaseWide", float) = 525//贴图的基础宽度
        _BaseHight ("BaseHight", float) = 259//贴图的基础高度
        _Left ("left", Range(0, 1)) = 0.3//九宫格左边界距离
        _Right ("right", Range(0, 1)) = 0.3//九宫格右边界距离
        _Up ("up", Range(0, 1)) = 0.3//九宫格上边界距离
        _Down ("down", Range(0, 1)) = 0.3//九宫格下边界距离
    }
    
    SubShader {
        LOD 100
        Tags { "QUEUE" = "Transparent" "IGNOREPROJECTOR" = "true" "RenderType" = "Transparent" }        
        Pass {            
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            sampler2D _MainTex; 
            float4 _MainTex_ST;       
            float _Wide;
            float _Hight;
            float _BaseWide;
            float _BaseHight;
            float _Left;
            float _Right;
            float _Up;
            float _Down;
            struct appdata {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };
            
            struct v2f {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            
            v2f vert(appdata v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                return o;
            }
            
            fixed4 frag(v2f i) : COLOR {
                float x = i.uv.x;
                float y = i.uv.y;
                //UV映射
                if (x * _Wide < _Left * _BaseWide) {
                    x = i.uv.x * _Wide / _BaseWide;
                } else if ((1 - i.uv.x) * _Wide < _Right * _BaseWide) {
                    x = 1 - (1 - i.uv.x) * _Wide / _BaseWide;
                } else {
                    x = ((i.uv.x * _Wide - _Left * _BaseWide) / (_Wide - (_Left + _Right) * _BaseWide) * (_BaseWide * (1 - _Left - _Right)) + _Left * _BaseWide) / _BaseWide;
                }
                if (y * _Hight < _Down * _BaseHight) {
                    y = i.uv.y * _Hight / _BaseHight;
                } else if ((1 - i.uv.y) * _Hight < _Up * _BaseHight) {
                    y = 1 - (1 - i.uv.y) * _Hight / _BaseHight;
                } else {
                    y = ((i.uv.y * _Hight - _Down * _BaseHight) / (_Hight - (_Down + _Up) * _BaseHight) * (_BaseHight * (1 - _Up - _Down)) + _Down * _BaseHight) / _BaseHight;
                }
                return tex2D(_MainTex, float2(x, y)); // 返回对应UV坐标处的像素值作为最终输出

            }
            ENDCG
        }
    }
}
Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐