鱼眼投影方式(Fisheye projection)的软件实现

简单实现

鱼眼模式(Fisheye)和普通的透视投影(Perspective projection),一个很大的区别就是鱼眼的投影算法是非线性的(non-linear),实际照相机的情况是在镜头外面包围一个半球体,将场景通过半球体投影到画布上。大致如下:

               M
                 x                 
                                  
                     ______       
                 M'_x'      `-.
                 ,' |         `.
                /   |           
               /    |            
              |     |             |
    __________|_____|____\_________|_________
                    M"    O        1
                    
M: world position
M': projection of M on the unit hemisphere
M": projection of M' on the unit disc (= the screen)

上面这个示意图来自stack exchange 的回答,是Sam Hocever画的

vertex shader 绘制一个长宽均为1的正方形,作为远处的物体,纹理实际贴在这个正方形上面。

在 fragement shader 内将上面的这个算法实现即可。

设我们在屏幕上的点为(x0, y0) 直接得到外面球面上的点是
(x0, y0, z0) and z0 = sqrt(1 - x0^2 - y0^2)
远处平面上的点和球面上的点共线所以坐标成比例关系,直接设x1 = a * x0然后假设我们的远处的物体就是一个平面,处于 z1 = -1 的位置,直接得到:

因为: 
abs(z1) = 1 = z0 * a
z0 = sqrt(1 - x0^2 - y0^2)
所以:
a = 1.0 / z0 = 1.0 / (sqrt(1 - x0^2 - y0^2))

当然远处平面的位置可以调整,离的近就大,离的远就小,但是大小是不变的,仍然是一个边长为 1 的正方形。所以可以调整的就是这个距离,也是 z1 的值。Sam Hocever 提供的思路是改变这个投影的 fov 的值。当 fov = PI / 2 时,和我刚刚设定的值一样,z1 = -1。两者关系为
z1 = 0.5 / tan(theta / 2)

总结:a = z1 / z0 = 0.5 / ((sqrt(1 - x0^2 - y0^2)) * tan(theta / 2))

其他实现方式

主要参考 Computer Generated Angular Fisheye Projections
上文介绍了两种投影的方式,第一种前文已经解释,后一种方式我正在学习中。

另外还有一个经典的项目,blinky
提供另外一种解决的办法,先弄出一个包围盒,纹理贴在包围盒上,然后在转换成鱼眼效果。
具体的实现看源码。

本文的主要参考链接

[How do I create a wide-angle / fisheye lens with HLSL?](http://
gamedev.stackexchange.com/questions/20626/how-do-i-create-a-wide-angle-fisheye-lens-with-hlsl)

原文地址:https://www.cnblogs.com/psklf/p/6075088.html