webgl用法和简介

WebGL 的基本图元包括:点、线段、三角形。

三角形图元分类

基本三角形(TRIANGLES)

基本三角形是一个个独立的三角形。
假如:提供给着色器 6 个顶点,WebGL 会绘制 2 个三角形,前三个顶点绘制一个,后三个顶点绘制另一个,互不相干。
例如:[v1, v2, v3, v4, v5, v6] 采用基本三角形图元进行绘制,绘制完如下图所示
在这里插入图片描述
[v1, v2, v3] 为一个三角形、[v4, v5, v6] 为另一个三角形。
绘制三角形的数量 = 顶点数 / 3

三角带(TRIANGLE_STRIP)

例如:[v1, v2, v3, v4, v5, v6] 采用三角带的方式进行绘制,绘制完如下图所示

在这里插入图片描述
则会绘制 [v1, v2, v3], [v3, v2, v4], [v3, v4, v5], [v5, v4, v6] 共计 4 个三角形
绘制三角形数量 = 顶点数 - 2

三角扇(TRIANGLE_FAN)

例如:[v1, v2, v3, v4, v5, v6] 采用三角扇的方式进行绘制,绘制完如下图所示

在这里插入图片描述
则会绘制 [v1, v2, v3], [v1, v3, v4], [v3, v4, v5], [v1, v5, v6] 共计 4 个三角形
绘制三角形数量 = 顶点数 - 2

绘制基本三角形

目标:在 canvas 上点击三个位置作为三角形的三个顶点,然后绘制一个红色的三角形。
注意:不涉及到深度信息 z 值,每个顶点之传入 [x, y] 坐标即可。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绘制三角形</title>
  <link rel="stylesheet" href="styles/app.css">
</head>
<body>
  <canvas id="canvas"></canvas>

  <script>
    const random = Math.random;

    /**
     * 获取随机颜色
     * @returns { Object } 颜色对象
     */
    function randomColor () {
      return {
        r: random() * 255,
        g: random() * 255,
        b: random() * 255,
        a: random() * 1
      }
    }

    const canvas = document.querySelector('#canvas');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    const gl = canvas.getContext('webgl');
    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // 顶点着色器
    const vertexShaderSource = `
      // 设置浮点数据类型为中级精度
      precision mediump float;

      // 接收顶点坐标 (x,y)
      attribute vec2 a_Position;

      void main () {
        gl_Position = vec4(a_Position, 0.0, 1.0);
      }
    `;
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertexShaderSource);
    gl.compileShader(vertexShader);
    
    // 片元着色器
    const fragmentShaderSource = `
      // 设置浮点数据类型为中级精度
      precision mediump float;

      // 接收 JavaScript 传过来的颜色值(rgba)
      uniform vec4 u_Color;

      void main(){
        vec4 color = u_Color / vec4(255, 255, 255, 1);
        gl_FragColor = color;
      }
    `;
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader,fragmentShaderSource);
    gl.compileShader(fragmentShader);

    // 着色器程序
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    gl.useProgram(program);

    // 获取着色器程序中变量的指针位置
    const a_Position = gl.getAttribLocation(program, 'a_Position')
    const u_Color = gl.getUniformLocation(program, 'u_Color');

    // 定义三角形的三个顶点
    const positions = [
      0, 0.5,     // 上顶点
      -0.5, -0.5, // 左顶点
      0.5, -0.5   // 右顶点
    ];

    // 创建缓冲区
    const buffer = gl.createBuffer();

    // 绑定缓冲区并指定缓冲区的类型
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

    // 往缓冲区中写入数据
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

    // 将属性绑定到缓冲区
    gl.enableVertexAttribArray(a_Position);

    // 如何读取缓冲区数据
    // 指定要修改的顶点属性的索引(允许哪个属性读取当前缓冲区的数据) - a_Position
    // 指定每个顶点属性的组成数量(一次读取几个数据) - 2
    // 指定数组中每个元素的数据类型 - gl.FLOAT(32 位 IEEE 标准的浮点数,占用 4 个字节)
    // 当转换为浮点数时是否应该将整数数值归一化到特定的范围 - false(对于类型 gl.FLOAT 和 gl.HALF_FLOAT,此参数无效)
    // 步长(即:每个顶点所包含数据的字节数)0 表示一个属性的数据是连续存放的
    // 偏移量(指定顶点属性数组中第一部分的字节偏移量)(在每个步长的数据里,目标属性需要偏移多少字节开始读取;必须是类型的字节长度的倍数)0 * 4 = 0
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

    // 随机颜色
    const { r, g, b, a } = randomColor();
    // 向片元着色器传递颜色信息
    gl.uniform4f(u_Color, r, g, b, a);

    // 绘制三角形
    // 指定绘制图元的方式 - gl.TRIANGLES(三角形)
    // 指定从哪个点开始绘制 - 0
    // 指定绘制需要使用到多少个点 - 3
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
  </script>
</body>
</html>

如何将三角形的三个顶点数据传递给顶点着色器

因为要传递多个顶点数据,通过缓冲区可以向顶点着色器传递多个顶点数据	
// 定义三角形的三个顶点
const positions = [
  0, 0.5,     // 上顶点
  -0.5, -0.5, // 左顶点
  0.5, -0.5   // 右顶点
];

// 找到 a_Position 变量的指针位置
const a_Position = gl.getAttribLocation(program, 'a_Position')

// 创建缓冲区
const buffer = gl.createBuffer();

// 绑定缓冲区并指定缓冲区的类型
// 绑定之后,对缓冲区绑定点的的任何操作都会基于该缓冲区(即 buffer) 进行
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

// 往缓冲区(即上一步通过 bindBuffer 绑定的缓冲区)中写入数据

步骤分析
创建一个数组,用于保存三角形的顶点坐标信息
创建一个缓冲区
绑定缓冲区,并指定缓冲区类型
往缓冲区写入数据
使用 Float32Array 将 JavaScript 中的弱类型数组转化为强类型数组,然后复制到缓冲区中
gl.STATIC_DRAW 告诉 WebGL 不会频繁改变缓冲区中的数据,WebGL 会根据这个参数做一些优化处理
如何把顶点组成的模型渲染到屏幕上
// 将属性绑定到缓冲区
gl.enableVertexAttribArray(a_Position);

// 允许哪个属性读取当前缓冲区的数据,读取长度,读取类型,如何读取
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

// 绘制三角形

步骤分析
将属性绑定到缓冲区
告诉 WebGL 允许哪个属性,如何从缓冲区中获取数据的方式
允许哪个属性读取当前缓冲区的数据
一次读取几个数据
指定数组中每个元素的数据类型
当转换为浮点数时是否应该将整数数值归一化到特定的范围 [-1, 1] 之间
步长,即每个顶点所包含数据的字节数,默认值是:0
不能大于 255
如果为 0,则表示下一个顶点的属性紧跟当前顶点之后(表示一个属性的数据是连续存放的)
本例中,一个顶点包含两个分量:x 坐标和 y 坐标,每个分量都是 Float32Array 类型,占 4 个字节,所以 步长 = 2 * 4 就是 8 个字节;但本例中,缓冲区只为一个属性 a_Position 服务,并且缓冲区的数据是连续存放的,因此,可以使用默认值 0 来表示
如果缓冲区为多个属性所共用,步长就不能设置为 0 了,需要进行计算
偏移量(指定顶点属性数组中第一部分的字节偏移量)必须是类型的字节长度的倍数
可理解为:在每个步长的数据里,目标属性需要偏移多少字节开始读取
本例中,缓冲区只为 a_Position 一个属性服务,所以 偏移量 = 0 * 4 为 0
图解步长
假如顶点数组为 [10, 20, 30, 30, 40, 50, 60, 70],每相邻数字代表一个顶点的 x 坐标和 y 坐标。
由于使用的是 Float32Array 浮点数组,每个数字占 4 个字节。

在这里插入图片描述
在这里插入图片描述

绘制三角形
// 指定绘制图元的方式 - gl.TRIANGLES(三角形)
// 指定从哪个点开始绘制 - 0
// 指定绘制需要使用到多少个点 - 3
gl.drawArrays(gl.TRIANGLES, 0, 3);

图解数据传输过程在这里插入图片描述

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值