OpenGLES渲染管道,顶点着色器(VertexShader) ,片元着色器(FragmentShader)

着色器只能用在OpenGLES 2.X以上等可编程管道里,而在OpenGLES 1.X是不能使用的。

管线,Pipeline,显卡执行的、从几何体到最终渲染图像的、数据传输处理计算的过程

OpenGLES1.X中它是固定管道,整体式封闭的,中间的各道工艺按固定的流程顺序走。如图所示:

从上图可以看出,这些工艺顺序是固定的,整个过程又分为:处理顶点,处理片元,验证片元信息并存入内存

Rasterizer:光栅化处理,当顶点处理完,会交给rasterizer来进行光栅化处理,结果会吧顶点的坐标信息转换成能在屏幕显示的像素信息,即片元(Fragments)

生成片元后,接下来就是对fragments片元的各种验证,即过滤掉无用的片元,裁剪掉不在视野内的片元,最终把有效片元存储入内存中。

光栅化处理过程,就是把矢量图转化成像素点的过程。我们屏幕上显示的画面都是由像素组成,而三维物体都是点线面构成的。要让点线面变成能在屏幕上显示的像素,就需要Rasterizer这个过程。

OpenGLES2.X可编程管道,由两VertexShader(顶点着色器)、FragmentsShader(片元着色器)组成,分别对应上图中的Coordinates 和Texture等蓝色块

OpenGLES2.0可渲染管道图:

VertexShader:顶点着色器

顶点着色器输入包括:

着色器程序——描述顶点上执行操作的顶点着色器程序源代码或者可执行文件

顶点着色器输入(或属性)——用顶点数组提供的每个顶点的数据

统一变量(uniform)——顶点(或片段)着色器使用的不变数据

采样器——代表顶点着色器使用纹理的 特殊统一变量类型

顶点着色器的输出在OpenGLES2.0称作可变变量(varying),但在OpenGLES3.0中改名为顶点着色器输出变量。

在光栅化阶段,为每个生成的片段计算顶点着色器输出值,并作为输入传递给片段着色器。

插值:光栅器对从顶点着色器传递的变量进行插值

为了在屏幕上真正显示,必须将顶点着色器vs的输出变量设置为gl_Position,gl_Position是一个保存着顶点齐次坐标的4维向量。ZYZ分量被W分量分割(称作视角分割)并且XYZ分量上超过单位化盒子([-1, 1])的部分会被裁剪掉。最终的结果会被转换到屏幕坐标系然后三角形(或其它图元类型)被光栅器生成对应的像素。

OpenGLES3.0新增了一个功能——变换反馈,使顶点着色器输出可以选择性地写入一个输出缓冲区(除了传递给片段着色器之外,也可用这种传递替代)

顶点着色器的输入和输出如下图所示:

先看看脚本:

private final String mVertexShader =

"uniform mat4 uMVPMatrix;\n" +

"attribute vec4 aPosition;\n" +

“attribute vec4 a_color;\n” +

"attribute vec2 aTextureCoord;\n" +

"varying vec2 vTextureCoord;\n” +

“out vec4 v_color;\n"

"void main() {\n" +

" gl_Position = uMVPMatrix * aPosition;\n" +

" vTextureCoord = aTextureCoord;\n" +

“ v_color = a_color;\n"

"}\n";

private final String mFragmentShader =

"precision mediump float;\n" +

"varying vec2 vTextureCoord;\n" +

"uniform sampler2D sTexture;\n" +

"void main() {\n" +

"gl_FragColor = texture2D(sTexture, vTextureCoord);\n” +

"}\n”;

其中脚本语句关键字:

attribute:使用顶点数组封装每个顶点的数据,一般用于每个顶点都各不相同的变量,如顶点位置、颜色等

uniform:顶点着色器使用的常量数据,不能被着色器修改,一般用于对同一组顶点组成的单个3D物体中所有顶点都有相同的变量,如当前光源位置

sampler:这是可选的,一种特殊的uniform,表示顶点着色器使用的纹理

mat4:表示4x4浮点数矩阵,该变量存储了组合模型视图和投影矩阵

vec4:表示包含了4个浮点数的向量

varying:用于从顶点着色器传递到片元或FragmentsShader传递到下一步的输出变量

uMVPMatrix * aPosition:通过4x4 的变换位置后,输出给gl_Position,gl_Position是顶点着色器内置的输出变量。

gl_FragColor:片元着色器内置的输出变量

PrimitiveAssembly:图元装配

图元即图形,在OpenGL有几个基本图元:点、线、三角形,其他的复杂图元都是基于这些基本图元来绘制而成。

在图元装配阶段,那些经过顶点着色器(VertexShader)处理过的顶点数组或缓冲区的数据(VertexArrays/BufferObjects),被组装到一个个独立的几何图形中(点,线,三角形)

对装配好的没个图元,都必须确保它在世界坐标系中,而对于不在世界坐标系中的图元,就必须进行裁剪,使其处于在世界坐标系中才能流到下一道工序(光栅化处理)

这里还有一个剔除操作(Cull),前提是这个功能的开关是打开的:GLES20.glEnable(GLES20.GL_CULL_FACE); 剔除的是图元的背影,阴影,背面等。

Rasterization:光栅化

光栅化阶段绘制对应的图元(点、线、三角形),将图元转化为一组二维数组的过程,然后传递给片段着色器处理。这些二维数组代表屏幕上绘制的像素

(PS:上图中的点精灵光栅化应该是点光栅化)

FragmentShader:片元着色器

片元着色器主要是对光栅化处理后生成的片元逐个进行处理。接收顶点着色器输出的值,需要传入的数据,以及它经过变换矩阵后输出值存储位置。

着色器程序——描述片元所执行的片元着色器程序源代码

输入变量——光栅器对顶点着色器插值后的输出值

统一变量——片元(或顶点)着色器使用的不变的数据

采样器——代表片元着色器所用纹理的一种特殊的统一变量类型

片元着色器输入和输出关系如下图所示:

因为光栅化处理后,图元只是在屏幕上有了像素,却没有进行颜色处理,还是看不到东西。

因此FragmentsShader主要的作用是告诉GPU如何处理光照、阴影、遮挡、环境等,然后将结果输出到gl_FragColor变量中

FragmentsShader只输出一个颜色值——gl_FragColor,是片元着色器内置的输出变量

片元着色器脚本示例:

#version 300 es

precision mediump float; // 设置精度限定符

in vec4 v_color;

out vec4 fragColor;

void main()

{

fragColor = v_color;

gl_FragColor = fragColor;

}

光栅化阶段生成的颜色、深度、模板和屏幕坐标位置(Xw, Yw)将会变成逐片元操作阶段的输入值

Pre-Fragment Operations:逐片元操作阶段

在片元着色器对片元进行综合的处理,并最终为片元生成一个颜色值,并储存在gl_FragColor变量后,接下来就是逐个对片元进行一些列的测试。

光栅化处理时,它由于时把顶点从世界坐标系转换到屏幕坐标系,因此在光栅处理后,每个片元在屏幕上都有个坐标(Xw, Yw)。且存储在了帧缓冲区(FrameBuffer),

包括片元着色器也是对(Xw, Yw)这个坐标的片元进行处理

Pixel ownership test——像素归属测试,它决定FrameBuffer中某个(Xw, Yw)位置的像素是否属于当前Context

Scissor test——裁剪测试,决定一个位置(Xw, Yw)的片元是否位于裁剪举行内,如果不在,则被丢弃

Stencil test/Depth test——模版和深度测试,传入片元的模板和深度值,决定是否丢弃片

Blending——混合,将FragmentShader 新产生的片元颜色值和FrameBuffer中某个位置(Xw, Yw)的片元存储的颜色值进行混合

Dithering——抖动,对可用颜色较少的系统,可以牺牲分辨率为代价,通过颜色值的抖动来增加可用颜色值。抖动操作和硬件相关,OpenGL允许程序员所有的操作就只有打开或关闭都懂操作。默认情况下抖动是激活的

在逐片元操作阶段的最后,片元要么被舍弃,要么将颜色、深度、模板值写入到帧缓冲区(Xw, Yw)位置,写入的值取决于启用的写入掩码

写入掩码可以更精细地控制写入的颜色、深度、模板值。

备注:Alpha测试和逻辑操作不再是逐片元操作的一部分,这两个阶段存在于OpenGL2.0盒OpenGL1.x中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容