关于webgl:WebGL浅入浅出

5次阅读

共计 5933 个字符,预计需要花费 15 分钟才能阅读完成。

豆皮粉儿们,又见面了,明天这一期,由“Kakashi”,给咱们带来 webgl 的学习,webgl 一种很强的数据可视化的图形库,同时数据可视化也是前端倒退的一个重要方向之一,值得入坑和学习。

本文作者:Kakashi

前言:本篇文章预计浏览耗时【15min】将较为全面根底的带你学习 如何应用 WebGL(并重)&& 相干原理(简略)。通过本次学习 你将能够从 0 到 1 搭建本人的 webgl 繁难渲染库

一、背景:

1.1 为什么要用 WebGL?

先热身一下吧,看个问题:
如果你有一堆作业没有做完,能够抉择帮手替你实现,你会抉择?

A. 1 个老传授
B. 9 个小学生

  • 选 A 的同学,你真的忍心让老传授帮忙写语文填空?
  • 选 B 的同学,你真的释怀让小学生帮你解线性代数?
    所以咱们要看看“作业”内容到底是什么,有多少作业量。
  • 如果题目是 1+2,9 个小学生 = 人海战术收费劳动力,没有技术含量,纯正体力活,效率会很高。
  • 如果题目是线性代数,老传授 >> 99 个小学生。
    回到咱们的主题,相似的,因为设计指标的不同,CPU 和 GPU 也是大不相同的。它们别离针对了两种不同的利用场景:
  • CPU 须要很强的通用性来解决各种不同的数据类型,同时又要逻辑判断又会引入大量的分支跳转和中断的解决。这些都使得 CPU 的内部结构异样简单。
  • GPU 面对的则是类型高度对立的、互相无依赖的大规模数据和不须要被打断的污浊的计算环境。

(图片来自 nVidia CUDA 文档。其中绿色的是计算单元,橙红色的是存储单元,橙黄色的是管制单元。)
GPU 在概念上实用于高度并行计算,因为 GPU 能够通过计算暗藏内存拜访提早,而不是通过大数据缓存和流控制来防止内存拜访提早。
简而言之,CPU 基于低延时的设计,GPU 是基于大的吞吐量设计

1.2 什么是 WebGL?

WebGL 是一种 3D 绘图规范,这种绘图技术标准容许把 JavaScript 和 OpenGL ES 2.0 联合在一起,通过减少 OpenGL ES 2.0 的一个 JavaScript 绑定,WebGL 能够为 HTML5 Canvas 提供硬件 3D 减速渲染(局部计算 GPU),这样 Web 开发人员就能够借助零碎显卡来在浏览器里更流畅地展现 3D 场景和模型了,还能创立简单的导航和数据视觉化。显然,WebGL 技术标准免去了开发网页专用渲染插件的麻烦,可被用于创立具备简单 3D 构造的网站页面,甚至能够用来设计 3D 网页游戏等等。
总结一下,WebGL 的实质 —— JavaScript 操作 OpenGL 接口

    当然,WebGL 只是绑定了一层,外部的一些核心内容,如着色器,材质,灯光等都是须要借助 GLSL ES 语法来操作的。
1.2.1 WebGL / OpenGL / ES X.0 之间的关系?

  • OpenGL(Open Graphics Library)
    一种图形应用程序编程接口标准(Application Programming Interface,API)。它是一种能够对图形硬件设施个性进行拜访的软件库,OpenGL 被设计为一个现代化的、硬件无关的接口,因而咱们能够在不思考计算机操作系统或窗口零碎的前提下,在多种不同的图形硬件零碎上,齐全通过软件的形式实现 OpenGL 的接口。
  • OpenGL ES(embedded system)
    OpenGL ES 是 OpenGL 的一个非凡版本,次要针对嵌入式设施应用,专用于嵌入式计算机、智能手机、家用游戏机等设施。OpenGL ES 2003-2004 年被首次提出来,其中两次重要降级别离在 2007 年(OpenGL ES 2.0)和 2012 年(OpenGL ES 3.0),WebGL 就是基于 OpenGL ES 2.0 的。

二、如何应用 WebGL

2.1 入门示例,不再是 hello world!

  let gl = (document.getElementById('canvas') as HTMLCanvasElement).getContext('webgl') as WebGLRenderingContextBase;
    // 指定一个笼罩(清空)canvas 的 rgba 色彩,实质是 setColor, 它把背景色存到了 webgl system 中的 glCOLOR_BUFFER_BIT,得手动 render 一下
    gl.clearColor(0.0, 0.0, 0.5, 1.0);
    // 革除 canvas,会革除全副,再应用背景色 填充
    gl.clear(gl.COLOR_BUFFER_BIT);
  }

运行后果 & 流程示意:

论断:

  1. WebGL 须要依赖 canvas 这个载体获取对应的绘图上下文
  2. WebGL API 基于 OpenGL ES,函数命名绝对应
  3. WebGL 基于多缓冲区模型

2.2 绘制一个点

如果相似 canvas 2d 的话,你可能认为 WebGL 绘制一个点:

gl.drawColor(1.0, 1.0, 1.0, 1.0) // 点的色彩
gl.drawPoint(0, 0, 0, 10) // 点的地位大小

相似这样就能够了,可怜的是:
WebGL 依赖于一种着色器(shader)的绘图机制,简单而弱小,着色器是 WebGL 的外围机制。
WebGL 中着色器程序能够写成字符串变量:

// 顶点着色器程序
const VSHADER_SOURCE = `
        void main(){gl_Position = vec4(0.5,0.5,0.0,1);
          gl_PointSize = 10.0;
        }`;
// 片元着色器程序
const FSHADER_SOURCE = `
        void main(){gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }`;

当然也反对通过 ajax 申请读取 glsl 文件,又或者参考 MDN GLSL 示例,写在 script 标签中。
接下来咱们初始化着色器(包含加在着色器代码,创立程序,链接,编译等一套流程):

if (!initShaders(this.gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.error('初始化着色器失败');
  return;
}

绘制点:

// 指定一个笼罩(清空)this.canvas 的背景色彩
this.gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 用指定的色彩清空色彩缓冲,从而清空 canvas
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
// 将 1 个点绘制进去
this.gl.drawArrays(this.gl.POINTS, 0, 1);
this.gl.POINTS 指定 WebGL 的绘制模式为点绘制。

运行后果 & 流程示意:

(思考一下,为什么画在了屏幕右上角?轻轻提醒:坐标零碎)

论断:

  1. WebGL 须要两种着色器,应用 GLSL ES 语言来编写(须要学习老本)。

    1. 顶点着色器(Vertex shader):形容顶点个性(地位,尺寸)。
    2. 片元着色器(Fragment shader):形容 片元(像素)处理过程。
  2. 着色器运行在 WebGL 零碎中,而不是 JS 程序。
  3. WebGL 地位应用向量,应用右手坐标系。

    2.3 绘制多个动静的点

    上一节绘制出了一个点,然而点的地位、色彩之类属性是在代码中写死的,这种“硬编码”便于了解,然而不足可拓展性,怎么动静的设置点的信息呢?
    咱们的指标,将地位信息通过 Javascript 动静传给顶点着色器,须要通过上面的流程:

  4. 在顶点着色器,申明 attribute 变量。
  5. 将 attribute 变量赋值给 gl_Positon 变量。
  6. 向 attribute 变量传输数据。

咱们须要在第三步来绘制多个点,举个例子:
一共绘制 20 个点,采取的策略是:

  • 每次绘制一个点,绘制 20 次?
  • 绘制 1 次,一次性绘制 20 个点?
    当然抉择后者。咱们须要借助 缓冲区对象,一次性传入多个顶点数据。

    2.4 绘制一个箭头

    查看 Canvas 的绘图 API,咱们会发现它能画直线、矩形、圆、弧线、贝塞尔曲线。
    于是,咱们看了看 WebGL 绘图 API,发现:

    void gl.drawArrays(mode, first, count);

    mode 指定绘制图元的形式,可能值如下:

  • gl.POINTS: 绘制一系列点。
  • gl.LINE_STRIP: 绘制一个线条。即,绘制一系列线段,上一点连贯下一点。
  • gl.LINE_LOOP: 绘制一个线圈。即,绘制一系列线段,上一点连贯下一点,并且最初一点与第一个点相连。
  • gl.LINES: 绘制一系列独自线段。每两个点作为端点,线段之间不连贯。
  • gl.TRIANGLE_STRIP:绘制一个三角带。
  • gl.TRIANGLE_FAN:绘制一个三角扇。
  • gl.TRIANGLES: 绘制一系列三角形。每三个点作为顶点。

const VERTEXRS = [V0,V1,V2,V3,V4,V5];    

如图所示,WebGL 可只能绘制三种图元:点、线、三角形。不过所有其余图元,从圆到球体、从立方体到简单三维模型,都能够由一个个三角面片组成。实际上,咱们能够用三角形绘制出所有你想绘制的货色。
那么绘制一个箭头的思路能够有很多,举两个例子:

不过不同的绘制计划间接是有区别的,会影响到法线,进而影响面片方向(侧面还是反面)的判断,这些就不深刻介绍啦。

论断:

  1. WebGL 只能绘制点,线,三角形,然而万物能够由三角形组成(准则:数量越少越好)。

2.5 绘制一个正方体

2.5.1 对于三维世界

二维图形和三维图形,最显著的区别是:三维图形有深度,也就是 z 轴。咱们须要思考两个角度:

  1. 察看方向:观察者在什么地位,在看场景的哪一部分?

观察者的地位称为视点(eye point),从视点登程沿察看方向的射线 叫做眼帘(viewing direction),通过视图矩阵确定察看方向:

  1. 可视空间:观察者能看到多远?(能看多少?是否须要远小近大)
  2. 正摄投影:长方体可视空间,也称盒状空间:

正射投影能够通过投影矩阵确定可视空间:

Matrix4.setOrtho(left, right, bottom, top, near, far);
  • 透视投影:四棱锥 / 金字塔可视空间:

透视投影能够通过投影矩阵确定可视空间:

Matrix4.setPerspective(fov, aspect, near, far);
2.5.2 对于正方体

通过之前学习,咱们联想到,两个三角形能够拼成一个矩形立体,作为正方体一面。一个正方体也就是 62 = 12 个三角形,每个三角形 3 个顶点,也就是 12 3 = 36 个顶点。咱们的顶点着色器传入 36 个顶点就能够了。然而用失常逻辑一想,正方体实际上不是只有 8 个顶点吗?显然咱们定义 36 个是有反复的,并没有被多个三角形专用。
如你所愿,WebGL 提供了一个通过 gl.drawElements 函数的复用计划:
立方体被拆成 6 个面,每个面都由两个三角形组成,每个三角形都有三个顶点,和顶点列表中的三个点相关联。三角形列表中的数字示意该三角形的三个顶点在顶点列表中的索引值。如下图所示:

论断:

  1. WebGL 绘制 3D 较为简单,须要依赖视图矩阵和投影矩阵实现 3d 视觉效果,然而建模局部还是依赖于最小图元 - 三角形。

2.6 其余纳闷

  • 怎么样平移,旋转,缩放?
    A:线性代数上场啦。举个例子,平移须要将平移矩阵 [Tx,Ty,Tz] 传入顶点着色器,逐顶点操作,加到对应顶点坐标重量上,再赋值给 gl_positon。旋转、缩放相似。
  • 怎么样写文字?
    A:参考链接,或者能够用 tiny-sdf 库,文字即图片的计划。
  • 怎么实现动画?
    A:WebGL 不提供动画接口,次要依赖 requestAnimation 办法。
  • 怎么实现渐变色?
    A:借用顶点着色器缓冲区对象,通过 varying 变量,从顶点着色器向片元着色器传输数据。
  • 怎么实现背景图片?
    A:纹理映射(Texture Mapping)。在片元着色器将筹备好的纹理(Image 转换)取出赋值给片元。
  • 怎么画圆?
    A:把正方形削成圆形。片元着色器内能够通过坐标判断放弃绘制一些点。

三、WebGL 的流程原理

简略说来,WebGL 绘制过程包含以下三步:
1、获取顶点坐标

2、图元拆卸(即画出一个个三角形)

3、光栅化(生成片元,即一个个像素点)

残缺链路:


四、WebGL 的现状

看到下图,笔者不禁一把辛酸泪。

对于 WebGL 而言,最大的问题就是 兼容性

一. 浏览器支不反对?(入门难度:装置最新 chrome)

WebGL 遍及水平绝对较高。2.0 版本 Safari 仿佛正在接入,或者对 WebGL2.0 的推广有所助力。

二. 显卡支不反对?(天堂难度:换显卡)

三. 显卡和浏览器都 ok 的话,设置合不合理?(难以评估难度:对非开发者极不敌对)

  • Case1:浏览器设置开启硬件加速。
    关上 chrome 设置(地址栏输出 chrome://settings/),『显示高级设置』,找到『零碎』,在『应用硬件加速模式』选项前打钩,重启浏览器。
  • Case2:浏览器设置禁用 webgl
    WebGL:–disable-webgl
    关上 chrome://flags 面板(将这行字输出地址栏),ctrl/command + f 搜寻『–disable-webgl』并启用该选项。重启浏览器。
  • Case3:浏览器设置显卡黑名单
    Hardware accelerated:WebGL 已启用,并取得了显卡反对 Software only, hardware acceleration unavailable:WebGL 已启用,但没有显卡反对,只有软件渲染反对 Unavailable:WebGL 既没有显卡反对也没有软件反对。

WebGL 利用个别须要显卡减速,如果你的浏览器显示 WebGL 未取得显卡反对(即显示为前面两项),如上图 webgl2 Unavailable,则两种可能:

  1. 你电脑的显卡可能进入了 chrome 的黑名单。
  2. 2. 你的显卡不行(^_^)
    有一些显卡和显卡驱动因为 bug 太多会导致浏览器解体甚至零碎解体,所以很多浏览器都有一个显卡黑名单,对这些有问题的显卡和驱动,浏览器将不启用硬件加速。能够在 chrome://flags 中开启 –ignore-gpu-blacklist 来忽视这个黑名单(不举荐,可能会引发浏览器解体或者零碎解体)

    附录

    一些罕用的库:

  3. Three(基于原生 WebGL 封装运行的三维引擎,在所有 WebGL 引擎中,Three.js 是国内文材料最多、应用最宽泛的三维引擎)
  4. stats.js(JavaScript 性能监控器,能够测试 webgl 代码的渲染性能)
  5. dat.GUI(google 开发人员创立的,是一个轻量级的图形用户界面库(GUI 组件),应用这个库能够很容易地创立出可能扭转代码变量的界面组件)
  6. ShaderToy(一个酷炫乏味的网站,学习 shader 编程)
  7. rainbow(一个繁难的 webgl 渲染库,蕴含本次全副 demo⭐️)

参考资料及鸣谢

  • 图解 WebGL&Three.js 工作原理:
    https://www.cnblogs.com/wanbo…
  • 《WebGL 编程指南》:【必看】
正文完
 0