畸变(Distortion)定义
光学畸变: 现实中的光学畸变是由于摄像头镜头的物理特性造成的。例如,广角镜头可能会产生桶形畸变(Barrel Distortion),其中图像的边缘向中心凹陷;而长焦镜头可能会产生枕形畸变(Pincushion Distortion),其中图像的边缘向外膨胀。这些畸变可以通过后期处理软件进行校正。
桶形(barrel)畸变
枕形(pinchushion)畸变
Shader实现
顶点着色器:
#version 450
layout (location = 0) out vec2 outUV;
void main()
{
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
}
实现的解读,参考:Vulkan 渲染不带缓冲区的全屏四边形
片段着色器:
#version 450
//用来访问一个包含多个2D纹理的纹理数组。它将采样器绑定到纹理单元1。
layout (binding = 1) uniform sampler2DArray samplerView;
layout (binding = 0) uniform UBO
{
layout(offset = 2576) float distortionAlpha; //结构体字节偏移272,扭曲参数。
} ubo;
layout (location = 0) in vec2 inUV;
layout (location = 0) out vec4 outColor;
//一个常量表达式,表示纹理数组中视图层的索引。
layout (constant_id = 0) const float VIEW_LAYER = 0.0f;
void main()
{
const float alpha = ubo.distortionAlpha;
//将输入纹理坐标从[0, 1]范围转换为[-1, 1]范围,并将它们存储在一个局部向量变量
vec2 p1 = vec2(2.0 * inUV - 1.0);
//对p1应用一个扭曲函数,并将结果存储在另一个局部向量变量,名为p2。
//length(p1)是p1从原点的欧几里得距离。
//这创建了一个径向扭曲效果,根据alpha的符号和大小,将纹理坐标推向或拉远中心。
vec2 p2 = p1 / (1.0 - alpha * length(p1));
//将p2转换回[0, 1]范围
p2 = (p2 + 1.0) * 0.5;
//检查p2是否在[0, 1]范围内
bool inside = ((p2.x >= 0.0) && (p2.x <= 1.0) && (p2.y >= 0.0 ) && (p2.y <= 1.0));
//根据inside的值赋值输出颜色。
//如果inside为真,它使用samplerView和p2作为参数采样纹理数组,并将结果赋给outColor。
//p2的第三个分量用作纹理数组的层索引,可以通过将VIEW_LAYER设置为不同的值来改变。
//如果inside为假,它将黑色(vec4(0.0))赋给outColor。
outColor = inside ? texture(samplerView, vec3(p2, VIEW_LAYER)) : vec4(0.0);
//vec3(p2, VIEW_LAYER):纹理坐标+层的采样
}
alpha > 0,p2 > p1,原来位置处的纹理替换为离中心点更远处的纹理,表现出纹理坐标的 “收缩” ,是桶形畸变;
alpha < 0,p2 < p1,原来位置处的纹理替换为离中心点更近处的纹理,表现出纹理坐标的 “扩张” ,是枕形畸变。
渲染效果:
左:alpha = 0.4;右:alpha = -0.4