WebGL+Three.js—第四章 WebGL原理学习:OpenGL ES 语言

448 阅读4分钟

4.1 OpenGL ES 语言基础

4.1.1 语言基础

    1、大小写敏感

        着色器语言对于大小写是敏感的,例如aPosition与aposition就是两个变量。

    2、强制分号

        它每一句语法的最后必须要使用分号结尾,如果漏写会导致程序报错无法执行。

4.1.2 程序入口

    着色器语言通过main函数作为程序入口,且没有任何返回值。

4.1.3 注释

    在JavaScript中,单行注释使用//,多行注释使用/**/。OpenGL跟JavaScript是一致的。

4.1.4 强类型语言

    变量的使用和赋值必须是相同类型,需要时刻注意变量的类型。

image.png

// 顶点着色器
const VERTEX_SHADER_SOURCE = `
  void main() {
    float f = 10.0;
    int i = 10;
    bool b = true;
  }
`;

4.1.5 变量声明

    1、数字字母下划线

    2、不能是关键字或保留字

    3、不能以数字开头

    4、不能以gl_、webgl_、_webgl_作为开头

4.1.6 类型和类型转换

    1、int():转为整型

    2、float():转为浮点型

    3、bool():转为布尔型

4.1.7 运算符

image.png

4.2 矢量和矩阵

4.2.1 矢量

    1、矢量类型

        (1)vec2、vec3、vec4具有2、3、4个浮点数元素的矢量

        (2)ivec2、ivec3、ivec4具有2、3、4个整型元素的矢量

        (3)bvec2、bvec3、bvec4具有2、3、4个布尔值元素的矢量

    2、赋值

        需要通过构造函数来进行赋值

vec4 position = vec4(0.0, 0.0, 0.0, 1.0);    // vec4 就是矢量的构造函数

    3、访问矢量里的分量

image.png

        (1)获取单个分量

vec4 position = vec4(0.1, 0.2, 0.3, 1.0);
position.x  // 0.1
position.y  // 0.2
position.z  // 0.3

        (2)获取多个分量

            可以通过混合的方式获取多个值,获取到的是一个新的矢量内容。

vec4 position = vec4(0.1, 0.2, 0.3, 1.0);
position.xy   // vec2(0.1, 0.2)
position.yx   // vec2(0.2, 0.1)
position.zyx  // vec3(0.3, 0.2, 0.1)

4.2.2 矩阵

    1、矩阵类型

        mat2、mat3、mat4对应22、33、4*4的浮点数元素矩阵

    2、赋值

        矩阵入参,注意:矩阵参数是列主序的

mat4 m = mat4(
  1.0, 5.0, 9.0,  13.0,
  2.0, 6.0, 10.0, 14.0,
  3.0, 7.0, 11.0, 15.0,
  4.0, 8.0, 12.0, 16.0
)

4.3 纹理取样器

    1、取样器有两种:sampler2D和samplerCube

    2、只能声明为uniform变量

// 声明二维纹理
uniform sampler2D uSampler;
// 声明立方体纹理
uniform samplerCube uSamplerCube;

    3、二维纹理使用

// 创建纹理对象
const texture = gl.createTexture();

// 翻转图片Y轴
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);

// 开启一个纹理单元
gl.activeTexture(gl.TEXTURE0);

// 绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D, texture);

// 处理放大缩小的逻辑
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

// 横向 纵向 平铺的方式
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

// 配置纹理图像
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);

gl.uniform1i(uSampler, 0);

    4、立方体纹理使用

        立方体纹理的使用流程跟二维很类似,区别是gl.TEXTURE_2D变成了gl.TEXTURE_CUBE_MAP,二维只需要处理1个面,立方体需要处理6个面。

// 创建纹理对象
const cubeMap = gl.createTexture();

// 翻转图片Y轴
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

// 开启一个纹理单元
gl.activeTexture(gl.TEXTURE1);

// 绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D, cubeMap);

// 处理放大缩小的逻辑
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

// 横向 纵向 平铺的方式
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

// 配置纹理图像
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[0]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[1]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[2]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[3]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[4]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[5]);

gl.uniform1i(uSampler, 0);

4.4 分支和循环

    1、分支逻辑

        if() {} 和 if() {} else {}

    2、循环语句

        for() {}

        while() {}

        do {} while()

    3、跳出循环

        continue

        break

        discard:只能在片元着色器中使用,因为着色器是逐个片元来处理的,discard表示放弃当前片元直接处理下一个片元

4.5 函数

    1、函数返回值

        如果函数需要返回值,那么在函数名前面定义返回类型;如果不需要返回,则在函数名前添加void关键字。

// 主函数不需要返回值
void main() {}

// 需要返回float类型的值
float getFloat() {
  return 10.0;
}

    2、函数传参

        函数接收参数也要定义好类型。

// 函数传参接参
float getFloat(float x, int y) {
  return 10.0;
}
getFloat(10.0, 1);

4.6 内置函数介绍

    GLSL ES里提供了较多的内置函数,可以直接使用。

image.png

image.png

image.png

image.png

image.png

4.7 存储限定词

4.7.1 const

    声明一个常量,定义之后不能被改变。

4.7.2 attribute

    只能出现在顶点着色器中,只能声明为全局变量,表示顶点信息。

4.7.3 uniform

    1、可同时出现在顶点着色器和片元着色器中

    2、只读类型,强调一致性

    3、用来存储的是影响所有顶点的数据,如变换矩阵

4.7.4 varying

    从顶点着色器向片元着色器传递数据,需要同时在顶点着色器和片元着色器声明相同的类型和变量名。

4.7.5 精度限定

    1、提升运行效率,削减内存开支

    2、可以单独针对某个变量声明精度

mediump float f;

    3、劣势:会出现精度歧义,也不利于后期维护

        例如在使用f的时候,需要将f的精度转为高精度,这样就会出现精度的歧义,也有可能忘记转换精度,出现一些意想不到的效果,而且也不利于维护。

    4、通过precision关键字来修改着色器的默认精度

precision mediump float;

image.png

4.7.6 精度使用场景

    片元着色器中的float类型没有默认精度,所以如果需要在片元着色器中使用浮点型数据的时候,需要修改默认精度。