OpenGL学习之着色器与渲染管线

OpenGL学习之着色器与渲染管线

看此篇之前请看https://www.jianshu.com/p/68ee05d6106a

着色器与渲染管线

渲染管线一般是有显示芯片(GPU)内部处理图形信号的并行处理单元组成。这些并行处理单元两两之间是相互独立的,在不同型号的硬件上独立处理单元的数量也有很大的差异。

图中阴影部分是可编程的部分

enter image description here
  1. 基本处理
    该阶段设定3D空间中物体的顶点坐标,顶点对应的颜色,顶点的纹理坐标等属性,并且指定绘制方式。

  2. 顶点着色器
    顶点着色器是一个可编程的处理单元,功能为执行顶点的变换,光照,材质的应用于计算等顶点的相关操作。工作过程为首先将原始的顶点几何信息及其他属性传送到顶点着色器中,经过自己开发的顶点着色器处理后产生纹理坐标,颜色,点位置等后继流程需要的各项顶点属性信息,然后将其传递给图元装配阶段。
    顶点着色器的输入主要为待处理顶点相应的attribute变量,uniform变量,采样器以及临时变量;输出主要为经过顶点着色器生成的varying变量及一些内建输出变量。

顶点着色器的输入数据由下面组成:
Attributes:使用顶点数组封装每个顶点的数据,一般用于每个顶点都各不相同的变量,如顶点位置、颜色等。
Uniforms:顶点着色器使用的常量数据,不能被着色器修改,一般用于对同一组顶点组成的单个3D物体中所有顶点都相同的变量,如当前光源的位置。
Samplers:这个是可选的,一种特殊的uniforms,表示顶点着色器使用的纹理。
Shader program:顶点着色器的源码或可执行文件,描述了将对顶点执行的操作。

输出变量-易变比那里在顶点着色器赋值后并不是将赋的值送入后后继的片元着色器中,而是在光栅化阶段由管线根据片元所属顶点对应的顶点着色器对此易变变量的赋值情况及片元与各项顶点的位置插值产生。

enter image description here

下面是一个用opengl es着色器语言编写的顶点着色器源码,这个顶点着色器使用一个position和跟它相关联的color数据作为输入数据,通过一个4×4矩阵变换位置,然后输出变换后的位置和颜色数据。

 // uniforms used by the vertex shader
 uniform mat4 u_mvpMatrix; // matrix to convert P from model
 // space to normalized device space.
 
 // attributes input to the vertex shader
 attribute vec4 a_position; // position value
 attribute vec4 a_color; // input vertex color

 // varying variables – input to the fragment shader
 varying vec4 v_color; // output vertex color
 void main() {
 v_color = a_color;
 gl_Position = u_mvpMatrix * a_position;
 }
  1. 图元装配(primitive assembly)
    顶点着色器之后,渲染管线的下一个阶段是图元装配,图元是一个能用OpenGL ES绘图命令绘制的几何体,绘图命令指定了一组顶点属性,描述了图元的集合形状和图元类型。顶点着色器使用这些顶点属性计算顶点的位置,颜色以及纹理坐标,这样才能传到片元着色器。
    这个阶段主要有两个任务,一个是图元组装,另一个是图元处理。
    图元组装是指顶点数据根据设置的绘制方式被结合成完整的图元,例如,点绘制方式下仅需要一个单独的顶点,每个顶点为一个图元;线段绘制方式则需要两个顶点,每两个顶点构成一个图元。
    图元处理最重要的工作是剪裁,对于每个图元,必须确定它是否位于视椎体内(3维空间显示在屏幕上的可见区域),如果图元部分在视椎体中,需要进行裁剪,如果图元全部在视椎体外,则直接丢弃图元。裁剪之后,顶点位置转换成了屏幕坐标。背面剔除操作也会执行,它根据图元是正面还是背面,如果是背面则丢弃该图元。经过裁剪和背面剔除操作后,就进入渲染流水线的下一个阶段:光栅化。

  2. 光栅化(Rasterization)
    光栅化阶段把图元转换成片元集合,之后会提交给片元着色器处理,这些片元集合表示可以被绘制到屏幕的像素。如下图所示:

enter image description here
  1. 片元着色器
    片元着色器是用于处理片元值及相关数据的可编程单元,其可以执行纹理的采样,颜色的汇总,计算雾颜色等操作。片元着色器主要功能为通过重复执行(每片元一次)将3D物体中的图元光栅化后产生的每个片元的颜色等属性计算出来送入后继阶段;
    片元着色器对光栅化阶段产生的每个片元进行操作,需要的输入数据如下:
    • Varying variables:顶点着色器输出的varying变量经过光栅化插值计算后产生的作用于每个片元的值。
    • Uniforms:片元着色器使用的常量数据
    • Samplers:一种特殊的uniforms,表示片元着色器使用的纹理。
    • Shader program:片元着色器的源码或可执行文件,描述了将对片元执行的操作。

片元着色器也可以丢弃片元或者为片元生成一个颜色值,保存到内置变量gl_FragColor。光栅化阶段产生的颜色、深度、模板和屏幕坐标(Xw, Yw)成为流水线中pre-fragment阶段(FragmentShader之后)的输入。如下图:

enter image description here
  • Varting0~n值的是从顶点着色器传递到片元活色器的易变数据变量,它是由系统在顶点着色器后的光栅化阶段自动插值产生,其个数不一定。

  • gl_FragColor值的是计算后此片元的颜色。一般在片元着色器的最后都需要对gl_FragColor进行赋值。

    下面是一个简单的片元着色器源码,可以跟上面的顶点着色器源码结合绘制一个高洛德着色的三角形。

    precision mediump float;
    varying vec4 v_color; // input vertex color from vertex shader
    void main(void) {
    gl_FragColor = v_color;
    }

  1. 追个片元操作阶段(Per-Fragment Operations)
    片元着色器之后就是追个片元操作阶段,包括一系列的测试阶段。一个光栅化阶段产生的具有屏幕坐标(x,y)的片元,只能修改framebuffer(帧缓冲)中位置在(x,y)的像素。下图是Opengl es 2.0逐片元操作的过程:
enter image description here

Pixel ownership test:像素所有权测试,决定framebuffer中某一个(Xw, Yw)位置的像素是否属于当前Opengl ES的context,比如:如果一个Opengl ES帧缓冲窗口被其他窗口遮住了,窗口系统将决定被遮住的像素不属于当前Opengl ES的context,因此也就不会被显示。
Scissor test:裁剪测试,决定位置为(Xw, Yw)的片元是否位于裁剪矩形内,如果不在,则被丢弃。
Stencil and depth tests:模板和深度测试,传入片元的模板和深度值,决定是否丢弃片元。
Blending:将新产生的片元颜色值和framebuffer中某个(Xw, Yw)位置存储的颜色值进行混合。
Dithering:抖动,可以用来最大限度的减少使用有限精度存储颜色值到framebuffer的工件。
逐片元操作之后,片元要么被丢弃,要么一个片元的颜色,深度或者模板值被写入到framebuffer的(Xw, Yw)位置,不过是否真的会写入还得依赖于write masks启用与否。write masks能更好的控制颜色、深度和模板值写入到合适的缓冲区。例如:颜色缓冲区中的write mask可以被设置成没有红色值写入到颜色缓冲区。另外,Opengl ES 2.0提供从framebuffer中获取像素的接口,不过需要记住的是像素只能从颜色缓冲区读回,深度和模板值不能读回。

注意:Opengl ES 2.0 的Per-Fragment Operations已经不再支持Alpha test 和 LogicOp了,这两个步骤在 OpenGL 2.0 和 OpenGL ES 1.x中是存在的。Alpha test 阶段不再需要的原因是片元着色器可以丢弃片元,所以可以在片元着色器中执行Alpha test。 LogicOp因为很少使用,所以不再支持了。

  1. 帧缓冲
    OpeGL ES中的物体绘制并不是直接在屏幕上进行的,而是预先在帧缓冲区中进行绘制,每绘制玩一帧再将绘制的结果交换到屏幕上。因此,在每次绘制新的一帧时都需要清除缓冲区中的相关数据,否则有可能产生不正确的绘制效果。
    同时,微课应对不同方面的需要,帧缓冲是由一套组件组成的,主要包括颜色缓冲,深度缓冲以及模板缓冲
    • 颜色缓冲用于存储每个片元的颜色值,每个颜色值包括RGBA 4个色彩通道,应用程序运行时在屏幕上看到的就是颜色缓冲中的内容。
    • 深度缓冲用来存储每个片元的深度值,所谓深度值是指以特定的内部格式表示的从片元处到观察点(摄像机)的距离。在启用深度测试的情况下,新片元想进入帧缓冲时需要将自己的深度值与帧缓冲中对应位置的片元的深度值进行比较,若结果小于才可能进行缓冲,否则丢弃。
    • 模板缓冲用来存储每个片元的模板值,供模板测试使用。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容