扭曲效果 (Distortion)
屏幕空间的折射和扭曲
📚 原理
扭曲效果通过偏移屏幕 UV 来模拟折射、热浪、水下等视觉效果。核心是采样屏幕颜色纹理(_CameraOpaqueTexture)时使用偏移后的 UV。
💻 URP 实现
基础扭曲 Shader
Shader "Custom/Distortion"
{
Properties
{
_DistortionMap("Distortion Map", 2D) = "bump" {}
_DistortionStrength("Strength", Range(0, 0.1)) = 0.02
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" "RenderPipeline"="UniversalPipeline" }
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
TEXTURE2D(_DistortionMap);
SAMPLER(sampler_DistortionMap);
CBUFFER_START(UnityPerMaterial)
float4 _DistortionMap_ST;
float _DistortionStrength;
CBUFFER_END
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = TRANSFORM_TEX(input.uv, _DistortionMap);
output.screenPos = ComputeScreenPos(output.positionCS);
return output;
}
half4 frag(Varyings input) : SV_Target
{
// 采样扭曲贴图(法线贴图格式)
half4 distortTex = SAMPLE_TEXTURE2D(_DistortionMap, sampler_DistortionMap, input.uv);
half2 distortion = (distortTex.xy * 2.0 - 1.0) * _DistortionStrength;
// 计算屏幕 UV
float2 screenUV = input.screenPos.xy / input.screenPos.w;
// 应用扭曲
screenUV += distortion;
// 采样屏幕颜色
half4 sceneColor = SAMPLE_TEXTURE2D(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, screenUV);
return sceneColor;
}
ENDHLSL
}
}
}
动态热浪效果
// 使用噪声和时间产生动态扭曲
float2 AnimatedDistortion(float2 uv, float time)
{
// 多层噪声叠加
float2 offset1 = SAMPLE_TEXTURE2D(_NoiseMap, sampler_NoiseMap, uv + time * 0.1).xy;
float2 offset2 = SAMPLE_TEXTURE2D(_NoiseMap, sampler_NoiseMap, uv * 2 - time * 0.15).xy;
float2 distortion = (offset1 + offset2 - 1.0) * _Strength;
return distortion;
}
⚙️ URP 设置
启用 Opaque Texture
在 URP Asset 中启用 "Opaque Texture" 选项,否则 _CameraOpaqueTexture 不可用。
路径:URP Asset > Quality > Opaque Texture = On
🎮 应用场景
🔮 玻璃/水晶
透明物体的折射效果
🔥 热浪
火焰、沙漠的空气扭曲
🌊 水下
水面折射、水下视角
🛡️ 隐身效果
隐形斗篷的光学迷彩
💡 技巧
边缘处理
扭曲后的 UV 可能超出 [0,1] 范围,建议 clamp 或使用边缘渐变:
// 边缘衰减 float edge = smoothstep(0, 0.1, screenUV.x) * smoothstep(1, 0.9, screenUV.x); edge *= smoothstep(0, 0.1, screenUV.y) * smoothstep(1, 0.9, screenUV.y); distortion *= edge;