webgl绘制图形API——drawArrays、drawElements


前言

gl.drawArrays()作为webgl中常用的函数图形绘制方法,可以在浏览器按照指定的模式绘制图形,与之相对的gl.drawElements()函数也是常用的绘制函数,本文将介绍二者的区别与使用。


gl.drawArrays()——按顶点绘制

可绘制基本类型

gl.drawArrays(mode, first, count)的使用在webgl图形绘制基础中有过详细的介绍,它的mode参数其实十分强大,可以按照不同的规则绘制不同的图形,可直接绘制的图形有七种,这七种图形是绘制其它各种复杂图形的基础。

参数名图形描述
gl.POINTS一系列点,依次绘制
gl.LINES线段每两个一组绘制线段,若点的数目为奇数,最后一个点会被舍弃
gl.LINES_STRIP线条所有的点依次相连
gl.LINE_LOOP回路再线条的基础上,将首尾点相连
gl.TRIANGLES三角形每三个一组绘制三角形,若点的数目无法被三整除,剩余的点会被舍弃
gl.TRIANGLES_STRIP三角带一系列条带状的三角形,每个三角形都存在一条边共享
gl.TRIANGLES_FAN三角扇类似于扇形的图形

在这里插入图片描述

绘制矩形和圆形

绘制矩形可以通过两个三角形完成,要注意顶点数据必须按照三角形逆时针方向给出。

const vertices = new Float32Array([
      // 第一个三角形
			-0.3, 0.3, 
			-0.3, -0.3,
			0.3, -0.3,
      // 第二个三角形
			0.3, -0.3, 
			0.3, 0.3,
			-0.3, 0.3,
		])

在这里插入图片描述

绘制圆形的原理相似,当相同大小的三角形具备同一个顶点并组成一个闭环时,就可以近似视为圆。三角形数越多,圆形越近似。

当用十个点绘制时:

	const _circle = [];
    for (let i = 0; i <= 10; i++) {
      const angle = i * Math.PI * 2 / 10; // 把2Π分成10份
      _circle.push(0 + 0.3 * Math.sin(angle), 0 + 0.3 * Math.cos(angle));
    }
    const circle = new Float32Array(_circle);

在这里插入图片描述

当用一百个点绘制时:

	const _circle = [];
    for (let i = 0; i <= 100; i++) {
      const angle = i * Math.PI * 2 / 100; // 把2Π分成100份
      _circle.push(0 + 0.3 * Math.sin(angle), 0 + 0.3 * Math.cos(angle));
    }
    const circle = new Float32Array(_circle);

在这里插入图片描述
完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>webgl</title>
  <script src="./lib.js"></script>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    canvas {
      margin: 50px 30px;
      width: 500px;
      height: 500px;
    }
  </style>
</head>

<body>
  <canvas id="canvas"></canvas>
  <script>
    /** @type {HTMLCanvasElement} */
    //------------------------------------------------------创建画布

    // 获取webgl绘图上下文
    const gl = canvas.getContext('webgl');
    if (!gl) {
      throw new Error('WebGL not supported');
    }

    gl.clear(gl.COLOR_BUFFER_BIT)
    const vertex = `
			attribute vec4 aPosition;
			void main() {
				gl_Position = aPosition;
				gl_PointSize = 10.0;
			}
		`
    const fragment = `
			precision highp float;
			void main(){
				gl_FragColor =vec4(1.0,0.0,1.0,1.0);
			}
		`
    // 创建program
    const program = initShader(gl, vertex, fragment)
    // 获取attribute变量的数据存储位置
    const aPosition = gl.getAttribLocation(program, 'aPosition');
    // 创建缓冲区对象
    const buffer = gl.createBuffer();
    // 绑定缓冲区对象
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    // 传入的数据
    const vertices = new Float32Array([
      // 第一个三角形
      -0.3, 0.3,
      -0.3, -0.3,
      0.3, -0.3,
      // 第二个三角形
      0.3, -0.3,
      0.3, 0.3,
      -0.3, 0.3,
    ])

    const _circle = [];
    for (let i = 0; i <= 100; i++) {
      const angle = i * Math.PI * 2 / 100; // 把2Π分成100份
      _circle.push(0 + 0.3 * Math.sin(angle), 0 + 0.3 * Math.cos(angle));
    }
    const circle = new Float32Array(_circle);
    // 开辟空间并写入数据
    gl.bufferData(gl.ARRAY_BUFFER, circle, gl.STATIC_DRAW)
    // 缓冲区对象分配给attribute变量
    gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0)
    // 开启attribue变量
    gl.enableVertexAttribArray(aPosition)
    // 开始绘制
    gl.drawArrays(gl.TRIANGLE_FAN, 0, 1000)
  </script>
</body>

</html>

gl.drawElements()——按索引绘制

使用规范

在绘制矩形时,实际上只需要四个顶点,可是使用gl.drawArrays却存储了六个顶点,每个顶点大小为 4 * 6 = 24 个字节,绘制矩形就浪费了 48 字节的空间,为了避免这种浪费,WebGL 提供了按照顶点索引进行绘制的方法gl.drawElements节省存储空间。

drawElements(mode, count, type, offset): 从数组数据中按照指定模式渲染图元。

  • mode:绘制模式,与gl.drawArrays() 相同
  • count: 绑定元素数组缓冲区的元素数
  • type:元素数组缓冲区中值的类型,枚举如下:
    — gl.UNSIGNED_BYTE
    — gl.UNSIGNED_SHORT
  • offset:元素数组缓冲区中的字节偏移量

绘制矩形

效果
在这里插入图片描述

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>webgl</title>
  <script src="./lib.js"></script>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    canvas {
      margin: 50px 30px;
      width: 500px;
      height: 500px;
    }
  </style>
</head>

<body>
  <canvas id="canvas"></canvas>
  <script>
    /** @type {HTMLCanvasElement} */
    //------------------------------------------------------创建画布

    // 获取webgl绘图上下文
    const gl = canvas.getContext('webgl');
    if (!gl) {
      throw new Error('WebGL not supported');
    }

    gl.clear(gl.COLOR_BUFFER_BIT)
    const vertex = `
			attribute vec4 aPosition;
			void main() {
				gl_Position = aPosition;
				gl_PointSize = 10.0;
			}
		`
    const fragment = `
			precision highp float;
			void main(){
				gl_FragColor =vec4(1.0,0.0,1.0,1.0);
			}
		`
    // 创建program
    const program = initShader(gl, vertex, fragment)
    // 获取attribute变量的数据存储位置
    const aPosition = gl.getAttribLocation(program, 'aPosition');
    // 创建缓冲区对象
    const buffer = gl.createBuffer();
    // 绑定缓冲区对象
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    // 传入的数据
    const vertices = new Float32Array([
      // 第一个三角形
      -0.3, 0.3,
      -0.3, -0.3,
      // 0.3, -0.3,
      // 第二个三角形
      0.3, -0.3,
      0.3, 0.3,
      // -0.3, 0.3,
    ])
    // 索引缓冲区
    const index = new Uint16Array([0, 1, 2, 0, 2, 3])

    // 开辟空间并写入数据
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
    // 缓冲区对象分配给attribute变量
    gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0)
    // 开启attribue变量
    gl.enableVertexAttribArray(aPosition)

    const indexBuffer = gl.createBuffer();
    //绑定索引缓冲区
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    //向索引缓冲区传递索引数据
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);

    // 开始绘制
    gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);

  </script>
</body>

</html>

总结

gl.drawArrays()

  • 可绘制基本类型
  • gl.drawArrays()绘制矩形和圆形

gl.drawElements()按照索引绘制

  • 使用规范
  • 绘制矩形
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值