首页 > 学院 > 开发设计 > 正文

OpenGL的渲染流程梳理

2019-11-09 18:30:22
字体:
来源:转载
供稿:网友

渲染可以拆分为多个步骤(stage),拆分之后,就可以使用管道(pipeline)来优化执行效率。打个比方,过安检的时候,至少有三个步骤,把包放在传送带上,然后走过去,取回传送带上的包。在排队过安检的过程中,排在后面的旅客并不需要等前面的旅客完成,只要前面的旅客把包放上传送带(完成第一个步骤),后面的旅客就可以接着把包放在传送带,这就是管道原理。

Step1 准备顶点数据(vertex specification)。对于现在使用硬件加速的渲染技术,这个步骤是在CPU上完成的。如果要渲染一个三角形,这一步需要几个信息:三个点的位置和顶点颜色、以及绘制对象:“三角形”。

以下这段代码是个人随手而写,并非真的OpenGL代码,只是用来描述Step1。

var glState = OpenGLState.getInstance();var arrbuf = new ArrayBuffer();//new a array buffer to store the data//vertex positionarrbuf.push({0, 1});arrbuf.push({-0.5, 0});arrbuf.push({0.5, 1});//vertex colorarrbuf.push({255, 0, 0});arrbuf.push({0, 255, 0});arrbuf.push({0, 0, 255});var vertextArr = new VertexArray(arrbuf);vertextArr.setAttr1(0, 2);//attr1 for positionvertextArr.setAttr1(3, 5);//attr2 for colorglState.vertextArr = vertextArr;var vertextShader = new Shader("your vertex shader code");glState.vertextShader = vertextShader;var fragShader = new Shader("your fragShader");glState.fragShader = fragShader;// other Operation to configure glStateglState.run();// the run call will trigger the gl render stages blow

Step2 处理顶点(vertex PRocessing),根据每个顶点的数据(在前一步指定了),以及一些常量(uniform)(在前一步指定了),进行一次分析处理,例如,是否需要对每个顶点的位置做一次位置的变换(transform)(在3D渲染中,变换非常重要)。在可编程(programmable)的渲染管道中,顶点处理可以细分为三个可编程的步骤,第一个小步骤的指令可以vertext shader来指定,第二个小步骤叫tessellation,又可以再细化3个步骤,由2个shader加上一个内置的程序(fixed-function)来控制,第三个步骤由geometry shader来控制,第一个步骤是必须的,后两个步骤是可选的。

Step3 顶点的后续处理(vertex post-processing),上一个步骤产生的所有顶点信息,会在这里进一步处理。这个步骤是不可以编程的,所以没有相应的shader,但是可以配置。通过配置,可以实现transform feedback,前一个步骤处理完产生的数据,可以在这一步反馈回CPU。如果不需要绘制到屏幕上,这个步骤可以中断。如果不中断,则会进行裁剪(clipping),打个比方,原先的三角形,如果有个点不再可视范围内,那么这个三角形会被处理成2个三角形,增加2个在可视边界上的顶点。根据可配置的viewport提供的信息,对顶点的位置投影(projection)到一个平面(window space)上,要么做透视处理(perspective),要么做正交处理(orthographic)。

Step4 对绘制对象的整合(primitive assembly),将前面产生的顶点,根据第一个步骤指定的绘制对象信息,打包成一个个的assembly,然后交给下一个步骤处理。如果第二个步骤中需要进行tessellating,或者需要执行geometry shader,那么在vertex shader之后,也会紧接着完成一个简单的”绘制对象整合”。

Step5 进行光栅化处理(rasterization),管道里会有一个不可编程的程序称为rasterizer。所谓光栅化,就是根据顶点的位置信息,加上分辨率信息,对渲染对象所在的一个包围盒里(包含绘制对象的最小的一个像素矩阵表),凡是判断到像素格子受到影响,就会生成一个fragment信息。这个fragment信息不一定是整个像素格子。

Step6 可编程的并且可选的(optional)步骤,交由fragment shader来处理。这个步骤的结果是将颜色、深度等信息输出,也可以输出自定义信息。当涉及的多重采样(MSAA),一般情况,shader只会针对每个fragment执行一次。但如果在shader中,使用了gl_SampleID,则shader会针对每个采样执行一次。

Step7 对fragment shader的输出进行最后的处理(per-sample processing)。这一步会判断fragment shader的输出是否有效,如果无效则忽略,最后会将最终的颜色写入framebuffer,或者跟framebuffer相应位置的颜色进行混合(blend)。其中,判断输出是否有效那些子步骤,在新的OpenGL版本中,可以提前到fragment shader处理之前,这种情况的输入是来自rasterizer。

参考 [1] Rendering Pipeline Overview


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表