当前位置: 首页 > news >正文

webgl绘制图形API——drawArrays、drawElements

文章目录

  • 前言
  • gl.drawArrays()——按顶点绘制
    • 可绘制基本类型
    • 绘制矩形和圆形
  • gl.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()按照索引绘制

  • 使用规范
  • 绘制矩形

相关文章:

  • 不平衡数据集的建模的技巧和策略
  • 每天一道大厂SQL题【Day01】
  • 【JAVA核心知识】46:什么是零拷贝Zero-copy
  • Spring和Spring Boot的区别
  • 初始网络编程
  • 数据分析:SQL和Python
  • 我建议大学生看一下阿凡达2,对离校后很有帮助
  • 单片机开发---ESP32S3移植lvgl+触摸屏
  • 【网络安全】记一次红队渗透实战项目
  • 网络安全协议
  • 数据结构(括号匹配与表达式计算)
  • 【Linux】冯诺依曼体系结构
  • element 日期组件实现只能选择小时或者只能选择小时、分钟
  • 【寒假小练】day2
  • 指针(基础)
  • [deviceone开发]-do_Webview的基本示例
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • in typeof instanceof ===这些运算符有什么作用
  • Linux gpio口使用方法
  • Spring Boot快速入门(一):Hello Spring Boot
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 服务器之间,相同帐号,实现免密钥登录
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 基于遗传算法的优化问题求解
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 手写一个CommonJS打包工具(一)
  • 思考 CSS 架构
  • 小程序测试方案初探
  • 一个项目push到多个远程Git仓库
  • 阿里云ACE认证学习知识点梳理
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (1)SpringCloud 整合Python
  • (1)STL算法之遍历容器
  • (31)对象的克隆
  • (C语言)共用体union的用法举例
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (八)Spring源码解析:Spring MVC
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (原)Matlab的svmtrain和svmclassify
  • (轉貼) UML中文FAQ (OO) (UML)
  • .chm格式文件如何阅读
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET Core中的去虚
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .net 验证控件和javaScript的冲突问题
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .NET6 命令行启动及发布单个Exe文件
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)