WebGL - 着色器

  • 简述

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

    下表列出了 OpenGL ES SL 提供的基本数据类型。
    序号 类型和说明
    1
    void
    表示一个空值。
    2
    bool
    接受真或假。
    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 中有三个主要限定符 -
    序号 限定符和说明
    1
    attribute
    这个限定符充当顶点着色器和 OpenGL ES 之间的链接,用于每个顶点数据。此属性的值会随着顶点着色器的每次执行而改变。
    2
    uniform
    此限定符链接着色器程序和 WebGL 应用程序。与属性限定符不同,制服的值不会改变。制服是只读的;您可以将它们与任何基本数据类型一起使用,以声明变量。
    Example− 制服vec4灯光位置;
    3
    varying
    该限定符为插值数据形成了顶点着色器和片段着色器之间的链接。它可以与以下数据类型一起使用 - float、vec2、vec3、vec4、mat2、mat3、mat4 或数组。
    Example− 变化的vec3普通的;
  • 顶点着色器

    顶点着色器是一个程序代码,它在每个顶点上被调用。它将几何体(例如:三角形)从一个地方转换(移动)到另一个地方。它处理每个顶点的数据(per-vertex data),例如顶点坐标、法线、颜色和纹理坐标。
    在顶点着色器的 ES GL 代码中,程序员必须定义属性来处理数据。这些属性指向用 JavaScript 编写的顶点缓冲区对象。可以使用顶点着色器和顶点变换来执行以下任务 -
    • 顶点变换
    • 法线变换和归一化
    • 纹理坐标生成
    • 纹理坐标变换
    • 灯光
    • 色料应用

    预定义变量

    OpenGL ES SL 为顶点着色器提供以下预定义变量 -
    序号 变量和描述
    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(). 属性coordinates与着色器程序对象一起作为参数传递给此方法。)
    在给定的顶点着色器程序的第二步中,gl_position变量被定义。

    gl_位置

    gl_Position 是预定义变量,仅在顶点着色器程序中可用。它包含顶点位置。在上面的代码中,coordinates属性以向量的形式传递。由于顶点着色器是针对每个顶点的操作,因此会为每个顶点计算 gl_position 值。
    稍后,gl_position 值被图元组装、裁剪、剔除和其他固定功能操作使用,这些操作在顶点处理结束后对图元进行操作。
    我们可以为顶点着色器的所有可能操作编写顶点着色器程序,我们将在本教程中单独讨论。
  • 片段着色器

    一个mesh由多个三角形组成,每个三角形的表面称为fragment. 片段着色器是在每个片段的每个像素上运行的代码。这是为了计算和填充单个像素的颜色而编写的。可以使用片段着色器执行以下任务 -
    • 对插值的操作
    • 纹理访问
    • 纹理应用
    • 多雾路段
    • 色和

    预定义变量

    OpenGL ES SL 为片段着色器提供以下预定义变量 -
    序号 变量和描述
    1
    中等 vec4gl_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)
    
    此方法接受着色器程序对象作为参数。创建着色器程序对象后,将源代码附加到它,并将该对象传递给此方法。
    以下代码片段显示了如何创建和编译顶点着色器以及片段着色器以创建三角形。
    
    // Vertex 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);