学习OpenGL-ES: 3 - 3D绘图原理

1,成像模型

计算机图形的生成,总是可以抽象成三个过程:输入数据 -> 处理数据 -> 输出人眼识别的图像。

其中最后一个过程,在之前的文章:学习OpenGL-ES: 1 - 像素、颜色、显存、初始化 中已经有过比较详细的描述,最终输出的是像素(颜色)点阵,由硬件激发显示屏,发射出相应颜色的光线,被人眼接受,形成图像视觉。所以OpenGL ES 的绘图过程可描述为:输入数据 -> 处理数据 -> 输出像素点阵。  

那么,输入数据和处理数据又是怎样的呢?

很自然的可以想到通过模拟人眼的输入和处理过程来进行计算机处理。对人眼而言,观察物体实际上是物体在视网膜成像的过程,首先存在物体,然后存在光源,物体反射(自发射)光线,这些光线进入人眼,在视网膜成像,刺激视觉神经细胞,令人产生视觉。 

相应的,对于计算机,我们需要描述物体,描述光源,模拟光源和物体的作用过程(吸收、反射、折射光线),模拟视网膜成像;但人眼本身是一个非常复杂的器官,很难完全对其进行模拟,一个简化方法是使用相机模型来代替人眼模型。和人眼模型相比,我们同样需要描述物体,描述光源,模拟光源和物体的作用过程,但是只需要用比较简单的相机成像来替代复杂的视网膜成像即可。

所以,OpenGL ES的绘图过程可描述为:输入物体数据、光源数据 -> 模拟光照,模拟投影(成像) -> 输出像素点阵。 

2,输入物体数据 

如何描述一个物体?让我们看看一个物体有哪些属性(对于视觉而言): 

  a, 位置:

    首先,我们需要知道物体的位置,如果物体在我们的视野以外,我们就无法看到它。 

  b,朝向:

    其次,我们需要知道物体的朝向,当物体侧面对着我们时,我们看到的内容是不同于物体背面对着我们时的。 

  c,形状:

    这点很明显。 

  d,颜色:

     颜色其实是物体和光线相互作用的结果。

   e, 材质:

    金属表面有光泽,而木头表面比较粗糙,这也是物体和光线相互作用的结果,我们用材质来描述决定这种结果的属性。

 接下来我们看看如何在计算机中去描述这些属性,注意我们是在一个三维空间中:

  a, 位置: 

    人们日常生活中所用的位置总是一个相对值,比如:我在你前面100米。另一个例子是地图,人们查看地图时,总是先确定一个参考点,比如我当前位于XX,然后再确定另一个点:火车站在我右手边2000米。同样,在计算机中,我们也也使用相对位置,我们需要一个参考点,通常这个点是某个坐标系的原点,所有对位置的描述都是相对于这个原点进行的。 

    那么,我们需要在计算机中描述这些东西(注:以下描述为了简单起见,可能不够严谨): 

    坐标系 - 通常是笛卡尔坐标系,通过描述原点(位置)和三个正交基(坐标轴xyz,向量)的数学表示来进行。 

    物体位置 - 物体(中心点)在给定坐标系中的坐标。 

  b, 朝向: 

    同位置一样,这也是个相对值。通常我们先给定一个正方向,然后描述相对于这个正方向的旋转来描述物体的朝向,比如:先让物体处于正方向,然后围绕X轴旋转30度,再围绕Y轴旋转50度,就是现在的朝向。

      那么,我们需要在计算机中描述这些东西: 

    正方向:事实上,我们不需要描述这个东西,我们假定这个东西为1,那么 朝向 = 1 * 旋转,因此我们只需要描述旋转就可以了。

     旋转:有多种描述方式,矩阵、欧拉角、四元数等,后续再进行详细的讲解。

   c,形状:

     三维空间中的物体,可以看做由无数个紧密点组成,也可以看做由无数个紧密曲面组成,这两种表述都需要极大的计算量(有例外),不适合计算机。

     计算机图形学中最常见的方法是使用大量细小的平面去模拟曲面,这个概念比较难以描述,任何看过3D建模工具中模型的线框图的人应该都能很容易理解,如果你不理解,建议去看一看,这里不再赘述。

     平面有很多种,出于效率(算法限制)以及硬件实现复杂度的考量,我们一般要求平面为凸多边形,更进一步,OpenGL ES 只支持三角形。所以,我们使用大量的三角形来描述物体形状;那么,如何描述三角形本身呢,一个直观的想法是描述所有顶点,以及顶点组成三角形的方式,OpenGL ES 确实是采用这样的方式,后续再进行详细的说明。

   d, 颜色:

     当物体受到光照时,对于RGB中的每一种,它都会进行吸收、反射,所以颜色的定义来源于吸收了RGB中的多少,反射了多少。比如假设0代表完全吸收,1代表完全反射,那么(r,g,b) = (1,0,0)表示完全反射红光,吸收蓝光和绿光,那么我们所看到的就是红色的物体(假设使用白光照射)。

  e,材质:

     如果物体表面光滑,则大部分入射光会以相同的角度反射出去,我们称之为镜面反射;反之如果物体表面粗糙,大部分入射光会进行近似无序的散射;真实的物理过程比较复杂,一般我们会采用简化的模型,我们需要描述有多少比例的光进行镜面反射,多少比例的光进行散射。

 3,输入光源数据

 a, 位置:

  光源可视为物体,位置的描述方式和物体一样。

 b, 颜色:

  发射的光线中RGB分量的强度。

 c, 强度:

  光源的亮度。

 d, 方向:

  是球形发射的点光源,还是集中在一个方向的聚光灯,还是无穷远处点光源发射过来的(近似)平行光。

 e, 衰减度:

   随距离增大的衰减程度。

  4,模拟光照

  总体来说分为两大类,局部光照和全局光照:

 局部光照:

   对指定物体,局部光照只考虑光源和这个物体的作用,不考虑其它物体。主要为 Phone光照模型。

 全局光照:

   对指定物体,全局光照不仅仅考虑光源和这个物体的作用,还考虑场景中的其它物体影响,比如光源照在A物体上,A物体反射的光照射在B物体上,则B物体同时受到光源的光和A反射光的影响。

  全局光照主要使用光线跟踪(Ray Tracing)和辐射度(Radiosity)两种方法,前者顾名思义,追踪所有进入人眼的光线(光源直射、反射、反射的反射、反射的反射的反射。。。);后者基于一个场景内光线总能量守恒的原理,进行相应计算。

 全局光照有更好的效果,更复杂的实现,更多的计算量。光照是个复杂的话题,这里只做简单描述。

 5,模拟投影

物体摆好,光源设置好之后,从不同的位置不同的角度观察,所看到的图像是不同的,观察的过程本质上是投影的过程,将三维空间中的点投影到一个2D平面,形成图像。对人眼而言,投影到视网膜,对相机而言,投影到底片。为了模拟投影过程,我们需要设置观察者,以相机为例:

  1,将相机放置在某个位置,这和放置物体是完全一样的。

  2,调整好相机的朝向,这和调整物体朝向是完全一样的。

  3,设定相机的观察范围,所有在这个观察范围内的物体都是可见的,在此之外的物体都是不可见的。观察范围通常是一个多面体,位于多面体内的物体可见,体外的物体不可见,称之为视见体。对照相机来说,这一步对应着调整焦距(视角)。

  4,设定投影平面,这一步和第三步是密切相关的,容易想象,只有投影平面之前的物体才能投影到该平面,而位于投影平面之后的物体都是不可见的。

  5,拍摄(投影)。

  6,冲洗照片,我们可以以任意的尺寸冲洗照片。

6,输出像素点阵

将前面计算得出的像素(颜色)数据写入显存,通知硬件刷新(显示画面)。

7,总结:

OpenGL ES 的粗略绘制过程如下:

用大量三角形构造3D物体,指定物体位置、朝向,设置物体颜色、材质,设定光源,计算光照结果,投影,刷新显示。

以上是我们所推导的绘制过程,OpenGL ES的实际绘制过程包含比这些要多的内容,比如裁剪、纹理等,但其本质不变。

posted on 2013-02-22 17:15  kiffa  阅读(6109)  评论(1编辑  收藏  举报

导航