一点 透视 屏幕坐标 平面坐标_osg-3D世界到屏幕

5c50713503ed7086ed95246c10c58e31.png

前面记录了3D世界如何绘制,今天讨论一下3D世界怎么呈现到屏幕?

1.(模型视图矩阵)model-view matirx

模型矩阵: 用于描述物体在3D世界中的位置,原理是:把模型上所有的顶点从模型本地坐标系变换(乘以模型矩阵)到世界坐标系.

视图矩阵: 作用是变换整个3D世界到摄像机空间.

(PS:opengl是右手左边系,所以OSG也是右手坐标系,Opengl默认摄像机位置在世界中心(0,0,0)的位置,摄像机默认朝向z轴的负方向.)

但是Opengl中没有把模型矩阵和视图矩阵分离开来,而是用统一的一个矩阵表示,三维物体从本地左边系到摄像机坐标系的变换---模型视图矩阵

//变换向量v到摄像机空间结果为Ve
Ve = V * modelViewMatirx;//OSG中矩阵是以行为主(opengl是以列为主),所以向量和矩阵的乘法规则是向量在前矩阵在后

2.(投影矩阵)projection matrix

投影矩阵:是把摄像机空间的三维模型投影显示到二维空间.今天重点介绍一下投影矩阵的原理,以为投影矩阵的理解对于三维开发者有非常重要的意义.

透视投影的原理:

在计算机图形学领域透视投影是作为一种将三维坐标投影为二维坐标的方法,最常用的是正交投影和透视投影.正交投影可以理解为简单的把三维物体沿着摄像机的方向压扁成为二维平面的过程,而透视投影是为了把三维世界更加真实的表现在二维平面的一种算法.

首先要想透视投影成立,需要三个因素:观察者投影平面被投影三维物体.三者关系是:假设人眼即为观察者,我们观察的是三维模型在投影平面上的投影,可以用图来表示:

6d00fb0688bc18667aa19b0d6b2bd37d.png

假设三维世界中有一条经过X点的射线R,X和视点的连线在视平面(也是投影平面)上的交点是Xp,那么Xp即为X点在视平面上的投影.那么射线R上的所有点都可以依照上面的方法在投影平面上找到对应的一点Xp,所有的Xp点就构成了射线R的透视投影后的射线Rp.无论三维模型多复杂,投影的方法都是一样的,如下图:

caf5a10e5f4bcc8ab8850aabcf7540d8.png

透视投影在原理上对于投影平面的大小以及摄像机的位置都是没有限制的.只是在计算机图形学中,我们需要将三维世界的物体投影到各种屏幕,所以投影平面成为了矩形.并且由于计算效率问题,我们需要指定一个最远平面在三维世界中.并且摄像机的视角也是固定的.所以我们可以根据上面的一段话理解为,计算机图形学是把投影的范围退化成为了一个棱台----这就是透视投影的视截体.

e1ed5e932c6b4e41725bf3af01bdfae9.png

关于投影矩阵的推导.

对称的视锥体:中心对称的视锥体,zz轴位于视锥体的中心;

不对称的视锥体:z轴不在视锥体的中央,就好比我们靠近窗户去观察景色,但没有正对窗户中心。

这里我们也分这两种情况来推导:

情况一:对称的视锥体

第一步:根据相似三角形的性质,有:

ee2042bdc465eee97e6b3b495c39ac41.png

第二步:为使视景体内的顶点投影到近平面上,其坐标映射到[-1.0, 1.0]范围内,投影后的点要分别除以width / 2和height / 2,其中width,height分别为近投影平面的宽度与高度,根据第一步结果,有:

381474977e5790c060a1f1a3ab91ecb2.png

第三步:这一步推导深度部分变换,根据第一步和第二步,可以假设投影矩阵具有如下形式:

60a414b3e4b5c4ecc8e4ef28ddc91ad0.png

得到zproj=(Az+B)/z,或Az+B=zzproj 将远平面和近平面z坐标代入上式得(注意注意:在这里,视景体内的深度坐标投影之后,有zproj∈[−1,1]):

6294678508f4af699c158eb4788dca4d.png

得到:

c4ad596c186657586ca4de8bf7780371.png

至此,对称视锥体的透视投影变换矩阵就推导完毕了,最终得到的透视投影变换矩阵为:

e95a3c78a408d23bbf612277825935fb.png

情况二:不对称的视锥体

这一情况看起来较上面复杂一些,其实也没复杂多少,首先,深度投影没什么变化;其次,对于不对称视锥体的xx和yy方向上的投影,只要在对称视锥体的投影基础上平移一下即可,其实只有第一步和第二步有所区别,如下:

第一步:投影,按如下方式进行平移lx和ly,

1d20138994f876a01e99ca5a214bf6bd.png

第二步:将近平面(注:z=−znear)的左、右边缘x坐标代入(1)得:

9809e1e088ad33dd080b4602dcf91db7.png

得:

d83357b0a10912d48d72ef19521486f8.png

同样,将近平面的上、下边缘y坐标代入(2)得:

a76f63077a4943b7945795790f08d541.png

这样,最终的投影变换矩阵为:

e1d6ec2fe8369fe7b0b379e3bdfa632a.png

OpenGL中相关API就需要指定这些参数,来构建投影矩阵,如下:

void glFrustum(    GLdouble left,
     GLdouble right,
     GLdouble bottom,
     GLdouble top,
     GLdouble znear,
     GLdouble zfar);
//top      ——近平面上边缘离中心的距离
//bottom    ——近平面下边缘离中心的距离
//left     ——近平面左边缘离中心的距离
//right    ——近平面右边缘离中心的距离
//znear     ——近平面离视点的距离
//zfar     ——元平面离视点的距离

参数见上,另外还有一个,本质也是一样的,它应该是设置对称的视锥体的透视投影矩阵,即:

void gluPerspective(    GLdouble fovy,
     GLdouble aspect,
     GLdouble zNear,
     GLdouble zFar);
//fovy        —— y方向上的视角
//aspect      —— 宽高比
//zNear       —— 近平面离视点距离
//zFar        —— 远平面离视点距离

通过fov和aspect,可以求出宽度和高度,进而求出透视投影矩阵。

3.转换为屏幕坐标

透视投影后,三维模型就会投影到投影平面,投影平面的坐标系模型(x轴向右,y轴向上,原点在平面中心)如下图

b80e580319eaf4d5890a5b2fb17d762b.png

而我们的屏幕的坐标系模型(原点在左上角,x轴向右,y轴向下)如下图

61907cfa84dbefe2557ae55672326309.png

令视平面坐标系中的点(xp, yp)对应于屏幕坐标系中的点(xs, ys),它们的变换关系如下:

2b139f3d1129fb2c3010533bf22d76cb.png

由上面可知,设视平面的宽度为Wp,高度为Hp;屏幕的宽度为Ws,高度为Hs.视平面中的(0,00, 0)点对应于屏幕坐标系中的中心点(0.5*Ws-0.5, 0.5*Hs-0.5)点对应屏幕坐标系中心点(0.5*Ws-0.5,0.5*Hs-0.5)(PS:由于屏幕坐标系是离散坐标系,所有屏幕右下点的坐标为(Ws-1, Hs-1),而不是(Ws, Hs));另外,视平面的(-0.5*Wp, -0.5*Hp)对应于屏幕的(0, 0)点。将上述两种取值代入变换方程可以得出:

9ce6bb3cb11fcff40eb4c9211c80e1d5.png

这样就完成了3D世界到屏幕的整个过程.

欢迎大家来我的新家看一看3wwang个人博客-记录走过的技术之路

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值