OpengGL ES基础入门----(3)着色器的介绍

着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。

前面的教程里我们简要地触及了一点着色器的皮毛,并了解了如何恰当地使用它们。现在我们会用一种更加广泛的形式详细解释着色器,特别是OpenGL着色器语言(GLSL)。

GLSL

着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。如果你不知道什么是uniform也不用担心,我们后面会进行讲解。

一个典型的着色器有下面的结构:

#version version_number

in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

int main()
{
  // 处理输入并进行一些图形操作
  ...
  // 输出处理过的结果到输出变量
  out_variable_name = weird_stuff_we_processed;
}

当我们特别谈论到顶点着色器的时候,每个输入变量也叫顶点属性(Vertex Attribute)。我们能声明的顶点属性是有上限的,它一般由硬件来决定。OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性,你可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限:

GLint nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

通常情况下它至少会返回16个,大部分情况下是够用了。

数据类型

和其他编程语言一样,GLSL有数据类型可以来指定变量的种类。GLSL中包含C等其它语言大部分的默认基础数据类型:int、float、double、uint和bool。GLSL也有两种容器类型,它们会在这个教程中使用很多,分别是向量(Vector)和矩阵(Matrix),其中矩阵我们会在之后的教程里再讨论。

向量

GLSL中的向量是一个可以包含有1、2、3或者4个分量的容器,分量的类型可以是前面默认基础类型的任意一个。它们可以是下面的形式(n代表分量的数量):

类型    含义
vecn     包含n个float分量的默认向量
bvecn   包含n个bool分量的向量
ivecn   包含n个int分量的向量
uvecn   包含n个unsigned int分量的向量
dvecn   包含n个double分量的向量

大多数时候我们使用vecn,因为float足够满足大多数要求了。

一个向量的分量可以通过vec.x这种方式获取,这里x是指这个向量的第一个分量。你可以分别使用.x、.y、.z和.w来获取它们的第1、2、3、4个分量。GLSL也允许你对颜色使用rgba,或是对纹理坐标使用stpq访问相同的分量。

向量这一数据类型也允许一些有趣而灵活的分量选择方式,叫做重组(Swizzling)。重组允许这样的语法:

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

你可以使用上面4个字母任意组合来创建一个和原来向量一样长的(同类型)新向量,只要原来向量有那些分量即可;然而,你不允许在一个vec2向量中去获取.z元素。我们也可以把一个向量作为一个参数传给不同的向量构造函数,以减少需求参数的数量:

vec2 vect = vec2(0.5f, 0.7f);
vec4 result = vec4(vect, 0.0f, 0.0f);
vec4 otherResult = vec4(result.xyz, 1.0f);

关于OpenGLES渲染管线,请参考博客 [OpenGL ES 02]OpenGL ES渲染管线与着色器。着色器是可编程管线中的术语,其语法类似C语言,分为顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)

顶点着色器

Vertex shader – 在你的场景中,每个顶点都需要调用的程序,称为“顶点着色器”。假如你在渲染一个简单的场景:一个长方形,每个角只有一个顶点。于是vertex shader 会被调用四次。它负责执行:诸如灯光、几何变换等等的计算。得出最终的顶点位置后,为下面的片段着色器提供必须的数据。

vertex shader可通过可编程的方式实现对顶点的操作,如坐标空间转换,颜色及纹理坐标。最简单的Vertex shader如下

attribute vec4 Position;

void main(Void) {
    gl_Position = Position; // must set gl_Position for vertex shader
}

1、attribute声明vertex shader接收的变量,针对每一个顶点的数据。属性可理解为针对每一个顶点的输入数据,只有在vertex shader中才有,在fragment shader中没有。vec4表示由4部分组成的矢量。这里的Position用来传入顶点vertex的位置数据。
2、main是shader脚本的入口。
3、gl_Position是vertex shader内建的输出变量,传递给fragment shader,必须设置。这里将Position直接传递给fragment shader。

片元着色器

Fragment shader – 在你的场景中,大概每个像素都会调用的程序,称为“片段着色器”。在一个简单的场景,也是刚刚说到的长方形。这个长方形所覆盖到的每一个像素,都会调用一次fragment shader。片段着色器的责任是计算灯光,以及更重要的是计算出每个像素的最终颜色

Fragment是可以被渲染到屏幕上的像素点,fragment shader即用于计算每个像素的颜色等属性。最简单的Fragment shader如下

precision mediump float;

void main(void) {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // must set gl_FragColor for fragment shader
}

1、precision mediump float设置float的精度为mediump,还可设置为lowp和highp,主要是出于性能考虑。
2、gl_FragColor是fragment shader唯一的内建输出变量,设置像素的颜色。这里设置所有像素均为红色。

Vertex shader接收多个参数

上边的vertex shader仅接收顶点的位置信息,因此像素颜色都是在fragment shader中写固定的(红色)。而在下边的vertex shader中,通过SourceColor传递像素颜色。

attribute vec4 Position;    // position of vertex
attribute vec4 SourceColor; // color of vertex

varying vec4 DestinationColor; // will pass out to fragment shader

void main(void) {
    DestinationColor = SourceColor;
    gl_Position = Position;
}

1、未声明为attribute的变量即为输出变量(如DestinationColor),将传递给fragment shader。
2、varying表示依据两个顶点的颜色,平滑地计算出顶点之间每个像素的颜色。

对应的fragment shader为:

varying lowp vec4 DestinationColor;

void main(void) {
    gl_FragColor = DestinationColor;
}

这里,fragment shader接收来自vertex shader的变量DestinationColor,赋值给gl_FragColor,再输出至OpenGLES。即每个像素的颜色由DestinationColor决定,这样可在代码中精确控制每个像素的颜色。

Vertex shader与Fragment shader的差异

1、shader脚本中有三种级别的精度:lowp,mediump,highp。如precision highp float; 。在vertex shader中,int和float都默认为highp级别。而fragment shader中没有默认精度,必须设置精度描述符,一般设为mediump即可。
2、attribute只作用于vertex shader中,表示接收的变量。在vertex shader中,若没有attribute则为输出变量(输出至fragment shader)。
3、vertex shader的默认输出变量至少应该有gl_Position,另外有两个可选的gl_FrontFacing和gl_PointSize。而fragment shader只有唯一的varying输出变量gl_FragColor。
4、Uniform是全局变量,可用于vertex shader和fragment shader。在vertex shader中通常是变换矩阵、光照参数、颜色等,。在fragment shader中通常是雾化参数、纹理参数等。OpenGLES 2.0规定所有实现应该支持的最大vertex shader的uniform变量个数不能少于128个,而最大fragment shader的uniform变量个数不能少于16个。
5、simpler是一种特殊的uniform,用于呈现纹理,可用于vertex shader和fragment shader.

本文主要参考:http://learnopengl-cn.readthedocs.io/zh/latest/
http://blog.csdn.net/icetime17/article/details/50436927

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

推荐阅读更多精彩内容

  • 目录结构: 第一步,明确要干嘛 第二步,怎么去画(纯理论) 第三步,怎么去画(实战) 第四步,练练手 第一步,明确...
    半纸渊阅读 8,068评论 18 57
  • 你好,三角形 图形渲染管线(Pipeline) 3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Pi...
    IceMJ阅读 7,420评论 2 13
  • 1 前言 一直想沿着图像处理这条线建立一套完整的理论知识体系,同时积累实际应用经验。因此有了从使用AVFounda...
    RichardJieChen阅读 5,649评论 5 12
  • 着色器(Shader) 着色器是运行在GPU上的小程序。这些小程序为图形渲染管线的一个特定部分而运行。从基本意义上...
    IceMJ阅读 1,664评论 0 6
  • (馬齒莧) 嶺南草藥五行草 五行草 別名 瓜子菜、蜆肉菜、老鼠耳 拉丁名:Portulaca oleracea L...
    远水生方阅读 1,070评论 0 2