【Unity Shader URP】UV 扭曲效果(1 个可直接用的 Shader + 8 种变体)

0. 一张图理解 UV 扭曲

在这里插入图片描述

UV 扭曲的本质:把采样用的 UV 改掉,让像素去纹理的“别处”取色。

(可选)噪声示例:
在这里插入图片描述
在这里插入图片描述


1. 最小公式

float2 uv2 = uv + offset * _Strength;
half4 col = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv2);

常用参数建议:

  • _Strength:0 ~ 0.05(一般已经很明显)
  • _NoiseScale:1 ~ 10
  • _Speed:0 ~ 3

2. 基础噪声扭曲(完整 URP Shader,可直接用)

用途:水面/热浪/护盾等。NoiseTex 推荐用 RG 两通道做二维偏移。

Shader "Custom/UV_Distort_Basic"
{
    Properties
    {
        _BaseMap    ("Base Map", 2D) = "white" {}
        _NoiseTex   ("Noise (RG)", 2D) = "gray" {}
        _Strength   ("Distort Strength", Range(0, 0.2)) = 0.03
        _NoiseScale ("Noise Scale", Float) = 2.0
        _Speed      ("Noise Speed (XY)", Vector) = (0.2, 0.15, 0, 0)
        _Tint       ("Tint", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags
        {
            "RenderPipeline"="UniversalRenderPipeline"
            "Queue"="Transparent"
            "RenderType"="Transparent"
        }

        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            TEXTURE2D(_BaseMap);  SAMPLER(sampler_BaseMap);
            TEXTURE2D(_NoiseTex); SAMPLER(sampler_NoiseTex);

            float4 _BaseMap_ST;
            float _Strength;
            float _NoiseScale;
            float4 _Speed;
            float4 _Tint;

            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv         : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv          : TEXCOORD0;
            };

            Varyings vert(Attributes v)
            {
                Varyings o;
                o.positionHCS = TransformObjectToHClip(v.positionOS.xyz);
                o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
                return o;
            }

            half4 frag(Varyings i) : SV_Target
            {
                float2 noiseUV = i.uv * _NoiseScale + _Time.y * _Speed.xy;
                float2 n = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, noiseUV).rg * 2.0 - 1.0;
                float2 uv2 = i.uv + n * _Strength;
                return SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv2) * _Tint;
            }
            ENDHLSL
        }
    }
}

使用:新建 .shader → 粘贴 → 建材质 → 贴 _BaseMap + _NoiseTex(Noise 纹理 Wrap=Repeat 更常用)。


3. 8 种常用变体(核心代码)

下面的片段都假设你已经有 i.uv_Strength_NoiseScale_Speed 等参数。

3.1 Ripple(径向涟漪 / 冲击波)

float2 center = float2(0.5, 0.5);
float2 dir = i.uv - center;
float dist = length(dir);
float wave = sin(dist * _NoiseScale * 20.0 - _Time.y * _Speed.x * 5.0) * _Strength;
float2 uv2 = i.uv + normalize(dir) * wave;

3.2 Swirl(漩涡 / 传送门)

float2 center = float2(0.5, 0.5);
float2 dir = i.uv - center;
float dist = length(dir);
float angle = _Strength * 50.0 * (1.0 - smoothstep(0.0, 0.5, dist)) + _Time.y * _Speed.x;
float s = sin(angle), c = cos(angle);
float2 r = float2(dir.x * c - dir.y * s, dir.x * s + dir.y * c);
float2 uv2 = center + r;

3.3 Fisheye / Lens(鱼眼 / 凸透镜)

float2 center = float2(0.5, 0.5);
float2 dir = i.uv - center;
float dist = length(dir);
float power = 1.0 + _Strength * 10.0;
float newDist = pow(dist, power);
float2 uv2 = center + normalize(dir) * newDist;

3.4 Glitch(条纹位移 + RGB 分离)

float lineNoise = floor(i.uv.y * 50.0 + _Time.y * 20.0);
float rand = frac(sin(lineNoise * 12.9898) * 43758.5453);

float2 uv2 = i.uv;
if (rand > 0.95) uv2.x += (rand - 0.5) * _Strength * 5.0;

half4 col;
col.r = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv2 + float2(_Strength * 0.5, 0)).r;
col.g = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv2).g;
col.b = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv2 - float2(_Strength * 0.5, 0)).b;
col.a = 1.0;

3.5 Heat Haze(热浪:单向扭曲)

float2 noiseUV = float2(i.uv.x * _NoiseScale * 3.0, i.uv.y * _NoiseScale * 0.5 - _Time.y * _Speed.y);
float n = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, noiseUV).r * 2.0 - 1.0;
float2 uv2 = i.uv;
uv2.x += n * _Strength;

3.6 Magnifier(局部放大镜)

float2 center = _FocusPoint.xy;
float2 dir = i.uv - center;
float dist = length(dir);

float2 uv2 = i.uv;
if (dist < _Radius)
{
    float scale = 1.0 - _Strength * 5.0 * (1.0 - dist / _Radius);
    uv2 = center + dir * scale;
}

3.7 Pixelate + Distort(像素化后再扭曲)

float2 pixelUV = floor(i.uv * _PixelSize) / _PixelSize;
float2 noiseUV = pixelUV * _NoiseScale + _Time.y * _Speed.xy;
float2 n = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, noiseUV).rg * 2.0 - 1.0;
float2 uv2 = pixelUV + n * _Strength;

3.8 Radial Mask(让扭曲只在某个区域生效)

float2 center = float2(0.5, 0.5);
float mask = 1.0 - smoothstep(0.2, 0.5, length(i.uv - center)); // 中心强、外圈弱
float2 uv2 = i.uv + offset * (_Strength * mask);

4. 常见问题

  • 纯色贴图看不到扭曲:采样哪都一样,换成有细节的贴图更直观。
  • 边缘拉伸/撕裂:UV 出界了,常见处理是 Noise 贴图 Repeat 或对 UV 做 clamp。
  • 透明排序怪:保持 Queue=Transparent + ZWrite Off,需要更稳定时再做分层或自定义排序。

5. 小的性能建议

  • 噪声图 128/256 通常够用。
  • 大面积全屏慎用多次采样(比如 Glitch RGB 分离)。
  • 远处可以减小 _Strength 或关闭效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值