温馨提示:本文只是一篇入门聊天,不涉及代码教程,看不懂代码就跳过,没关系!
一、什么是uv
1、uv其实就是一个二维坐标系啊,就俩轴,就跟xy轴一样。
那为什么不叫xy,反而叫uv呢?
不知道,应该是为了跟空间坐标系xyz区别开来,以免在工作流程中产生误解吧吧吧。
2、uv坐标用于采样贴图,然后把它映射到模型表面。
图是网上找的,如果侵权了我立马删对不起对不起对不起
3、类比xOy直角坐标系,在unity shader中,uv坐标原点也是在左下角(0,0)的位置的。
注意,不同的shader体系,它们设定的原点坐标是不一样的,比如dirctX的原点就在左上角。
用这个uv贴图比较方便观察。记得再ps里转化成.tga格式再使用)
4、uv坐标的原始范围都是[0,1]。
二、uv变换
1、为什么是uv变换?
啊?为什么是uv变换,而不是贴图变换呢?
因为,贴图是不会变换的!
uv采样本质上就是用一个横向范围[0,1]和纵向范围[0,1]的直角坐标系去采样一张图,然后映射到模型表面上。Shader着色器通过各种花里胡哨的运算改变uv坐标,从而改变采样范围(内容),从而使我们看到贴图变形。
嗯……就好像我们拿望远镜观察星空,星星(贴图)当晚不会变,只有我们移动望远镜(uv坐标),我们看到的星星才会不同。
甚至,我们还可以在望远镜上装哈哈镜(shader),这样看到的星星也会不同。
或者,你可以想象你坐在火车上,窗外的风景就是贴图,窗就是uv坐标。风景不会跑,只有咱们的窗户在跟着车平移。
2、加减(平移)
举例,uv + (0.1, 0.1)
i.uv += float2(0.1, 0.1);
看起来贴图向左下角偏移了。
(会不会有同学没反应过来,为什么不是偏移一整格呢?因为这图是8×8格的所以要+0.125才能偏移一整格哈哈哈)
为什么呢?
一开始,原点(0,0)采样的是H1左下角明黄色的点
Uv坐标经过加减变换之后,原点(0,0)变成了(0.1, 0.1),坐标轴整体向右上角移动了,此时采样的点是H1接近右上角的明黄色的点.
以此类推别的坐标点(可以参考上面的坐标轴偏移示意图)
得到的采样结果就是这样啦。
所以,其实不是贴图向左下角偏移了,而是坐标向右上角偏移了。
嗯呃呃呃有一点相对论地拗口。
注意,贴图是循环平铺的。也就是说,原本边缘处(1, 1)的坐标点,经过加减变换之后变成了(1.1, 1.1),超出了贴图大于0小于1的坐标范围,但是,由于贴图是循环的,所以(1, 1)–加0.1→(1.1, 1.1)处采样的点与(0.1, 0.1)处采样的点是一致的!
但如果我把wrap mode网络循环模式从默认的Repeat循环改为Clamp钳制(超出范围的颜色,则与边缘颜色保持一致,将范围钳制在[0, 1]之间),那么,(1, 1)–加0.1→(1.1, 1.1)处采样的颜色就与(1, 1)处的颜色是一致的。而且(0.9, 0.9)–加0.1→(1, 1),同样也采了(1, 1)处的颜色。
同理,如果uv - (0.1, 0.1),就是将整个坐标轴向左下角移动,那么采样的范围就会向左下角偏移,采样的结果看起来就是贴图向右上角移动了。
嘿嘿。
2、乘除(缩放)
坐标轴乘以2。
i.uv *= float2(2, 2);
贴图以坐标原点(0,0)为中心缩小了2倍
啊…看得我自己都快眼花了……
然后,还是用刚才相对的思想去分析。
贴图是永远不会变的!只有坐标轴变大了两倍。uv坐标的范围变成了[0,2],贴图的范围是[0,1],由于贴图是循环平铺的,在[0,2]里就能出现两次[0,1],在22的坐标系里,就可以出现4个11,也就是4张贴图。
就这样,看起来,贴图缩小了!
同理,坐标轴除以2,贴图放大2倍
Unity内置了变换函数TRANSFORM_TEX,用于计算uv变换。在参数面板调整_MainTex_ST的tilling数值,结果也是如此
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
tilling值越大,就缩小;值越小,就变大。
3、 加减和乘除【待订正】
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
Unity内置的变换函数TRANSFORM_TEX等价于
fixed2 uv = i.uv * fixed2(_ScaleX, _ScaleY) - fixed2(_OffsetX, _OffsetY); // **先缩放,后移动**
half4 var_MainTex = tex2D(_MainTex, uv);
为什么是先缩放后移动?
【↓ 我暂时讲不清楚这部分,留个坑,以后填 ↓】
因为顶底变换的底层数学逻辑 总是 以最原始的原点(0, 0)为操作锚点的。如果先移动,再缩放,就会变成这样…
o.uv = v.uv + float2(0.5, 0.5);
o.uv *= sin(_Time.y) * 0.5 + 1;
用更玄学的话讲,就是,矩阵相乘不满足交换律…
【↑ 以后一定填呜呜 ↑】
Q:如果想让贴图以(0.8, 0.7)为中心放大3倍,公式怎么写?
我们用一个新的10*10棋盘格贴图,红点就是目标中心。
A:o.uv = v.uv / 3 + float2(0.8, 0.7) * (3-1)/3 ;
三、搞点事情吧——uv动画
1、基础动画
最基础的,就是用全局变量_Time时间单改变其中一个数值,让贴图动起来。
我们举例,改变offset偏移量。
i.uv += float2(_Time.x, 0);
动起来啦!就像坐在火车上看风景的比喻一样。
题外话,为什么是_Time.x捏?其实_Time有xyzw的,x是每秒+0.05,y是每秒+1,z是每秒+2,w是每秒+3。在这就不一一给大家截gif啦,亲自去试试吧很好玩的。
另外,为了防止因时间过长导致数据溢出,我们一般会给_Time取余。
i.uv += float2(frac(_Time.x), 0);
用函数frac()和运算符%都可以。
i.uv += float2(_Time.x % 1, 0);
如果我改变的是纵向的v轴呢,再换一张贴图呢?
看!是瀑布?是河流?
2、帧动画
帧动画的制作思路就是把uv坐标缩小,再移动到贴图中的第一帧,然后用floor向上取整实现逐帧“跳动”。
那岂不是一个材质只能播放一个动画了?
No,你也可以再次把uv坐标放大,这时候就可以播放多个动画了,只是,每个动画的播放进度都不一样。
四、高级变换
1、极坐标变换
就是把直角坐标系变成极坐标系,就是把正方形变成圆形。庄懂老师说,这个一般用于实现角色脚下的法阵特效,比美术画出来的好使多了。
在这里附上庄懂老师的代码:
// 直角坐标转极坐标方法
float2 RectToPolar(float2 uv, float2 centerUV) {
uv = uv - centerUV; // 将原点偏移到中心位置
float theta = atan2(uv.y, uv.x); // atan()的值域为[-π/2, π/2],只能画半圆,一般不用; atan2()的值域为[-π, π],刚好画出一个完整的圆
float r = length(uv);
return float2(theta, r);
}
// 输出结构>>>像素
half4 frag(VertexOutput i) : COLOR {
// 直角坐标转极坐标
float2 thetaR = RectToPolar(i.uv, float2(0.5, 0.5));
// 极坐标转纹理采样UV
float2 polarUV = float2(
thetaR.x / 3.141593 * 0.5 + 0.5, // θ从[-π, π]映射到[0, 1]
thetaR.y + frac(_Time.x * 3.0) // r随时间流动
);
// 采样MainTex
half4 var_MainTex = tex2D(_MainTex, polarUV);
// 处理最终输出
half3 finalRGB = (1 - var_MainTex.rgb) * _Color;
half opacity = (1 - var_MainTex.r) * _Opacity * i.color.r;
// 返回值
return half4(finalRGB * opacity, opacity);
}
因为特效一般是bulingbuling的并且涉及透明度,所以这里有用到AD透明度叠加shader文章来源:https://www.toymoban.com/news/detail-523261.html
原视频:庄懂的技术美术入门课(美术向)-直播录屏-第18课_哔哩哔哩_bilibili
(帧动画 + 极坐标变换)
GitHub源码:AP01:A向技术美术入门课程文章来源地址https://www.toymoban.com/news/detail-523261.html
到了这里,关于你好,uv变换(新手入门向聊天教程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!