Unity3D Shader UV 与纹理采样
Unity3D Shader UV 与纹理采样
Unity3D Shader UV 与纹理采样
前言
前面我们已经知道:
- 顶点着色器负责处理顶点
- 片段着色器负责决定像素颜色
但如果一个 Shader 只能返回纯色,那能做的效果其实非常有限。
真正让材质丰富起来的关键之一,就是:
纹理采样(Texture Sampling)
而纹理采样能成立的前提,就是 UV 坐标。
这一篇,我们就来彻底搞清楚:
- UV 是什么
- Shader 中如何采样贴图
_MainTex_ST是什么TRANSFORM_TEX为什么这么常见
本文示例基于 Unity Built-in Render Pipeline。
什么是 UV
UV 可以理解为:
模型表面上每个点,对应纹理哪一个位置。
它本质上是一组二维坐标:
1 | |
通常范围在:
1 | |
例如:
(0,0)表示纹理左下角(1,1)表示纹理右上角
也就是说:
模型不是直接“知道”自己要贴哪张图,
而是通过 UV 告诉 Shader:
我身上的这个点,应该去纹理的哪个位置取颜色。
为什么叫 UV,不叫 XY
因为:
x y z已经常用来表示空间坐标- 所以纹理坐标通常用
u v区分
也可以简单理解为:
x y:模型在空间中的位置u v:模型在贴图上的位置
Mesh 中的 UV 数据在哪里
和顶点位置、法线一样,UV 也是 Mesh 自带的数据之一。
在 Shader 中,通常这样接收:
1 | |
这里的:
1 | |
就表示从 Mesh 中读取第一套 UV。
最基础的纹理采样流程
一个最基础的贴图 Shader,通常分三步:
- 在
Properties里声明纹理属性 - 在顶点着色器中传递 UV
- 在片段着色器中用 UV 去采样纹理
最小示例如下:
1 | |
代码解读
1 声明一张 2D 纹理
1 | |
含义是:
_MainTex:Shader 中使用的变量名"Main Texture":Inspector 面板显示名称2D:二维纹理"white" {}:默认给一张白色贴图
在 CG/HLSL 中要声明成:
1 | |
2 顶点着色器传递 UV
1 | |
顶点着色器把 Mesh 里的 UV 带到 v2f,
再传给片段着色器。
3 片段着色器采样纹理
1 | |
这行代码的意思是:
去 _MainTex 这张纹理上,用 i.uv 这个坐标取一个颜色。
sampler2D 和 tex2D 是什么关系
可以简单这样理解:
sampler2D _MainTex:表示“有一张可采样的 2D 纹理”tex2D(_MainTex, uv):表示“从这张纹理的 uv 位置取样”
就像:
_MainTex是一本地图uv是地图上的位置tex2D是去这个位置读颜色
为什么有的贴图会重复平铺
如果 UV 超出了 0~1 的范围,纹理如何显示,就取决于纹理的 Wrap Mode。
最常见的是:
- Repeat:重复平铺
- Clamp:超过边界后固定在边缘颜色
例如:
1 | |
这就意味着:
- U 方向走了两遍
- V 方向走了两遍
结果通常就是贴图被平铺了 2 次。
_MainTex_ST 是什么
经常会在 Unity Shader 里看到:
1 | |
这是 Unity 自动为 2D 纹理属性生成的一个变量。
它保存了材质面板里:
- Tiling(平铺)
- Offset(偏移)
的数据。
格式可以理解为:
1 | |
也就是说:
1 | |
TRANSFORM_TEX 做了什么
Unity 中最常见的写法:
1 | |
它本质上等价于:
1 | |
也就是:
- 先乘平铺
- 再加偏移
所以如果希望材质面板中的 Tiling / Offset 生效,
就不要直接写:
1 | |
而应该写:
1 | |
一个更完整的贴图着色 Shader
下面我们加一个颜色叠乘:
1 | |
这个 Shader 做了什么
- 使用 UV 对纹理进行采样
- 支持材质面板中的 Tiling / Offset
- 最后把贴图颜色和
_Tint相乘
所以可以:
- 换不同纹理
- 调整贴图平铺
- 给贴图整体染色
这就是最常用的基础贴图 Shader 模板。
UV 不只是拿来贴图
很多初学者会以为 UV 只能用于采样贴图。
其实不是。
UV 还是一个非常方便的二维参数,可以拿来做很多效果:
- 流光滚动
- 边缘渐变
- 遮罩控制
- 溶解范围
- 水波扰动
例如:
1 | |
这就相当于:
让模型从左到右有一个 0~1 的渐变值。
常见问题
1 为什么贴图显示不对
先检查这几个点:
- Mesh 有没有正确 UV
- 顶点着色器有没有把 UV 传给
v2f - 片段着色器是否用正确 UV 采样
- 是否忘了写
_MainTex_ST - 是否忘了使用
TRANSFORM_TEX
2 为什么材质面板调 Tiling / Offset 没反应
通常是因为写了:
1 | |
而没有使用:
1 | |
3 为什么贴图看起来被拉伸了
这通常不是 Shader 问题,而是:
- 模型 UV 展开不合理
- 模型比例变化太大
Shader 只是按 UV 去取颜色,
真正决定“纹理如何铺在模型表面”的,是建模时的 UV 展开。
总结
这一篇最重要的几个点是:
- UV 是模型表面到纹理位置的映射
sampler2D用来声明 2D 纹理tex2D用 UV 从纹理中采样颜色_MainTex_ST保存 Tiling 和 OffsetTRANSFORM_TEX会自动应用平铺与偏移
可以先记住下面这套最常用模板:
1 | |
后面写:
- 流动贴图
- 溶解效果
- 遮罩混合
- 扭曲特效
基本都离不开这套东西。