SharpGL之透视投影和摄像机

当三维体放在世界坐标系中后,由于显示器只能用二维图像显示三维休,因此必须要依赖投影来把三维体降低维数。

投影变换的目的就是定义了一个视景体,使得视景体外多余的部分不会显示。

投影包括透视投影(perspective projection)和正视投影(orthographic projection)两种。

上图就是透视投影的效果,它符合人的观察经验,即离视点近的物体大,离视点远的物体小,远到极点就消失,成为灭点。就像笔直马路的尽头看上去就成为一个点。

 

我们看一下代码中有关投影部分的代码, 解释一下相关功能函数的参数意义。

复制代码
 1   private void openGLControl_Resized(object sender, EventArgs e)
 2         {
 3             //  TODO: Set the projection matrix here.
 4             OpenGL gl = openGLControl.OpenGL;
 5             gl.MatrixMode(OpenGL.GL_PROJECTION);
 6             gl.LoadIdentity();
 7 
 8             gl.Perspective(20.0f, (double)Width / (double)Height, 0.01, 100.0);
 9             gl.LookAt(-5, 5, -5, 0, 0, 0, 0, 1, 0);
10 
11             gl.MatrixMode(OpenGL.GL_MODELVIEW);
12         }
复制代码

 

创建透视效果的函数名和原型为: 

Perspective(double fovy, double aspect, double zNerar, double zFar);

aspect是窗口的纵横比

zNerar,zFar分别是近处和远处的裁面位置。

fovy是控制视野在XY平面的角度,范围是0--180度。你可以把它想象成是3dsmax中的相机镜头对应的视野参数。

 

 下面的Perspective函数的示意图中, 视角指的是参数fovy, aspect=w/h, zNerar为近平面距离, zFar为远平面距离.

 

 对于比较难以理解的参数fovy, 如果你仍然不是太明白,下面换个方式说明一下.

 

我们拿3dsmax的摄像机参数来做比喻(意义是类似的),上图是我们使用15mm镜头(视野为100.389度)看到的效果。小镜头看到的视野更大。摄影里面叫这种小镜头叫广角镜头。

 

现在使用85mm的镜头(视野为23.913度),只可以看到物体的局部了。它的可视范围变窄了。

那么 Perspective()函数的fovy参数的意义就等同于镜头所代表的视野度数。

 


设置好投影变换后, 接下来还要设置视点变换. 

设置视点变换的函数LookAt的原形为:

LookAt(double eyex, double eyey, double eyez, double centerx, double centery, double centerz, double upx, double upy, double upz);

这个函数是做视点变换用的,你可以认为它是设置摄像机的函数。

在opengl中,默认时视点定位于坐标系的原点,初使方向指向Z轴负方向,前面说过,默认的三维模形也是贴着世界坐标系的Z轴0的深度上放置的, 因此,如果不进行视点变换,则相当于摄像机正好贴着物体,什么也看不见,这就是为什么上节的代码里面要有一句代码gl.Translate()用于把把物体往Z轴负方向移动一定距离的原因。

 

我们还是以3dsmax中的摄像机来类比。下面的示意图中,我们使用的是一种被称为”目标摄像机“的相机,之所以这么称谓,是因为为这个摄像机带一个目标点可以调节。

 

前三个参数 eyex, eyey, eyez 表示摄像机本身位于世界坐标系中的位置。

 在3dsmax中,摄像机的位置可以任意平移的.

上图我们放置的位置是XY轴刚好对着世界坐标系的原点。Z轴朝正方向走了老远。因为摄像机离物体远了,因此可以正常看到物体。

 

 上图中,摄像机的XYZ都远离了物体做了变换,相当于在围绕三维体进行观察。

 

 当中三个参数 centerx, centery,  centerz 相当于调整了3dsmax目标摄像机的目标点位置。

 如上图所示, 改变目标点的位置也有类似围绕观察对象的效果。并且,这个目标点在Z轴上相对于物体的距离是没有什么意义的,主要意义是在XY上的变化上。这一点读者可以自己去试验。

 

 

 最后三个参数 upx, upy, upz相当于在旋转3dsmax目标摄像机。

不过这个参数的值并不是角度值,而是向量,数值的大小没意义,正负值才有意义。

 

在3dsmax中,摄像机是可以任意角度旋转的。

但是在Lookat()函数中这最后三个参数, upx,upy 只能在上下,左右,45度这几个角度中变换,而且upz取值似乎没什么意义。

 

解释完这两个函数,我们用程序绘制一个三角形来测试一下上述视点变换和投影变换的效果。

上图是视野为20的效果,可以看到三角形看上去大些了。

 

视野改为60,三角形看上去小些了。

以上结果和上面分析Perspective()函数的fovy参数时结论是一致的。

 

现在我们改动LookAt的前三个参数,三角形正对着我们显示了。

 

现在我们改变LookAt的最后三个参数,Y向量改为-1,相当于摄像机旋转向下180度,结果三角形朝下了。

 

posted on 2019-12-19 18:00  NLazyo  阅读(777)  评论(0编辑  收藏  举报