WebGL - 着色器

着色器是在 GPU 上运行的程序。着色器使用 OpenGL ES 着色器语言(称为 ES SL)编写。ES SL 具有自己的变量、数据类型、限定符、内置输入和输出。

数据类型

下表列出了 OpenGL ES SL 提供的基本数据类型。

Sr.No. 类型 &描述
1

void

表示空值。

2

bool

接受 true 或 false。

3

int

这是一个有符号整数数据类型。

4

float

这是一个浮点标量数据类型。

5

vec2、vec3、vec4

n 分量浮点向量

6

bvec2、bvec3、bvec4

布尔向量

7

ivec2、ivec3、ivec4

有符号整数向量

8

mat2、mat3、mat4

2x2、3x3、4x4 浮点数矩阵

9

sampler2D

访问 2D 纹理

10

samplerCube

访问立方体映射纹理

限定符

OpenGL ES SL 中有三个主要限定符 −

Sr.No. 限定符和说明
1

attribute

此限定符充当顶点着色器和 OpenGL ES 之间每个顶点数据的链接。此属性的值会随着顶点着色器的每次执行而改变。

2

uniform

此限定符链接着色器程序和 WebGL 应用程序。与属性限定符不同,统一的值不会改变。统一是只读的;您可以将它们与任何基本数据类型一起使用,以声明变量。

示例 − uniform vec4 lightPosition;

3

variing

此限定符在顶点着色器和片段着色器之间形成链接,用于插值数据。它可与以下数据类型一起使用:float、vec2、vec3、vec4、mat2、mat3、mat4 或数组。

示例 − changing vec3 normal;

顶点着色器

顶点着色器是在每个顶点上调用的程序代码。它将几何图形(例如三角形)从一个位置转换(移动)到另一个位置。它处理每个顶点的数据(每个顶点的数据),例如顶点坐标、法线、颜色和纹理坐标。

在顶点着色器的 ES GL 代码中,程序员必须定义属性来处理数据。这些属性指向用 JavaScript 编写的顶点缓冲区对象。可以使用顶点着色器和顶点变换 − 执行以下任务

  • 顶点变换
  • 法线变换和规范化
  • 纹理坐标生成
  • 纹理坐标变换
  • 照明
  • 颜色材料应用

预定义变量

OpenGL ES SL 为顶点着色器 − 提供了以下预定义变量

Sr.No. 变量 &描述
1

highp vec4 gl_Position;

保存顶点的位置。

2

mediump float gl_PointSize;

保存转换后的点大小。此变量的单位是像素。

示例代码

查看以下顶点着色器的示例代码。它处理三角形的顶点。

attribute vec2 coordinates;

void main(void) {
   gl_Position = vec4(coordinates, 0.0, 1.0);
};

如果仔细观察上述代码,我们会发现我们声明了一个名为 coordinates 的属性变量。(此变量将使用方法 getAttribLocation() 与 Vertex Buffer Object 关联。属性 coordinates 将作为参数与着色器程序对象一起传递给此方法。)

在给定顶点着色器程序的第二步中,定义了 gl_position 变量。

gl_Position

gl_Position 是预定义变量,仅在顶点着色器程序中可用。它包含顶点位置。在上述代码中,coordinates 属性以向量的形式传递。由于顶点着色器是逐顶点操作,因此会为每个顶点计算 gl_position 值。

稍后,顶点处理结束后,原始组装、裁剪、剔除和其他对原始进行操作的固定功能操作将使用 gl_position 值。

我们可以为顶点着色器的所有可能操作编写顶点着色器程序,我们将在本教程中分别讨论这些操作。

片段着色器

一个 网格 由多个三角形组成,每个三角形的表面称为 片段。片段着色器是在每个片段的每个像素上运行的代码。它被编写来计算和填充单个像素上的颜色。使用片段着色器 − 可以执行以下任务

  • 对插值的操作
  • 纹理访问
  • 纹理应用
  • 颜色总和

预定义变量

OpenGL ES SL 为片段着色器 − 提供了以下预定义变量

Sr.No. 变量 &描述
1

mediump vec4 gl_FragCoord;

保存帧缓冲区内的片段位置。

2

bool gl_FrontFacing;

保存属于正面图元的片段。

3

mediump vec2 gl_PointCoord;

保存点内的片段位置(仅限点光栅化)。

4

mediump vec4 gl_FragColor;

保存着色器的输出片段颜色值

5

mediump vec4 gl_FragData[n]

保存颜色附件n的片段颜色。

示例代码

以下片段着色器示例代码展示了如何将颜色应用于三角形中的每个像素。

void main(void) {
   gl_FragColor = vec4(0, 0.8, 0, 1);
}

在上面的代码中,color 值存储在变量 gl.FragColor 中。片段着色器程序使用固定函数变量将输出传递到管道;FragColor 就是其中之一。此变量保存模型像素的颜色值。

存储和编译着色器程序

由于着色器是独立的程序,我们可以将它们编写为单独的脚本并在应用程序中使用。或者,您可以直接以 string 格式存储它们,如下所示。

var vertCode =
   'attribute vec2 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 0.0, 1.0);' +
   '}';

编译着色器

编译涉及以下三个步骤 −

  • 创建着色器对象
  • 将源代码附加到创建的着色器对象
  • 编译程序

创建顶点着色器

要创建一个空着色器,WebGL 提供了一种名为 createShader() 的方法。它创建并返回着色器对象。其语法如下 −

Object createShader (enum type)

从语法中可以看出,此方法接受预定义的枚举值作为参数。我们对此有两个选项 −

  • gl.VERTEX_SHADER 用于创建顶点着色器

  • gl.FRAGMENT_SHADER 用于创建片段着色器。

将源附加到着色器

您可以使用方法 shaderSource() 将源代码附加到创建的着色器对象。其语法如下 −

void shaderSource(Object shader, string source)

此方法接受两个参数 −

  • shader −您必须将创建的着色器对象作为一个参数传递。

  • Source − 您必须以字符串格式传递着色器程序代码。

编译程序

要编译程序,您必须使用方法 compileShader()。其语法如下 −

compileShader(Object shader)

此方法接受着色器程序对象作为参数。创建着色器程序对象后,将源代码附加到该对象并将该对象传递给此方法。

以下代码片段显示如何创建和编译顶点着色器以及片段着色器以创建三角形。

// 顶点着色器
var vertCode =
   'attribute vec3 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
   '}';

var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
 
// Fragment Shader
var fragCode =
   'void main(void) {' +
      ' gl_FragColor = vec4(0, 0.8, 0, 1);' +
   '}';

var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);

组合程序

创建并编译两个着色器程序后,您需要创建一个包含两个着色器(顶点和片段)的组合程序。需要遵循以下步骤 −

  • 创建程序对象
  • 连接两个着色器
  • 链接两个着色器
  • 使用程序

创建程序对象

使用方法 createProgram() 创建程序对象。它将返回一个空的程序对象。以下是它的语法 −

createProgram();

连接着色器

使用方法 attachShader() 将着色器连接到创建的程序对象。其语法如下 −

attachShader(Object program, Object shader);

此方法接受两个参数 −

  • Program − 将创建的空程序对象作为一个参数传递。

  • Shader − 传递已编译的着色器程序之一(顶点着色器、片段着色器)

注意 − 您需要使用此方法连接两个着色器。

链接着色器

使用方法 linkProgram() 链接着色器,方法是传递已将着色器附加到的程序对象。它的语法如下 −

linkProgram(shaderProgram);

使用程序

WebGL 提供了一种名为 useProgram() 的方法。您需要将链接的程序传递给它。它的语法如下 −

useProgram(shaderProgram);

以下代码片段显示了如何创建、链接和使用组合着色器程序。

var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);