JavaScript WebGL 绘制一个面

摘要:
目录导入器绘制三角形的执行过程以高清晰度处理。在得出矩形索引缓冲区对象引用引入器JavaScriptWebGL的基本疑虑后,进行了一些优化。WebGL中的几何图形最终由三角形组成。我习惯于以图形中心为原点描述顶点的顺序,并使用前面的最后两个顶点形成三角形,绘制一个具有共享边的三角形。并使用第一个顶点和最后一个顶点形成三角形。

目录

引子

JavaScript WebGL 基础疑惑点之后进行了一些优化,然后尝试绘制常见二维的面。

WebGL 中几何体最终都是由三角形构成,由三角形切入比较合适。

绘制三角形

这是示例,基于绘制一条直线主要的变化有:

  • 顶点
  • 绘制图元

顶点

三角形有三个顶点,在基础疑惑点中知道坐标系是右手坐标系,个人习惯描述顶点的顺序以图形中心为原点,从第一象限到第四象限。

  let vertices = [
    0.5, 0.5, 0.0, // 第一象限
    -0.5, 0.5, 0.0, // 第二象限
    -0.5, -0.5, 0.0, // 第三象限
  ]; // 三角形

绘制图元

这次绘制的是一个面,drawArrays 中绘制模式变为 gl.TRIANGLES 。顺便看看图元的几种模式。

  • gl.POINTS : 绘制一系列点。
  • gl.LINES :绘制一系列单独线段,每两个点作为端点,线段之间不连接。例如有顶点 A、B、C、D、E、F,就会得到了三条线段。

94-lines

  • gl.LINE_STRIP : 绘制一系列线段,上一点连接下一点。

94-line-strip

  • gl.LINE_LOOP : 绘制一系列线段,上一点连接下一点,并且最后一点与第一个点相连。

94-line-loop

  • gl.TRIANGLES : 绘制一系列三角形,每三个点作为顶点。例如有 6 个顶点 A、B、C、D、E、F,就会绘制 2 个三角形: ABC 和 DEF。

94-triangles

  • gl.TRIANGLE_STRIP : 用来绘制有共享边的三角形。从第二个三角形开始,每次读取一个顶点,并利用前面的末尾两个顶点构成一个三角形,以此类推。例如有 6 个顶点 A、B、C、D、E、F,就会绘制 4 个三角形: ABC 和 BCD 和 CDE 和 DEF。

94-triangle-strip

  • gl.TRIANGLE_FAN : 绘制有共享边的三角形。从第二个三角形开始,每次读取一个顶点,并利用首个顶点和之前最后一个顶点来构成一个三角形,以此类推。例如有 6 个顶点 A、B、C、D、E、F,就会绘制 4 个三角形: ABC 和 ACD 和 ADE 和 AEF。

94-triangle-fan

执行过程

这里有一个绘制三角形执行过程可视化,结合看看有助于加深理解。

高清处理

上面的示例,在高清屏幕中会出现明显的模糊和锯齿,但跟处理 2d 上下文的模糊又有些不一样。最主要的一个区别是 WebGL 中需要用 viewport 方法指定从标准设备到窗口坐标的映射变换。详细可以见这篇文章里面的解释。

这是高清示例

  function WebGLHD(w = 300, h = 150) {
    const ratio = window.devicePixelRatio || 1;
    const canvas = document.createElement("canvas");
    const context = canvas.getContext("webgl");
    // 高清屏幕模糊问题处理
    canvas.width = w * ratio; // 实际渲染像素
    canvas.height = h * ratio; // 实际渲染像素
    canvas.style.width = `${w}px`; // 控制显示大小
    canvas.style.height = `${h}px`; // 控制显示大小
    context.viewport(0, 0, context.canvas.width, context.canvas.height);
  }

绘制矩形

前面有说 WebGL 中几何体最终都是由三角形构成,在绘制多边形的时候需要分解为多个三角形。

这是示例,一个矩形可以分为两个三角形:

  let vertices = [
    0.5, 0.5, 0.0,
    -0.5, 0.5, 0.0,
    -0.5, -0.5, 0.0, // 第一个三角形
    -0.5, -0.5, 0.0,
    0.5, -0.5, 0.0,
    0.5, 0.5, 0.0, // 第二个三角形
  ]; // 矩形

可以发现有一条边是公共,这个时候可以索引缓冲区对象减少冗余的数据。

索引缓冲对象

索引缓冲对象全称是 Index Buffer Object(IBO),通过索引的方式复用已有的数据。

基于上面正方形的示例,主要的变化有以下几方面:

  • 数据
  • 缓冲
  • 绘制

数据

顶点位置数据只需要 4 个就足够了,公共数据使用索引代替。

  const vertices = [
    0.5, 0.5, 0.0, // 第 1 个顶点
    -0.5, 0.5, 0.0, // 第 2 个顶点
    -0.5, -0.5, 0.0, // 第 3 个顶点
    0.5, -0.5, 0.0, // 第 4 个顶点
  ]; // 矩形

索引数据跟上面提示到的图元绘制模式有关。

绘制模式为 gl.TRIANGLES 时,两个三角形是独立的,索引数据如下:

const indexData = [
  0, 1, 2, // 对应顶点位置数据中 1、2、3 顶点的索引
  0, 2, 3, // 对应顶点位置数据中 1、3、4 顶点的索引
]

绘制模式为 gl.TRIANGLE_STRIP 时,利用前一个三角形末尾的两个顶点构建三角形:

const indexData = [
  1, 0, 2, 3 // 绘制时,先取索引 1、0、2 的位置数据绘制第一个三角形,然后再取索引 0、2、3 的位置数据 绘制第二个三角形
]

绘制模式为 gl.TRIANGLE_FAN 时,利用第一个顶点,和前一个三角形末尾的一个顶点,加上新读取的顶点构建三角形:

const indexData = [
  0, 1, 2, 3 // 绘制时,先取索引 0、1、2 的位置数据绘制第一个三角形,然后再取索引 0、2、3 的位置数据 绘制第二个三角形
]

缓冲

索引的数据需要缓冲到对应的变量才能使用。

/**
 * 缓冲索引数据
 * @param {*} gl WebGL 上下文
 * @param {*} data 索引数据
 */
function setIndexBuffers(gl, data) {
  // 创建空白的缓冲对象
  const buffer = gl.createBuffer();
  // 绑定目标
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
  // WebGL 不支持直接使用 JavaScript 原始数组类型,需要转换
  const dataFormat = new Uint16Array(data);
  // 初始化数据存储
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, dataFormat, gl.STATIC_DRAW);
}

绘制

使用了索引缓冲对象,需要用 drawElements 方法来替代 drawArrays。该方法多了一个 type 参数,指的是索引缓冲数据的类型,有下面的值可取:

  • gl.UNSIGNED_BYTE
  • gl.UNSIGNED_SHORT

前面缓冲索引数据类型转换为了 Uint16Array ,这里应该使用 gl.UNSIGNED_SHORT

三种方式示例如下:

Back to top

参考资料

免责声明:文章转载自《JavaScript WebGL 绘制一个面》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Impala的安装和使用RFC 2544 性能测试下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

app开发之deviceone

deviceone,跨平台、低成本、纯原生的app开发服务,具体介绍见:http://www.deviceone.net/ do不同于dcloud、rn等开发套件,do只是一座桥梁,可以选择使用javascript or lua进行纯原生开发,开发后的app同时适配android、ios、winphone、桌面等平台,真正实现了跨平台原生开发的特点,开发出...

前端动态表单的处理方法

背景: 类似于如下的表单的形式,如果我们提前知道了表单的key,那么我们就可以通过正常的处理表单形式,完成相关数据的获取。 但是,如果我们事先不知道表单的属性key值及对应的输入框还是select框, 那我们就得选择其他方式处理。  步骤一:首先,我们约定,后台返回的格式如下: 其中,code字段的具体值为表单的key,type为到底是输入框还是选择框,...

MySQL三种备份

一)备份分类 1 2 3 4 5 6 7 8 9 10 11 12 冷备:cold backup数据必须下线后备份 温备:warm backup全局施加共享锁,只能读,不能写 热备:hot backup数据不离线,读写都能正常进行 备份的数据集 完全备份:full backup 部分备份:partial backup 备份时的接口(是直接备份数据文...

Hive的基本操作

一、创建数据库   hive>create database mydb ; //hql和mysql语法极其相似   hive>show databases;//查看所有数据库 二、创建表   格式:     create [external] table <表名>(列的定义,....)  [row format delimited...

jdbc 连接数据库

1.什么是jdbc? 答:jdbc是java data base connection 的简写,即java与数据库的连接,是java与数据库之间进行数据交互的工具,书上解释为java访问数据库的API。jdbc是一个轻量级的连接封装,适用于多种数据库,如:oracle、sql server,mysql等等。hibernate则是对jdbc的再封装。 2、j...

ES入门 (5) 语法(3)DML(2)映射操作 创建映射/查看映射/索引映射关联/

有了索引库,等于有了数据库中的 database。 接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。 1 创建映射 在 Postman 中,向 ES...