WebGL学习系列-片元着色器简介

前言
到目前为止,我们绘制过点、三角形、矩形等,但使用的都是单色系。之前曾经说过着色器的概念,着色器分为顶点着色器和片元着色器,我们一直在使用顶点着色器,而对片元着色器基本没有提及过,本小节将展开对片元着色器的简单介绍。

彩色的点
之前提到过,顶点着色器决定点的大小、位置和颜色,而片元着色器是用于给像素着色的,初步看,片元着色器的任务好像给顶点着色器完成了,但实际上不然,顶点着色器只能决定点的颜色,如果绘制成了图形,图形填充的颜色就该由片元着色器处理了。

先来看一下我们将要绘制的彩色点的效果图: 

WebGL学习系列-片元着色器简介_第1张图片
我们一共绘制了三个点,而且三个点的颜色不同,接下来分析下代码,先来看下顶点着色器的代码:

// 顶点着色器代码(决定顶点的位置、大小、颜色)
var VSHADER_SOURCE = 
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'varying vec4 v_Color;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' + // 设置顶点的位置
  '  v_Color = a_Color;\n' +        // 顶点设置一个varying类型的颜色值,用于线性化处理
  '  gl_PointSize = 10.0;\n' +      // 设置顶点的大小
  '}\n';

上面的代码定义了两个color变量,然后把attribute类型的颜色变量赋值给了varying类型的颜色变量(你一定有很多疑惑,不要着急,下文会解释的)。

接着看看片元着色器的代码:

// 片元着色器代码(给像素上色)
var FSHADER_SOURCE =
  'precision mediump float;\n' +
  'varying vec4 v_Color;\n' + 
  'void main() {\n' +
  '  gl_FragColor = v_Color;\n' + // 设置像素的颜色
  '}\n';

片元着色器代码中,也定义了一个varying变量,而且变量名字也叫v_Color,最后把v_Color赋值给了内置颜色变量gl_FragColor,从而决定了像素点的颜色。一起来看一下变量传递说明图:

WebGL学习系列-片元着色器简介_第2张图片

我们会定义好一个顶点颜色缓冲区,然后逐顶点传递给顶点着色器中的a_Color变量,而a_Color赋值给了v_Color变量。最需要关注的就是,在顶点着色器和片元着色器中,两个varying变量直接关联赋值了,这是两种不同着色器传递信息的方式,以后介绍纹理时也会使用此种方式来传递坐标信息。最后在片元着色器中的v_Color变量就获取到了一个线性化的颜色值,然而最终决定像素颜色值的是gl_FragColor这个内置变量,所以最后进行了赋值。

我初步看到的时候也发现实在是复杂,但没办法,底层就是这样处理的,我们要确保需要传值的两个varying变量名称是一致的。varying用于着色器间信息的传递,它命名为varying,表示变化的意思,还有更加深层次的应用,稍后我们会继续解释。

初始化颜色信息跟初始化顶点信息非常的类似,代码如下:

// 三个顶点的颜色
 var verticesColors = new Float32Array([
    1.0,  0.0,  0.0, 
    0.0,  1.0,  0.0, 
    0.0,  0.0,  1.0
]);
// 创建一个缓存对象,用于存放顶点颜色数据
 var colorBuffer = context.createBuffer();
 // 绑定缓存对象
 context.bindBuffer(context.ARRAY_BUFFER, colorBuffer);
 // 把数据写到缓冲对象中
 context.bufferData(context.ARRAY_BUFFER, verticesColors, context.STATIC_DRAW);
 // 获取顶点着色器代码中的顶点颜色变量
 var a_Color = context.getAttribLocation(context.program, 'a_Color');
 // 设置变量获取数据规则
 context.vertexAttribPointer(a_Color, 3, context.FLOAT, false, 0, 0);
 // 允许变量从 ARRAY_BUFFER目标上绑定的缓冲区对象获取数据
 context.enableVertexAttribArray(a_Color);

这里相信大家都很熟悉了,不再展开说明。

神奇的彩色三角形
到这里,我们已经学会使用varying变量来绘制多个不同颜色的点,接下来,我们把上一个示例给绘制成三角形,而不是点,如下代码所示:

// 绘制一个三角形
context.drawArrays(context.TRIANGLES, 0, n);

结果如下: 

WebGL学习系列-片元着色器简介_第3张图片
是不是感觉很惊讶,咱们只在三个顶点中定义了颜色,结果看起来像是自动会渐变的。这就是片元着色器之所以叫片元的地方了。我们先来看渲染原理图:

WebGL学习系列-片元着色器简介_第4张图片

顶点着色器用于决定顶点的位置、大小和颜色(严格上来讲,是顶点关联了一个颜色值)
确定了顶点信息后,便可以绘制出三角形图形
有了三角形图形,webgl内部会对三角形进行光栅化,简单来讲,就是把三角形拆解成一个一个的像素点,然后发现了varying修饰的v_Color变量,利用顶点颜色信息,以及使用线性化计算方式,给每个像素点计算一个线性化的v_Color值,这就是varying有变化的意思的由来。在顶点中定义的varying变量,实际上,对于每个像素点,都有不同的值,最后调用片元着色器,把每个像素的颜色值(独有的v_Color值)传递给了片元着色器,最后设置到了颜色缓冲区,以便于最终在浏览器上显示。
着色器三大变量
通过前面的学习,我们一共接触了三种类型的着色器变量,分别是 attribute,uniform和 varying,现在简单回顾一下。 
1. attribute 变量用于顶点着色器中,表示普通的变量。 
2. uniform 变量用于顶点着色器和片元着色器中,用于表示不变的变量,比如,在顶点着色器中,表示点大小的变量,可以使用uniform,如果所有的顶点大小一致。 
3. varying 变量用于顶点着色器和片元着色器之间的传递信息,通常用于传递颜色信息和坐标信息(比如纹理坐标)。

小结
理解片元着色器是按照逐像素进行着色是非常关键的,而顶点着色器则是逐顶点执行的。我们使用varying变量在顶点着色器和片元着色器之间共享数据,而且要注意的是,varying针对第个像素都有一个线性化的值,参考彩色三角形效果图就知道了。varying不仅仅用于传递颜色信息,它还经常用于传递纹理坐标信息,以便进行贴图。

你可能感兴趣的:(HTML5)