1.实现类似瞳孔放大的视觉扭曲效果。该效果通过组合图像拉伸、扭曲和模糊算法。
输入图像 → 横向拉伸 → 径向扭曲 → 方向模糊 → 输出图像
↑ ↑ ↑ ↑
原图UV 基于距离的 正弦扭曲 4次采样
边缘拉伸 时间动画 模糊处理
横向拉伸算法
// 计算横向距离 [-1, 1]
float distanceFromCenter = (uv.x - 0.5) * 2.0;
// 基于距离计算拉伸因子(边缘拉伸更大)
float stretchFactor = smoothstep(0.0, 1.0, abs(distanceFromCenter)) * _StretchAmount;
// 应用横向拉伸
uv.x = lerp(uv.x, 0.5 - sign(distanceFromCenter) * 0.5, stretchFactor);
// 伴随垂直微调(增强立体感)
uv.y = lerp(uv.y, sign(distanceFromCenter) * -0.01, stretchFactor);
算法特点:
-
使用smoothstep平滑边缘过渡
-
保留中心区域不变(瞳孔位置)
-
添加垂直方向微小偏移增强3D感
动态扭曲效果
float2 center = float2(0.5, 0.5); float dist = length(uv - center); // 基于距离的正弦扭曲 + 时间动画 float twist = sin(dist * 10.0 + _Time.y * _twistSpeed) * 0.6 * 0.01; uv.x += twist * _twistAmount;数学原理:
-
dist:像素到中心的径向距离 -
dist * 10.0:产生多个扭曲环带 -
_Time.y * _twistSpeed:随时间旋转的波动 -
* 0.6 * 0.01:限制扭曲幅度,保持视觉效果自然方向性模糊实现
int sampleCount = 4; float2 direction = normalize(half2(0.1, 0.1)); // 45度方向模糊 for (int j = 0; j < sampleCount; ++j) { float offset = (float(j) / float(sampleCount - 1) - 0.5) * _blurAmount; float2 offsetUV = uv + direction * offset * _MainTex_TexelSize.xy * _BlurOffset; col += SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, offsetUV); } col /= sampleCount;
-
2.模拟心跳脉搏的屏幕后处理Shader。该效果通过组合径向脉冲扩张、动态扭曲和色差偏移三种技术,营造出类似心脏跳动时的视觉张力感
核心技术图解
时间输入 → 心跳波形生成 → 径向扩张 → 动态扭曲 → 色差偏移 → 最终输出
↑ ↑ ↑ ↑ ↑
_HeartBeatSpeed 分段函数 基于距离 正弦波动 RGB通道分离
效果组合逻辑
整个后处理效果按照特定顺序叠加:
-
拉伸阶段:改变图像的基础形貌,创造瞳孔扩张的视觉基础
-
扭曲阶段:添加动态波纹,模拟液体或光学的波动感
-
模糊阶段:柔化边缘,增强视觉冲击力
心跳波形生成算法
1. 分段函数设计
half pulseMax = 1.0; // 最大幅度 half pulseMin = 0.0; // 最小幅度 half heartbeatDuration = 0.3; // 心跳上升+顶峰+下降总时间 half pauseDuration = _pauseDurationTime; // 低谷停顿时间 // 计算当前时间在一个心跳周期中的进度 float totalDuration = heartbeatDuration + pauseDuration; float currentTime = fmod(_Time.y * _HeartBeatSpeed, totalDuration);
设计思路:将心跳周期分为四个阶段,模拟真实心跳波形:
-
快速上升期(40%):心室收缩,压力骤增
-
顶峰停顿(40%):保持收缩状态
-
缓慢下降期(20%):心室舒张
-
低谷停顿:心脏休息期
2. 波形生成代码
float pulse; if (currentTime < heartbeatDuration * 0.4) { // 上升阶段:线性上升 pulse = pulseMin + (pulseMax - pulseMin) * (currentTime / (heartbeatDuration * 0.4)); } else if (currentTime < heartbeatDuration * 0.8) { // 顶峰停顿:保持最大 pulse = pulseMax; } else if (currentTime < heartbeatDuration) { // 下降阶段:线性下降 float t = currentTime - (heartbeatDuration * 0.8); pulse = pulseMax - (pulseMax - pulseMin) * (t / (heartbeatDuration * 0.2)); } else { // 低谷停顿:保持最小 pulse = pulseMin; }
波形特点:
-
快速上升制造冲击感
-
顶峰停顿强化收缩感
-
缓慢下降模拟舒张
-
低谷停顿形成节奏感
核心效果实现
1. 径向脉冲扩张
float2 center = float2(0.5, 0.5); float dist = length(uv - center); // 径向扩张:uv向中心收缩,产生向外扩张的视觉错觉 uv -= (uv - center) * pulse * _pulseAmount;
数学原理:
-
(uv - center):从中心指向当前像素的方向向量 -
pulse * _pulseAmount:当前时刻的脉冲强度 -
减去方向向量×强度 → UV向中心收缩 → 图像从中心向外扩张
视觉解释:当UV向中心收缩时,原本边缘的像素被映射到更靠近中心的位置,相当于把图像”撑开”,产生从中心向外脉冲的视觉效果。
2. 动态扭曲增强
// 基于距离的正弦扭曲 float twist = sin(dist * 10.0 + _Time.y * 1) * 0.6 * 0.01 * pulse; uv.x += twist * _twistAmount;
技术要点:
-
dist * 10.0:产生多个扭曲环带,增强层次感 -
_Time.y * 1:随时间旋转的波动 -
* pulse:扭曲强度随心跳节奏变化,增强同步感
3. 色差偏移(Chromatic Aberration)
// RGB通道分离采样 float2 uvR = uv + float2(0.01, 0.0) * pulse * _ChromaticAberrationAmount; float2 uvG = uv; float2 uvB = uv - float2(0.01, 0.0) * pulse * _ChromaticAberrationAmount; // 合并通道 half4 colR = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uvR); half4 colG = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uvG); half4 colB = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uvB); half4 col = half4(colR.r, colG.g, colB.b, 1.0);
设计原理:
-
模拟镜头色散现象,增强视觉冲击
-
偏移量随心跳节奏变化,强化脉搏感
-
RGB通道分离方向:红右蓝左,符合物理色散规律
-
绿通道保持不变,维持视觉中心
-
3.模拟屏幕闪白、震动和模糊的后处理Shader。该效果通过组合方向模糊、高频震动和曝光增强三种技术,营造出爆炸冲击、相机剧烈晃动或角色受击时的视觉冲击感。
核心技术图解
输入图像 → 方向模糊采样 → 高频震动偏移 → 曝光增强 → 输出图像
↑ ↑ ↑ ↑
_MainTex _SampleCount _ShakeIntensity _Exposure
_BlurOffset sin(_Time.y*100)
震动算法实现
1. 高频震动计算
// 100Hz的超高频正弦波,产生剧烈抖动感 float shake = sin(_Time.y * 100.0) * 0.01; // 应用到UV偏移 offsetUV += float2(shake, shake) * _ShakeIntensity;
数学原理:
-
_Time.y * 100.0:100倍时间速度,产生肉眼无法追踪的超快震动 -
* 0.01:基础偏移量控制,避免过度偏移导致图像撕裂 -
* _ShakeIntensity:可调节的震动强度参数
设计思路:采用超高频(100Hz)而非普通低频(如5-10Hz)震动,模拟真实相机在剧烈冲击下的微观震颤,比普通晃动更具冲击力。
2. 频率对比分析
| 频率 | 视觉感受 | 适用场景 |
|---|---|---|
| 5-10Hz | 明显的左右摆动 | 醉酒、眩晕效果 |
| 20-30Hz | 轻微的抖动感 | 车辆行驶、手持相机 |
| 100Hz | 微观震颤、冲击感 | 爆炸、受击、闪屏 |
方向模糊实现
1. 模糊采样算法
float2 direction = normalize(half2(0.1, 0.1)); // 45度方向模糊 float blurAmount = 5 * 10.0; // 基础模糊强度 for (int j = 0; j < sampleCount; ++j) { // 计算采样偏移量(-0.5到0.5均匀分布) float offset = (float(j) / float(sampleCount - 1) - 0.5) * blurAmount; // 应用方向、偏移和震动 float2 offsetUV = uv + direction * offset * _MainTex_TexelSize.xy * _BlurOffset; offsetUV += float2(shake, shake) * _ShakeIntensity; color += SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, offsetUV); } color /= sampleCount;
2. 模糊参数设计
| 参数 | 作用 | 技术细节 |
|---|---|---|
_SampleCount |
采样质量 | 2-10可调,平衡性能与效果 |
direction |
模糊方向 | 45度倾斜,避免水平和垂直方向的呆板感 |
_BlurOffset |
模糊距离 | 控制拖影长度 |
blurAmount = 50 |
基础强度 | 固定值确保足够的模糊范围 |
曝光增强处理
color *= _Exposure;
作用:整体提亮画面,模拟闪光灯或爆炸瞬间的光照过曝效果。配合震动和模糊,强化视觉冲击力。
参数调节指南
| 参数 | 范围 | 作用 | 推荐值 |
|---|---|---|---|
| _SampleCount | 2-10 | 模糊采样质量 | 6-8(平衡性能) |
| _Exposure | 0-20 | 曝光强度 | 1.5-3.0(轻微过曝) |
| _ShakeIntensity | 0-2 | 震动强度 | 0.5-1.2(剧烈冲击) |
| _BlurOffset | 0-5 | 模糊距离 | 1.0-3.0(明显拖影) |
效果组合逻辑
时序设计
假设用于爆炸反馈:
-
瞬间:高频震动启动,模拟冲击波
-
同时:方向模糊增强,模拟视觉暂留
-
伴随:曝光增强,模拟闪光
-
衰减:各参数随时间归零(需C#脚本配合)
视觉层次
震动层:微观震颤,传递冲击感 模糊层:方向拖影,传递运动感 曝光层:整体提亮,传递能量感
4.模拟高速运动视觉感受的屏幕后处理Shader。该效果通过组合极坐标变换、动态Voronoi噪声和屏幕震动三种技术,在屏幕边缘生成动态流动的线条,配合高频抖动,营造出角色高速移动、加速冲刺或时间紧迫感的视觉体验。
核心技术图解
输入图像 → UV震动偏移 → 极坐标变换 → Voronoi噪声 → 速度线生成 → 颜色混合 → 输出
↑ ↑ ↑ ↑ ↑ ↑
_MainTex sin(_Time*60) 中心点(0.5) 时间动画 边缘检测 _SpeedLineColor
极坐标变换原理
1. 坐标转换算法
void Unity_PolarCoordinates_float(float2 UV, float2 Center, float RadialScale, float LengthScale, out float2 Out) { float2 delta = UV - Center; // 计算相对于中心的向量 float radius = length(delta) * 2 * RadialScale; // 极径(距离) float angle = atan2(delta.x, delta.y) * 1.0/6.28 * LengthScale; // 极角(角度) Out = float2(radius, angle); }
数学原理:
-
radius:像素到屏幕中心的距离,决定线条的径向位置
-
angle:像素的方向角,决定线条的周向位置
-
输出坐标系:
(r, θ)将笛卡尔坐标转换为极坐标
视觉意义:将屏幕从”方形的XY网格”转换为”圆形的距离-角度”坐标系,使得在边缘生成的线条能够围绕中心自然弯曲。
2. 参数调校
Unity_PolarCoordinates_float(uv, float2(0.5, 0.5), 0.6, 1, _PolarCoordinates);
| 参数 | 值 | 作用 |
|---|---|---|
| Center | (0.5, 0.5) | 屏幕中心点 |
| RadialScale | 0.6 | 压缩径向范围,让线条更集中在边缘 |
| LengthScale | 1 | 角度缩放,保持自然 |
Voronoi噪声生成
1. 随机向量函数
inline float2 Unity_Voronoi_RandomVector_float(float2 UV, float offset) { float2x2 m = float2x2(15.27, 47.63, 99.41, 89.98); UV = frac(sin(mul(UV, m))); // 哈希函数生成随机值 return float2(sin(UV.y+offset)*0.5+0.5, cos(UV.x*offset)*0.5+0.5); }
算法特点:使用固定矩阵和三角函数生成确定性随机,保证每帧计算结果一致。
2. Voronoi核心算法
void Unity_Voronoi_float(float2 UV, float AngleOffset, float CellDensity, out float Out, out float Cells) { float2 g = floor(UV * CellDensity); // 网格坐标 float2 f = frac(UV * CellDensity); // 网格内偏移 // 遍历相邻3x3网格,寻找最近的特征点 for(int y=-1; y<=1; y++) { for(int x=-1; x<=1; x++) { float2 lattice = float2(x,y); float2 offset = Unity_Voronoi_RandomVector_float(lattice + g, AngleOffset); float d = distance(lattice + offset, f); if(d < res.x) { res = float3(d, offset.x, offset.y); Out = res.x; // 最小距离 Cells = res.y; // 特征点信息 } } } }
Voronoi图原理:将空间划分为若干区域,每个区域由距离最近的特征点决定。在速度线效果中,Voronoi的最小距离值用于生成流动的纹理。
速度线生成逻辑
1. 参数配置
// 极坐标变换 _PolarCoordinates = (r, θ) // 仅保留径向距离用于边缘检测 _Split_PolarCoordinates = _PolarCoordinates.r // 为Voronoi准备UV:角度作为U坐标,固定缩放创造拉伸效果 _TilingAndOffset = (_PolarCoordinates.θ, _PolarCoordinates.r) * float2(1, 200) // 垂直方向剧烈拉伸
设计思路:
-
将角度映射到Voronoi的U方向,创造围绕中心的周向流动
-
将径向距离放大200倍后映射到V方向,使线条垂直于半径方向
-
结果:线条从中心向外放射,同时围绕中心旋转
2. 动态动画
// 时间驱动的角度偏移 _Multiply_Time = _Time.y * 17.54; // 流动速度 // 细胞密度控制 _Subtract_voronol = 3.0 - 0.06; // ≈2.94,控制线条密度 // Voronoi计算 Unity_Voronoi_float(_TilingAndOffset, _Multiply_Time, _Subtract_voronol, _Voronoi_3, _Voronoi_4);
流动机制:AngleOffset参数随时间变化,使Voronoi特征点旋转,带动线条周向运动。
3. 线条筛选
// 径向距离与Voronoi距离相乘,让线条集中在边缘 _Multiply_Voronoi = _Split_PolarCoordinates * _Voronoi_3; // 阈值筛选,只保留小于0.71的部分 _Step_Voronoi = step(0.71, _Multiply_Voronoi); // 1表示内部,0表示线条 // 反转,让线条区域为1 _OneMinus_Voronoi = 1 - _Step_Voronoi; // 1表示线条,0表示非线条
效果:只有径向距离较大(靠近边缘)且Voronoi距离较小(特征点附近)的区域被标记为速度线。
屏幕震动效果
// 60Hz高频震动,与Voronoi动画同步 float shake = sin(_Time.y * 60.0) * 0.01; half2 offsetUV = float2(shake, shake) * 0.3; // 震动应用到UV采样 half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv + offsetUV);
设计意图:高频震动模拟高速运动时的视觉模糊和相机抖动,增强速度感。
颜色混合
col.rgb = lerp(_SpeedLineColor, col, _OneMinus_Voronoi);
混合逻辑:
-
_OneMinus_Voronoi == 1(线条区域):lerp返回col,保持原图 -
_OneMinus_Voronoi == 0(非线条区域):lerp返回_SpeedLineColor,显示速度线颜色
注意:当前实现中混合方向可能需要调整。通常应该是线条区域显示颜色,非线条区域保持原图。建议修改为:
col.rgb = lerp(col, _SpeedLineColor, _OneMinus_Voronoi);
参数调节指南
| 参数 | 作用 | 推荐值 | 调节效果 |
|---|---|---|---|
| RadialScale (0.6) | 径向压缩 | 0.3-1.0 | 数值越大,线条越靠近中心 |
| 垂直拉伸 (200) | 线条密度 | 50-500 | 数值越大,线条越密集 |
| 流动速度 (17.54) | 动画速度 | 5-30 | 数值越大,线条流动越快 |
| 细胞密度 (2.94) | 线条数量 | 1-10 | 数值越大,线条越多 |
| 阈值 (0.71) | 线条粗细 | 0.3-0.9 | 数值越大,线条越细 |
| 震动频率 (60) | 抖动速度 | 30-120 | 数值越大,抖动越快 |
效果组合逻辑
视觉层次
基础层:原图画面 震动层:高频UV抖动,模拟物理震动 速度线层:动态Voronoi线条,模拟视觉残留
时序效果
-
持续效果:线条持续流动,创造恒定的速度感
-
脉冲增强:可配合C#脚本,在加速时增强强度和密度
-
方向暗示:线条流动方向暗示运动方向(当前为周向)
5.模拟能量恢复、机体修复或逐渐显形的屏幕后处理Shader。该效果通过组合距离场计算、噪声纹理采样和边缘发光三种技术,实现从屏幕中心向外逐渐恢复的视觉特效,适用于角色复活、能量充能、伤势恢复等场景。
核心技术图解
输入图像 → 距离场计算 → 噪声采样 → 阈值判断 → 边缘检测 → 颜色混合 → 输出
↑ ↑ ↑ ↑ ↑ ↑
_MainTex uv - 0.5 _DissolveNoise _DissolveAmount _EdgeWidth _DissolveEageColor
distance _DissolveNoiseTilling
距离场计算原理
1. 中心距离计算
float2 uv1 = i.uv - 0.5; // 将UV原点移动到屏幕中心 float distance = length(uv1); // 计算像素到屏幕中心的欧几里得距离
数学意义:
-
uv - 0.5:将UV坐标从[0,1]范围转换到[-0.5,0.5]范围 -
length():计算向量的模长,得到像素到中心的距离 -
结果范围:中心点距离=0,四角距离≈0.707
视觉意义:利用距离值创建从中心向外的径向渐变,用于控制溶解的起始位置和扩散方向。
2. 距离分布特性
| 位置 | UV坐标 | 距离值 | 溶解优先级 |
|---|---|---|---|
| 屏幕中心 | (0.5, 0.5) | 0 | 最晚溶解 |
| 边缘中点 | (0.5, 0) 或 (0, 0.5) | 0.5 | 中等 |
| 屏幕四角 | (0,0) 或 (1,1) | ≈0.707 | 最早溶解 |
设计意图:能量恢复从边缘开始向中心汇聚,符合视觉直觉——能量从外部流入核心。
噪声纹理采样
1. 噪声采样配置
// 噪声纹理采样,支持Tilling控制 float noise = SAMPLE_TEXTURE2D(_DissolveNoise, sampler_DissolveNoise, i.uv * _DissolveNoiseTilling.xy).r;
噪声作用:
-
打破规则的圆形溶解,创造自然的不规则边缘
-
每像素随机值,使溶解边缘呈现有机形态
-
Tilling参数控制噪声纹理的重复密度
2. 灰度值计算
half gray = 1 - noise; // 反转噪声,使亮部对应高溶解概率
反转目的:通常噪声纹理中白色(1)区域代表”可溶解”,黑色(0)区域代表”不可溶解”。反转后,原始噪声的暗部变为溶解区域,创造更自然的溶解效果。
溶解阈值算法
1. 核心阈值计算
// cutoff = 溶解程度 + 距离 - 噪声*(1-溶解程度) half cutoff = _DissolveAmount + distance - noise.r * (1 - _DissolveAmount);
数学分解:
-
_DissolveAmount:基础溶解程度(0-1) -
+ distance:距离中心越远,cutoff值越大,越容易被溶解 -
- noise.r * (1 - _DissolveAmount):噪声调制,当_DissolveAmount较小时,噪声影响更大
物理意义:这个公式创建了一个动态阈值表面,其值在空间上随距离增加,在随机性上受噪声调制,整体随_DissolveAmount参数变化。
2. 阈值范围映射
cutoff = lerp(-20.2, 10.01, cutoff); // 将cutoff从[0,1]映射到[-20.2, 10.01]
映射目的:
-
扩展动态范围,使clip操作有明确的裁切边界
-
负数区域保证被裁切(显示溶解效果)
-
正数区域保证保留(显示原图)
3. 像素裁切
half a = gray - cutoff; clip(a); // 如果a < 0,则丢弃该像素
裁切逻辑:
-
a = gray - cutoff:比较噪声灰度值与动态阈值 -
当
gray < cutoff时,a < 0,像素被裁切(显示溶解) -
当
gray >= cutoff时,像素保留(显示原图)
边缘发光效果
1. 边缘检测
half edgeRate = cutoff + _EdgeWidth; // 边缘区域的上限 half edge = step(gray, edgeRate); // 当gray <= edgeRate时,edge=1
边缘定义:在裁切边界附近的一段区域内,gray值介于cutoff和cutoff + _EdgeWidth之间的像素被标记为边缘。
2. 颜色混合
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); col = lerp(col, _DissolveEageColor, edge); // 边缘区域混合发光颜色
混合效果:
-
edge == 0(非边缘):保持原图颜色 -
edge == 1(边缘):显示发光颜色(支持HDR)
参数调节指南
| 参数 | 作用 | 推荐值 | 调节效果 |
|---|---|---|---|
| _DissolveAmount | 溶解程度 | 0-1动态变化 | 0=全屏原图,1=完全溶解 |
| _EdgeWidth | 边缘宽度 | 0.01-0.05 | 数值越大,发光边缘越宽 |
| _DissolveEageColor | 边缘颜色 | HDR亮色(2,2,2,1) | 决定边缘发光色 |
| _DissolveNoiseTilling | 噪声密度 | (1,1)到(5,5) | 数值越大,溶解细节越丰富 |
效果组合逻辑
视觉层次
基础层:原图画面(未溶解区域) 裁切层:完全消失区域(clip丢弃) 边缘层:发光过渡带(溶解边界)




-DrawMe.png)


暂无评论内容