- 下图为静态的图片和噪声图
- 先把问题简化,让纹理产生扭曲的效果:
// 在片元着色器
fixed4 frag(v2f i) : SV_Target
{
// 采集到噪声图在该片元的颜色的r通道值
float r = tex2D(_NoiseTex, i.uv_Noise).r;
// 将r转换为主纹理采样的偏移值offset
fixed2 offset = fixed2(r, r);
// 修正,防止纹理边缘产生扭曲的效果
offset -= _NoiseBrightOffset;
// 将offset乘以自定义参数,方便我们控制
offset *= fixed2(_NoiseScaleX, _NoiseScaleY);
// 在采集纹素时,将偏移值offset附加到uv上
fixed4 col = tex2D(_MainTex, i.uv + offset); // 加上扰动UV后再采样主纹理
return col;
}
- 至此我们可以得到一个静态的扭曲的图片
- 那么如何让画面动起来呢?
- 如果让噪声图随时间移动,图片便会随着时间产生不同的扭曲效果。
- 很容易想到,我们可以去调整噪声图的偏移Offset。
- 这里我们使用内置变量
_Time
来影响噪声图的偏移。如下图,_Time变量可以方便我们在Shader中访问运行时间,实现各种动画效果。《Unity Shader入门精要-时间篇》
- 如下方代码,我们可以得到一个动态的扭曲的图片
// 顶点着色器 v2f vert(appdata v) { v2f o; // 顶点着色器的基本操作 o.vertex = UnityObjectToClipPos(v.vertex); // 将顶点的UV传递给片元着色器 o.uv = v.uv; // 将噪声图Noise的偏移Offset加上时间 // 这里我们将时间_Time乘以了自定义参数,更方便我们控制水流的速度 _NoiseTex_ST.zw += _Time * fixed2(_NoiseSpeedX, _NoiseSpeedY); // 计算出经过缩放和偏移后的纹理坐标 o.uv_Noise = TRANSFORM_TEX(v.texcoord, _NoiseTex); return o; }
完整代码参考
-
Shader "Unlit/PerlinNoiseApp" { Properties { [NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {} // 主纹理 _NoiseTex ("NoiseTex", 2D) = "white" {} // 噪点图 _NoiseScaleX ("NoiseScaleX", Range(0, 1)) = 0.1 // 水平噪点放大系数 _NoiseScaleY ("NoiseScaleY", Range(0, 1)) = 0.1 // 垂直放大系数 _NoiseSpeedX ("NoiseSpeedX", Range(0, 10)) = 1 // 水平扰动速度 _NoiseSpeedY ("NoiseSpeedY", Range(0, 10)) = 1 // 垂直扰动速度 _NoiseBrightOffset ("NoiseBrightOffset", Range(0, 0.9)) = 0.25 // 噪点图整体的数值偏移 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 texcoord : TEXCOORD1; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float2 uv_Noise : TEXCOORD1; }; // 主纹理 sampler2D _MainTex; // 噪声图 sampler2D _NoiseTex; // 噪声图 fixed4 _NoiseTex_ST; // 干扰在X方向上的缩放倍数 fixed _NoiseScaleX; // 干扰在Y方向上的缩放倍数 fixed _NoiseScaleY; // X方向的水流速度 fixed _NoiseSpeedX; // Y方向的水流速度 fixed _NoiseSpeedY; // 噪声图的起始偏移,防止纹理边缘产生扭曲的效果 fixed _NoiseBrightOffset; v2f vert(appdata v) { v2f o; // 顶点着色器的基本操作 o.vertex = UnityObjectToClipPos(v.vertex); // 将顶点的UV传递给片元着色器 o.uv = v.uv; // 将噪声图Noise的偏移Offset加上时间 // 这里我们将时间_Time乘以了自定义参数,更方便我们控制水流的速度 _NoiseTex_ST.zw += _Time * fixed2(_NoiseSpeedX, _NoiseSpeedY); // 计算出经过缩放和偏移后的纹理坐标 o.uv_Noise = TRANSFORM_TEX(v.texcoord, _NoiseTex); return o; } fixed4 frag(v2f i) : SV_Target { // 采集到噪声图在该片元的颜色的r通道值 float r = tex2D(_NoiseTex, i.uv_Noise).r; // 将r转换为主纹理采样的偏移值offset fixed2 offset = fixed2(r, r); // 修正,防止纹理边缘产生扭曲的效果 offset -= _NoiseBrightOffset; // 将offset乘以自定义参数,方便我们控制 offset *= fixed2(_NoiseScaleX, _NoiseScaleY); // 在采集纹素时,将偏移值offset附加到uv上 fixed4 col = tex2D(_MainTex, i.uv + offset); // 加上扰动UV后再采样主纹理 return col; } ENDCG } } Fallback "Diffuse" }