Glsl 着色器-防鱼眼;拉;像素

Glsl 着色器-防鱼眼;拉;像素,glsl,shader,fragment-shader,Glsl,Shader,Fragment Shader,我想修复此图像的失真: 很抱歉质量不好,但这是我能找到的最好的例子 我不知道是否可以修复这种失真(我希望有直门和直天花板),但基本上,我不想将像素推到图像外(红色箭头)以增加模糊效果,而是相反(绿色箭头),将像素拉向中心 如果你有任何想法,那就太棒了。也欢迎其他解决方案 这种失真是相机的特性。如果您可以访问用于拍照的相机,则可以对其进行校准,以提取其应用的变形。否则,您仍然可以使用一些一般方程。看看Paul Bourke的,这个堆栈溢出或这个着色器玩具,看看它是如何实现的。对于鱼眼效果的定义,

我想修复此图像的失真:

很抱歉质量不好,但这是我能找到的最好的例子

我不知道是否可以修复这种失真(我希望有直门和直天花板),但基本上,我不想将像素推到图像外(红色箭头)以增加模糊效果,而是相反(绿色箭头),将像素拉向中心


如果你有任何想法,那就太棒了。也欢迎其他解决方案

这种失真是相机的特性。如果您可以访问用于拍照的相机,则可以对其进行校准,以提取其应用的变形。否则,您仍然可以使用一些一般方程。看看Paul Bourke的,这个堆栈溢出或这个着色器玩具,看看它是如何实现的。

对于鱼眼效果的定义,您必须将角度(alpha)与视口的对角线(d)相关联。
视口的对角线是包括整个视口的圆的直径

周长圆半径(r)和角度(α)之间的关系为:

r=tan(α/2)
在下面的
中,眼角
对应于alpha,而
half\u dist
对应于
r

float half_angle = eye_angle/2.0;
float half_dist = tan(half_angle);
使用视口的纵横比(
aspect
),是视口
ndcPos
上碎片的标准化设备位置,可以计算位置
p
。在标准化设备空间中,
x
y
在范围[-1,1]内:

vec2vp_标度=vec2(纵横比,1.0);
vec2p=ndcPos*vp_标度;
对于视口上的每个点(
p
),必须计算相对于周长圆到视口中心的相对距离(
rel_dist
)。并且需要点(
P
)相对于纵横比的相对位置(
rel\u P
):

float vp_dia=长度(vp_标度);
浮动相对距离=长度(P)/vp直径;
vec2 rel_P=标准化(P)/标准化(vp_标度);
鱼眼效应是由球面在平面上的投影引起的。要计算从投影到投影的距离,必须找到弧长与到平面中心的距离之间的关系:

如果圆的半径为1,则弧的长度等于弧段的角度(以弧度为单位)。所以到点P的距离和角度β之间的关系是:

| P |/r=tan(β)
β=atan(| P |/r)
如果球面到平面的投影为:

float beta=rel_dist*half_angle;
vec3 pos_prj=rel_P*tan(β)/half_dist;
平面到球面的投影为:

float beta=atan(相对距离*半距离);
vec2位置prj=相对P*β/半β角;
请参见下面的WebGL示例,该示例在实现算法的地方使用片段着色器。角度α设置为统一变量
u\u alpha

如果
u_alpha>0.0
,则计算从球面到平面的投影。
如果
u_alpha<0.0
,则计算平面到球面的投影

(函数loadscene(){
var画布,gl,vp_大小,纹理,prog,bufObj={};
函数initScene(){
canvas=document.getElementById(“ogl画布”);
gl=canvas.getContext(“实验性webgl”);
如果(!gl)
返回;
纹理=新纹理(“https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/supermario.jpg" ); 
texture.bound=false;
progDraw=gl.createProgram();
for(设i=0;i<2;++i){
让source=document.getElementById(i==0?“绘制着色器vs”:“绘制着色器fs”).text;
让shaderObj=gl.createShader(i==0?gl.VERTEX\u着色器:gl.FRAGMENT\u着色器);
gl.shaderSource(shaderObj,source);
总编编辑主任(shaderObj);
let status=gl.getShaderParameter(shaderObj,gl.COMPILE_status);
如果(!状态)警报(gl.getShaderInfoLog(shaderObj));
总承包商attachShader(progDraw,shaderObj);
总账链接程序(progDraw);
}
status=gl.getProgramParameter(progDraw,gl.LINK\u status);
如果(!状态)警报(总账getProgramInfoLog(progDraw));
progDraw.inPos=gl.getAttribLocation(progDraw,“inPos”);
progDraw.u_时间=总账获取统一位置(progDraw,“u_时间”);
progDraw.u_分辨率=gl.getUniformLocation(progDraw,“u_分辨率”);
progDraw.u_纹理=gl.getUniformLocation(progDraw,“u_纹理”);
progDraw.u_角度=gl.getUniformLocation(progDraw,“u_角度”);
总账使用程序(progDraw);
var pos=[-1,-1,1,-1,1,1,1];
var inx=[0,1,2,0,2,3];
bufObj.pos=gl.createBuffer();
gl.bindBuffer(gl.ARRAY\u BUFFER,bufObj.pos);
总账缓冲数据(总账数组缓冲区、新Float32Array(pos)、总账静态绘图);
bufObj.inx=gl.createBuffer();
bufObj.inx.len=inx.length;
gl.bindBuffer(gl.ELEMENT\u ARRAY\u BUFFER,bufObj.inx);
gl.bufferData(gl.ELEMENT\u ARRAY\u BUFFER、新UINT16阵列(inx)、gl.STATIC\u DRAW);
gl.EnableVertexAttributeArray(progDraw.inPos);
gl.VertexAttributePointer(progDraw.inPos,2,gl.FLOAT,false,0,0);
总帐启用(总帐深度测试);
gl.clearColor(0.0,0.0,0.0,1.0);
window.onresize=调整大小;
调整大小();
请求动画帧(渲染);
}
函数resize(){
vp_size=[window.innerWidth,window.innerHeight];
canvas.width=vp_大小[0];
canvas.height=vp_大小[1];
}
函数渲染(deltaMS){
scale=document.getElementById(“scale”).value/100*2.0-1.0;
总图视口(0,0,canvas.width,canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);