Unity鱼眼特效
一、前言:
鱼眼特效本质上是让采样从笛卡尔坐标系中转到极坐标系,使用极角,极径来计算采样坐标的。不同的鱼眼特效本质上只是对极径计算的多项式不同而导致特效的些许不同,常用的有三种极径的多项式计算。
多项畸变:鱼眼极径
r_dst = k1·r_src + k2·r_src³ + k3·r_src⁵ + ...
(k1,k2,k3
为畸变系数)效果特点:可通过调整系数控制畸变强度:
k2>0
时边缘向外拉伸(桶形畸变),k2<0
时边缘向内挤压(枕形畸变
正切模型:
r_dst = f·tan(α)
(f
为焦距,α
为原始图像像素对应的视角,α = arctan(r_src/f)
)效果特点:视场角较小(<90°)时畸变弱,视场角增大时边缘畸变急剧增强,模拟 “广角鱼眼”
正弦模型:
r_dst = f·sin(α)
(α
为原始图像像素对应的视角,范围 <180°)效果特点:视场角接近 180° 时边缘畸变平缓,图像呈圆形,模拟 “全画幅鱼眼”
二、计算原理
具体的算法实现基本都是一致的,唯一不同的就是计算极径公式,这里以多项式畸变为例子:
1:
遍历鱼眼图像的每个目标像素
(x_dst, y_dst)
(屏幕空间坐标),先将其转换为以图像中心为原点的坐标(x_dst', y_dst')
(x_dst' = x_dst - W/2
,y_dst' = y_dst - H/2
)2:
- 计算目标像素的极角
θ_dst = arctan2(y_dst', x_dst')
(与原始图像的角度一致)。- 计算目标像素的 “线性极径”
r_dst_linear = sqrt(x_dst'² + y_dst'²)
(若直接使用此极径,无畸变)。- 通过多项式公式计算 “畸变极径”
r_dst = k1·r_dst_linear + k2·r_dst_linear³
(k1
控制整体缩放,k2
控制畸变强度)3:
根据鱼眼的极坐标
(r_dst, θ_dst)
,计算原始图像中对应采样坐标(x_src',y_src')
:
x_src' = r_dst · cos(θ_dst)
y_src' = r_dst · sin(θ_dst)
- 将
(x_src', y_src')
转换回原始图像的屏幕坐标:x_src = x_src' + W/2
,y_src = y_src' + H/2
。
三:实现
Unity中的具体实现算法:
float _FishEyeDistortIntensity; //default 0.0
float _FishEyeScaleIntensity; //default 1.0//return the change UV
void FishEye(inout float2 uv)
{float thea = atan2(uv.y - 0.5, uv.x - 0.5);float r = length(uv - float2(0.5, 0.5));float dis = _FishEyeScaleIntensity * r + _FishEyeDistortIntensity * pow(r, 3);uv.x = 0.5 + dis * cos(thea);uv.y = 0.5 + dis * sin(thea);
}
最终使用返回的UV进行采样即可: