openGL中投影坐标矩阵的推导

参考:http://www.songho.ca/opengl/gl_projectionmatrix.html
http://www.songho.ca/opengl/gl_transform.html#projection
http://www.linuxidc.com/Linux/2015-08/122229.htm
http://web.cse.ohio-state.edu/~shen.94/5542/Site/Slides_files/coordinates5542.pdf(ndc到屏幕空间转换)
在这里插入图片描述
计算机屏幕是2D表面,openGL渲染的是3D场景,但最终要投影到2D的计算机屏幕上。GL_PROJECTION矩阵就是干这个的。顶点数据经过摄像机空间转换到裁剪空间,除以裁剪坐标的w分量得到ndc坐标。所以我们要记住裁剪坐标转换和ndc坐标转换都集成在了GL_PROJECTION矩阵。下面部分描述怎么样通过左右上下前后这6个边界参数创建投影矩阵。
注意,视锥体裁剪是在裁剪坐标下执行的,在除以w之前。裁剪坐标x、y、z是通过和w比较来测试的。如果任何裁剪坐标(x、y或z)大于w或者小于-w,则这个顶点就会被舍弃掉。当发生裁剪时,openGL会重建多边形的边。
#透视投影
下面为透视投影的视锥体
这里写图片描述

其中,远裁剪平面距离原点为f, 近裁剪屏幕距离原点n。
设P(x0, y0,z0)投影到近平面上的Pn(x1, y1, z1)。
如下图所示,摄像机坐标是在右手坐标系下的,但NDC用的是左手坐标系。也就是说,摄像机看向的是摄像机空间的-z轴,却是ndc坐标系的+z轴。
这里写图片描述
由于glFrustum()只接受near和far的正值,所以我们需要在创建GL_PROJECTION矩阵时,将near和far取反。
这里写图片描述
如图所示,我们分别求x1,y1,z1。沿着x轴方向看横切面如图所示:
这里写图片描述
投影后,x坐标为x1(在近裁剪平面投影),由相似三角形的性质,有:
这里写图片描述

n为负,是由于视锥体和投影矩阵坐标系不同,一个是view空间,一个是投影空间。z轴方向不同
这样其实实现了透视投影近大远小的效果,因为z0越大,则x1,y1越小。为了将这两个值转换到[-1,1]区间内,设l和r分别为近裁剪平面左右边框的x左边,即l=-w/2,r=w/2。为了使任何投影到近裁剪空间的点都在区间内,转换后,[l’, r’]属于[-1,1],其中l’,r’分别为l和r转换后的值。因为是线性变化,可另归一化后得到的x2=kx1+b; 再进一步根据上面公式中,x1和x0的关系,得到x2和x0的关系。x2用x0和z0表示,(即从相机空间到ndc空间),如下:
这里写图片描述
同理,y2=ky1+b; 再进一步根据上面公式中,y1和y0的关系,得到y2和y0的关系。y2用y0和z0表示(即从相机空间到ndc空间),如下:
这里写图片描述
x和y投影后的左边都有共同因子[-1/z0],也就是说,他们都除以-z0(也是-相机空间的z,等于ze)。这是构建GL_PROJECTION矩阵的关键。view空间坐标乘以GL_PROJECTION矩阵后,裁剪坐标系还是一个齐次坐标。通过除以裁剪坐标系的w转换为NDC.如下图所示:
CLIPtOndc
所以我们可以将裁剪坐标系的w设为-z0。所以,GL_PROJECTION矩阵的第四行变成(0,0,-1,0),如图:
裁剪矩阵第四行
接下来,我们看z要满足什么要求。为了简化讨论,根据以上结论,我们假设透视变换有下述形式(图片的p就是上面公式的b,bottom):
这里写图片描述

这里写图片描述
于是
这里写图片描述
最后的变换矩阵为:
这里写图片描述

如果视锥体是对称的,r=-l,t=-b,则
这里写图片描述

z存在关系:
这里写图片描述
另外我们再看一个z2和z0关系,你会发现上述函数是有理函数,而z2和z0之间并不是线性关系。在近裁剪平面附近的地方精度较高,远裁剪平面附近的则较低。如果[-n,-f]范围变大,则会引起深度精度问题(z-fighting)。在远裁剪平面附近的z0值的很小的变化不会影响z0。所以n和f之间的距离应该尽量小,以减小深度缓存的精度问题。如图所示:
在这里插入图片描述
在这里插入图片描述

正交矩阵只需要考虑屏幕的最大最小值。上面的“为了将这两个值转换到[-1,1]区间内,设l和r分别为近裁剪平面左右边框的x左边,即l=-w/2,r=w/2。为了使任何投影到近裁剪空间的点都在区间内,转换后,[l’, r’]属于[0,1],其中l’,r’分别为l和r转换后的值。因为是线性变化,可另x’=kx+b;”
不用考虑z的变化,不需要w。
在这里插入图片描述
如果r=-l,t=-b能继续简化。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值