我所理解的cocos2dx - OpenGL Es2.0 概览

  GPU:以前用cpu来做渲染,但cpu是串行架构的,这样就会导致渲染效率很低,后来就发明了gpu,gpu是并行计算的,同时处理多任务。衡量gpu性能的一个重要术语叫 每秒像素填充率。

  oepngl es:一套图形硬件的软件接口,直接和gpu交互,多应用于各类嵌入和手持平台

 

OpenGL ES 2.0渲染管线

 

 

左边为客户端,右边为opengl服务端。客户端将顶点,着色器程序,纹理和其他gl状态传入服务端,然后客户端调用绘制命令,gl就对输入的图元执行一系列处理,把结果的像素填入到帧缓冲,交换缓冲区就显示在屏幕上。

  过程中,顶点着色器和片段着色器是可编程的,程序可通过提供着色器程序达到在gpu中渲染管线的目的。其他阶段只能用一些固定的gl命令来影响该阶段的执行

 

顶点数组

  传入opengl es前,,3d模型会转为一组图元的集合。每个图元都是一个点,线段或者三角形(或者多边形),模型间独立绘制,修改模型的某些设置不会影响其他模型的绘制。

  图元都是由一个或多个顶点组成,组成线段或者三角形,每个点都关联着数据,包括坐标,颜色,法向量和纹理坐标。

  通过绑定顶点缓冲对象(vertex buffer objects,vbo),把顶点数组数据传入到渲染管线。

  opengl中命令按接受顺序执行,所以一组图元绘制完毕才会绘制下一组。

 

顶点着色器

  顶点着色器是一段类似c的程序,由程序员提供在gpu执行,对顶点运算。可计算顶点的坐标,颜色,光照,纹理坐标。

  着色器最重要的任务就是顶点坐标转换,即游戏的坐标系转为opengl的坐标系,这里就执行模型视图变换,转为裁剪坐标系,顶点着色器转换后的坐标存于gl_Postion。

  着色器另一个功能是向后面片段着色器提供一组易变变量,用于图元装配阶段后的插值计算,具体后续补充。

 

图元装配

 

  顶点数组进入gl渲染管线时,顶点坐标位于应用程序的本地坐标系,着色器计算后转为裁剪坐标系,通常是向顶点着色器传入一个模型视图变换矩阵,执行坐标变换实现。

 

  裁剪坐标系定义在一个视锥体里,这是游戏的可视空间,由6个面组成,如下图。

  图元如果和任意面相交,会触发裁剪,产生新图元。透视裁剪需要每个图元和6个面进行相交计算并产生新图元,影响性能。如果在x或y方向上超出屏幕(glViewport定义)部分,则不用产生新图元,在视口变换时候高效丢弃。

  视锥体在3d游戏里通常表现为一个摄像机,观察点为原点,可通过gluPerspective定义其结构(开口大小,平面尺寸等),gluLookAt定义观察点。

  视锥体远近平面比例应该保持一致,否则转为屏幕时会导致图元变形。

  视锥体裁剪后需要透视分离,投影到视口上,称为规则化的设备坐标系,取值[0,1]。最后规则化后的坐标经过视口变换转为屏幕坐标,视口位置和尺寸通过void glViewPort(Glintx, Glint y, GLsizei w, GLsizei h)定义,左下角起点,单位都是像素。

 

光栅化

  在光栅化之前,要判断图元是面对观察者还是背对观察者,以决定是否丢弃图元,glFrontFace命令来决定哪个反方向为正,glCUllFace命令决定保留哪个方。这样做减少不必要的绘制。方向的确定主要通过顶点的索引,索引都是按顺序的,可通过顺序的方向来决定。

  光栅化会对图元的片段采样,以决定哪些片段位于图元内。过程中,片段坐标值是离散的正数,丢失精度,可能出现锯齿。

  而后,片段着色器就能使用这坐标值对该片段进行着色,最终化为一个像素。光栅化中还要计算顶点着色器定义的易变变量的插值,给后面的片段着色器做插值使用。

 

片段着色器

  这是可编程的,可实现高级特效,如贴图,光照,环境光,阴影等。其作用主要是计算每一个片段的颜色值。

  片段着色器根据顶点着色器输出的顶点纹理坐标对纹理采样,计算该片段颜色,最后写入帧缓冲。实际上还有放大缩小等问题,一般可通过glTexParameter设置一些处理方式,例如多级纹理。

  片段着色器可执行光照等高级特效的地方,例如传入光照位置和光源颜色,经过一定公式计算得出新颜色,就有光照效果了。

 

片段测试

  像素所有权:像素位置所有权是否属于OpenGL Es,例如被其他窗口挡住了

  裁剪测试:glScissor设定一个矩形,在区域外的都被丢弃

  多重采样片段操作:就通过某种采样方式来计算颜色

  深度测试:貌似3d里的概念,3d里存在远近,近的覆盖远的,所以需要一个深度测试,放弃一些像素点的绘制

  模版测试:通过预设的条件,一般为mask值,如果通过条件则通过测试,否则丢弃,具体应用有ClippingNode

  混合:描述图片和场景当前位置的颜色组合

  完成片段测试后,就能写入帧缓存区了,然后显示。

 

渲染管线中的并行计算

  opengl es是按顺序执行命令,但每一个阶段都是并行的,而阶段内部被拆分成多个子任务,也是并行的,也就是纵向横向都并行。正因为如此,所以计算需要的数据都得依赖于传入和状态的设定。opengl es是一个状态机,很多操作都依赖当前特定状态值,这样做能保证并行计算,提高渲染效率

 

构建高性能渲染引擎

  减少渲染次数(draw call):主要是每一次draw call都会伴随着数组和纹理的复制(cpu->gpu),纹理的复制是十分耗的,减少调用能减少这些复制,可以在一次调用中传递更多的顶点数组,使用同一张纹理的操作尽量合并。cocos2dx提供的纹理batch类就是做相似的工作

  渲染从主线程分离:利用cpu多线程的优势,避免cpu和gpu速度差异带来对性能的影响。绘制命令集中可方面优化。但cocos2dx是单线程,但绘制逻辑已经从ui树中抽离,做成了单独的command,后面会说。

 

帧缓冲

  渲染管道最后目的就是将每个像素点的颜色,深度,模版等数据传送到帧缓冲区。

  帧缓冲区存储着所有像素点的颜色深度和模版值,一个帧缓冲对应3个附加点,组成一个逻辑缓冲区,分别存颜色,深度和模版数据。每个附加点绑定到一个渲染缓冲对象。颜色和深度附加点可以绑定到一个纹理上,就可以绘制到纹理而不是显示设备了。

  视窗系统提供帧缓冲,可多个,切换不需要切换opengl es上下文。

内容绘制到视图帧缓冲才会显示在屏幕,一般采用双缓冲区,一个显示,一个后台绘制,绘制完切换到前台显示,达到流畅显示的效果。

 

posted on 2017-06-13 21:48  usp10  阅读(2053)  评论(2编辑  收藏  举报

导航