美高梅网投网站-美高梅手机网投-美高梅官方网站
做最好的网站

您的位置:美高梅网投网址 > Web前端 > 本文是自己读书 WebGL,本文是自己读书 WebGL

本文是自己读书 WebGL,本文是自己读书 WebGL

发布时间:2019-09-29 07:10编辑:Web前端浏览(188)

    WebGL技艺储备指南

    2015/12/22 · HTML5 · 1 评论 · WebGL

    原稿出处: 天猫商城前端团队(FED)- 叶斋   

    图片 1

    WebGL 是 HTML 5 草案的一片段,可以使得 Canvas 渲染三个维度场景。WebGL 尽管还未有广泛应用,但极具潜在的能量和设想空间。本文是本人上学 WebGL 时梳理知识系统的产物,花点时间整理出来与我们大快朵颐。

    WebGL 是 HTML 5 草案的一局地,能够使得 Canvas 渲染三维场景。WebGL 就算还未有广泛应用,但极具潜能和想象空间。本文是本身就学 WebGL 时梳理知识系统的产物,花点时间整理出来与我们大饱眼福。

    示例

    WebGL 很酷,有以下 demos 为证:

    追寻奥兹国
    赛车游戏
    泛舟的男孩(Goo Engine Demo)

    示例

    WebGL 很酷,有以下 demos 为证:

    检索奥兹国
    超跑游戏
    泛舟的男孩(Goo Engine Demo)

    本文的靶子

    本文的料想读者是:不熟谙图形学,熟习前端,希望通晓或系统学习 WebGL 的同校。

    正文不是 WebGL 的概述性作品,亦非完好详细的 WebGL 教程。本文只盼望变成一篇供 WebGL 初学者使用的总纲。

    本文的靶子

    本文的预期读者是:不了解图形学,熟练前端,希望了然或系统学习 WebGL 的校友。

    正文不是 WebGL 的概述性小说,亦不是完整详细的 WebGL 教程。本文只盼望形成一篇供 WebGL 初学者使用的提纲。

    Canvas

    深谙 Canvas 的同桌都驾驭,Canvas 绘图先要获取绘图上下文:

    JavaScript

    var context = canvas.getContext('2d');

    1
    var context = canvas.getContext('2d');

    context上调用各个函数绘制图形,比如:

    JavaScript

    // 绘制左上角为(0,0),右下角为(50, 50)的矩形 context.fillRect(0, 0, 50, 50);

    1
    2
    // 绘制左上角为(0,0),右下角为(50, 50)的矩形
    context.fillRect(0, 0, 50, 50);

    WebGL 相同供给得到绘图上下文:

    JavaScript

    var gl = canvas.getContext('webgl'); // 或 experimental-webgl

    1
    var gl = canvas.getContext('webgl'); // 或 experimental-webgl

    唯独接下去,借使想画一个矩形的话,就没这么轻巧了。实际上,Canvas 是浏览器封装好的二个制图景况,在实际上海展览中心开绘图操作时,浏览器照旧要求调用 OpenGL API。而 WebGL API 差相当的少就是 OpenGL API 未经封装,直接套了一层壳。

    Canvas 的越来越多文化,能够参照他事他说加以考察:

    • JS 权威指南的 21.4 节或 JS 高档程序设计中的 15 章
    • W3CSchool
    • 阮一峰的 Canvas 教程

    Canvas

    纯熟 Canvas 的同窗都精通,Canvas 绘图先要获取绘图上下文:

    var context = canvas.getContext('2d');
    

    context上调用各个函数绘制图形,例如:

    // 绘制左上角为(0,0),右下角为(50, 50)的矩形
    context.fillRect(0, 0, 50, 50);
    

    WebGL 一样需求获得绘图上下文:

    var gl = canvas.getContext('webgl'); // 或 experimental-webgl
    

    但是接下去,若是想画贰个矩形的话,就没这么简单了。实际上,Canvas 是浏览器封装好的多个制图遇到,在骨子里开展绘图操作时,浏览器依然需求调用 OpenGL API。而 WebGL API 大致便是 OpenGL API 未经封装,直接套了一层壳。

    Canvas 的越多学问,能够参照:

    • JS 权威指南的 21.4 节或 JS 高等程序设计中的 15 章
    • W3CSchool
    • 阮一峰的 Canvas 教程

    矩阵调换

    三个维度模型,从文件中读出来,到绘制在 Canvas 中,经历了每每坐标转换。

    一经有八个最简便的模型:三角形,七个极端分别为(-1,-1,0),(1,-1,0),(0,1,0)。那多少个数据是从文件中读出来的,是三角形最初先的坐标(局地坐标)。如下图所示,右臂坐标系。

    图片 2

    模型平常不会放在场景的原点,若是三角形的原点位于(0,0,-1)处,没有转动或缩放,多少个极点分别为(-1,-1,-1),(1,-1,-1),(0,1,-1),即世界坐标。

    图片 3

    绘图三维场景必得钦命三个观察者,假如阅览者位于(0,0,1)处何况看向三角形,那么七个极点相对于观望者的坐标为(-1,-1,-2),(1,-1,-2),(0,1,-2),即视图坐标。

    图片 4

    观望者的眼眸是三个点(那是看破投影的前提),水平视角和垂直视角都以90度,视线范围(目力所及)为[0,2]在Z轴上,观望者能够看见的区域是一个四棱台体。

    图片 5

    将四棱台体映射为正规立方(CCV,核心为原点,边长为2,边与坐标轴平行)。顶点在 CCV 中的坐标,离它最终在 Canvas 中的坐标已经很左近了,若是把 CCV 的前表面看成 Canvas,那么最后三角形就画在图中花青三角形的地点。

    图片 6

    上述调换是用矩阵来开展的。

    局地坐标 –(模型调换)-> 世界坐标 –(视图调换)-> 视图坐标 –(投影调换)–> CCV 坐标。

    以(0,1,0)为例,它的齐次向量为(0,0,1,1),上述转变的象征经过能够是:

    图片 7

    下边八个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。多个矩阵的值分别决议于:观看者的思想和视线距离,观察者在世界中的状态(地方和大势),模型在世界中的状态(地方和样子)。计算的结果是(0,1,1,2),化成齐次坐标是(0,0.5,0.5,1),正是其一点在CCV中的坐标,那么(0,0.5)就是在Canvas中的坐标(以为Canvas 宗旨为原点,长度宽度都为2)。

    地点出现的(0,0,1,1)是(0,0,1)的齐次向量。齐次向量(x,y,z,w)能够代表三个维度向量(x,y,z)参加矩阵运算,通俗地说,w 分量为 1 时表示地方,w 分量为 0 时表示位移。

    WebGL 未有提供任何有关上述转换的体制,开拓者需求亲自总结顶点的 CCV 坐标。

    关于坐标变换的更加的多内容,能够参照:

    • 计算机图形学中的5-7章
    • 转移矩阵@维基百科
    • 透视投影详解

    相比较复杂的是模型转变中的绕率性轴旋转(平常用四元数生成矩阵)和投影调换(上边的例子都没收涉及到)。

    有关绕猖狂轴旋转和四元数,能够参照:

    • 四元数@维基百科
    • 叁个鬼子对四元数公式的证实

    有关齐次向量的更加多内容,能够参照他事他说加以考察。

    • Computer图形学的5.2节
    • 齐次坐标@维基百科

    矩阵转换

    三维模型,从文件中读出来,到绘制在 Canvas 中,经历了每每坐标调换。

    若果有八个最简便的模型:三角形,四个极端分别为(-1,-1,0),(1,-1,0),(0,1,0)。那多少个数据是从文件中读出来的,是三角形最先叶的坐标(局地坐标)。如下图所示,右边手坐标系。

    图片 8

    模型日常不会放在场景的原点,假使三角形的原点位于(0,0,-1)处,未有转动或缩放,四个极点分别为(-1,-1,-1),(1,-1,-1),(0,1,-1),即世界坐标。

    图片 9

    绘图空间维度场景必须内定二个观望者,尽管阅览者位于(0,0,1)处何况看向三角形,那么多少个极点相对于观察者的坐标为(-1,-1,-2),(1,-1,-2),(0,1,-2),即视图坐标。

    图片 10

    观望者的双眼是贰个点(那是看破投影的前提),水平视角和垂直视角都是90度,视线范围(目力所及)为[0,2]在Z轴上,观望者能够看见的区域是二个四棱台体。

    图片 11

    将四棱台体映射为正规立方(CCV,中央为原点,边长为2,边与坐标轴平行)。顶点在 CCV 中的坐标,离它最后在 Canvas 中的坐标已经很周边了,借使把 CCV 的前表面看成 Canvas,那么最后三角形就画在图中黄色三角形的地方。

    图片 12

    上述转换是用矩阵来进展的。

    一部分坐标 –(模型转换)-> 世界坐标 –(视图调换)-> 视图坐标 –(投影转变)–> CCV 坐标。

    以(0,1,0)为例,它的齐次向量为(0,0,1,1),上述转换的象征经过能够是:

    图片 13

    上边多少个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。八个矩阵的值分别决计于:观看者的观点和视界距离,观望者在世界中的状态(地点和取向),模型在世界中的状态(地方和自由化)。总结的结果是(0,1,1,2),化成齐次坐标是(0,0.5,0.5,1),正是其一点在CCV中的坐标,那么(0,0.5)便是在Canvas中的坐标(感觉Canvas 主题为原点,长度宽度都为2)。

    地方出现的(0,0,1,1)是(0,0,1)的齐次向量。齐次向量(x,y,z,w)能够代表三个维度向量(x,y,z)到场矩阵运算,通俗地说,w 分量为 1 时表示地方,w 分量为 0 时表示位移。

    WebGL 未有提供任何有关上述转变的机制,开采者供给亲自总括顶点的 CCV 坐标。

    至于坐标调换的越来越多内容,能够参见:

    • Computer图形学中的5-7章
    • 转移矩阵@维基百科
    • 透视投影详解

    相比复杂的是模型调换中的绕大肆轴旋转(平时用四元数生成矩阵)和投影转换(上边的例子都没收涉及到)。

    关于绕跋扈轴旋转和四元数,能够参照:

    • 四元数@维基百科
    • 叁个鬼子对四元数公式的申明

    有关齐次向量的更加多内容,能够参谋。

    • Computer图形学的5.2节
    • 齐次坐标@维基百科

    着色器和光栅化

    在 WebGL 中,开辟者是由此着色器来成功上述转变的。着色器是运营在显卡中的程序,以 GLSL 语言编写,开垦者须要将着色器的源码以字符串的款型传给 WebGL 上下文的相关函数。

    着色器有三种,顶点着色器和片元(像素)着色器,它们成对出现。顶点着色器职分是吸取顶点的片段坐标,输出 CCV 坐标。CCV 坐标经过光栅化,转化为逐像素的数据,传给片元着色器。片元着色器的职责是规定每一种片元的颜色。

    终端着色器接收的是 attribute 变量,是逐顶点的多寡。顶点着色器输出 varying 变量,也是逐顶点的。逐顶点的 varying 变量数据经过光栅化,成为逐片元的 varying 变量数据,输入片元着色器,片元着色器输出的结果就能议及展览示在 Canvas 上。

    图片 14

    着色器功效比非常多,上述只是基本成效。超过四分之二绚烂的职能都是凭仗着色器的。固然您对着色器完全未有概念,能够试着明亮下一节 hello world 程序中的着色器再回顾一下本节。

    至于更加的多着色器的学识,能够参谋:

    • GLSL@维基百科
    • WebGL@MSDN

    着色器和光栅化

    在 WebGL 中,开垦者是经过着色器来实现上述转换的。着色器是运营在显卡中的程序,以 GLSL 语言编写,开拓者供给将着色器的源码以字符串的花样传给 WebGL 上下文的连带函数。

    着色器有三种,顶点着色器和片元(像素)着色器,它们成对出现。顶点着色器义务是抽取顶点的有的坐标,输出 CCV 坐标。CCV 坐标经过光栅化,转化为逐像素的数目,传给片元着色器。片元着色器的职责是规定各个片元的颜料。

    极限着色器接收的是 attribute 变量,是逐顶点的数目。顶点着色器输出 varying 变量,也是逐顶点的。逐顶点的 varying 变量数据经过光栅化,成为逐片元的 varying 变量数据,输入片元着色器,片元着色器输出的结果就能显得在 Canvas 上。

    图片 15

    着色器成效非常多,上述只是基本功能。超越四分之二炫丽的功效都以借助着色器的。假设你对着色器完全未有概念,能够试着明亮下一节 hello world 程序中的着色器再纪念一下本节。

    关于越多着色器的知识,能够参照:

    • GLSL@维基百科
    • WebGL@MSDN

    程序

    这一节解释绘制上述场景(三角形)的 WebGL 程序。点本条链接,查看源代码,试图精晓一下。这段代码出自WebGL Programming Guide,笔者作了一部分修改以适应本文内容。如若一切寻常,你见到的相应是上面那样:

    图片 16

    表明几点(假诺在此以前不驾驭 WebGL ,多半会对上面包车型地铁代码狐疑,无碍):

    1. 字符串 VSHADER_SOURCE 和 FSHADER_SOURCE 是终点着色器和片元着色器的源码。能够将着色器驾驭为有定位输入和出口格式的前后相继。开拓者须要事先编写好着色器,再依照一定格式着色器发送绘图命令。
    2. Part2 将着色器源码编写翻译为 program 对象:先分别编写翻译顶点着色器和片元着色器,然后连接两个。假设编译源码错误,不会报 JS 错误,但能够经过其余API(如gl.getShaderInfo等)获取编写翻译状态新闻(成功与否,若是出错的错误消息)。
    JavaScript
    
    // 顶点着色器 var vshader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vshader, VSHADER_SOURCE);
    gl.compileShader(vshader); // 同样新建 fshader var program =
    gl.createProgram(); gl.attachShader(program, vshader);
    gl.attachShader(program, fshader); gl.linkProgram(program);
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f14b3a671c960813930-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a671c960813930-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a671c960813930-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a671c960813930-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a671c960813930-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a671c960813930-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a671c960813930-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a671c960813930-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a671c960813930-9">
    9
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f14b3a671c960813930-1" class="crayon-line">
    // 顶点着色器
    </div>
    <div id="crayon-5b8f14b3a671c960813930-2" class="crayon-line crayon-striped-line">
    var vshader = gl.createShader(gl.VERTEX_SHADER);
    </div>
    <div id="crayon-5b8f14b3a671c960813930-3" class="crayon-line">
    gl.shaderSource(vshader, VSHADER_SOURCE);
    </div>
    <div id="crayon-5b8f14b3a671c960813930-4" class="crayon-line crayon-striped-line">
    gl.compileShader(vshader);
    </div>
    <div id="crayon-5b8f14b3a671c960813930-5" class="crayon-line">
    // 同样新建 fshader
    </div>
    <div id="crayon-5b8f14b3a671c960813930-6" class="crayon-line crayon-striped-line">
    var program = gl.createProgram();
    </div>
    <div id="crayon-5b8f14b3a671c960813930-7" class="crayon-line">
    gl.attachShader(program, vshader);
    </div>
    <div id="crayon-5b8f14b3a671c960813930-8" class="crayon-line crayon-striped-line">
    gl.attachShader(program, fshader);
    </div>
    <div id="crayon-5b8f14b3a671c960813930-9" class="crayon-line">
    gl.linkProgram(program);
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    1. program 对象急需内定使用它,才方可向着色器传数据并绘制。复杂的顺序平日有五个program 对 象,(绘制每一帧时)通过切换 program 对象绘制场景中的差别作用。
    JavaScript
    
    gl.useProgram(program);
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f14b3a6720232020477-1">
    1
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f14b3a6720232020477-1" class="crayon-line">
    gl.useProgram(program);
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    1. Part3 向正在选拔的着色器传入数据,包涵逐顶点的 attribute 变量和大局的 uniform 变量。向着色器传入数据必得接纳ArrayBuffer,实际不是平常的 JS 数组。
    JavaScript
    
    var varray = new Float32Array([-1, -1, 0, 1, -1, 0, 0, 1, 0])
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f14b3a6723482450329-1">
    1
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f14b3a6723482450329-1" class="crayon-line">
    var varray = new Float32Array([-1, -1, 0, 1, -1, 0, 0, 1, 0])
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    1. WebGL API 对 ArrayBuffer 的操作(填充缓冲区,传入着色器,绘制等)都以经过 gl.AMuranoRAY_BUFFE奥迪Q5进行的。在 WebGL 系统中又非常多近乎的场合。
    JavaScript
    
    // 只有将 vbuffer 绑定到 gl.ARRAY_BUFFER,才可以填充数据
    gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer); // 这里的意思是,向“绑定到
    gl.ARRAY_BUFFER”的缓冲区中填充数据 gl.bufferData(gl.ARRAY_BUFFER,
    varray, gl.STATIC_DRAW); // 获取 a_Position
    变量在着色器程序中的位置,参考顶点着色器源码 var aloc =
    gl.getAttribLocation(program, 'a_Position'); // 将 gl.ARRAY_BUFFER
    中的数据传入 aloc 表示的变量,即 a_Position
    gl.vertexAttribPointer(aloc, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(aloc);
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f14b3a6727492492738-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a6727492492738-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a6727492492738-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a6727492492738-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a6727492492738-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a6727492492738-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a6727492492738-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f14b3a6727492492738-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f14b3a6727492492738-9">
    9
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f14b3a6727492492738-1" class="crayon-line">
    // 只有将 vbuffer 绑定到 gl.ARRAY_BUFFER,才可以填充数据
    </div>
    <div id="crayon-5b8f14b3a6727492492738-2" class="crayon-line crayon-striped-line">
    gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
    </div>
    <div id="crayon-5b8f14b3a6727492492738-3" class="crayon-line">
    // 这里的意思是,向“绑定到 gl.ARRAY_BUFFER”的缓冲区中填充数据
    </div>
    <div id="crayon-5b8f14b3a6727492492738-4" class="crayon-line crayon-striped-line">
    gl.bufferData(gl.ARRAY_BUFFER, varray, gl.STATIC_DRAW);
    </div>
    <div id="crayon-5b8f14b3a6727492492738-5" class="crayon-line">
    // 获取 a_Position 变量在着色器程序中的位置,参考顶点着色器源码
    </div>
    <div id="crayon-5b8f14b3a6727492492738-6" class="crayon-line crayon-striped-line">
    var aloc = gl.getAttribLocation(program, 'a_Position');
    </div>
    <div id="crayon-5b8f14b3a6727492492738-7" class="crayon-line">
    // 将 gl.ARRAY_BUFFER 中的数据传入 aloc 表示的变量,即 a_Position
    </div>
    <div id="crayon-5b8f14b3a6727492492738-8" class="crayon-line crayon-striped-line">
    gl.vertexAttribPointer(aloc, 3, gl.FLOAT, false, 0, 0);
    </div>
    <div id="crayon-5b8f14b3a6727492492738-9" class="crayon-line">
    gl.enableVertexAttribArray(aloc);
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    1. 向着色器传入矩阵时,是按列存款和储蓄的。能够相比较一下 mmatrix 和矩阵转换一节中的模型矩阵(第 3 个)。
    2. 极端着色器总结出的 gl_Position 就是 CCV 中的坐标,例如最上边的终极(浅红色)的 gl_Position 化成齐次坐标就是(0,0.5,0.5,1)。
    3. 向终极着色器传入的只是多个终端的颜色值,而三角形表面包车型大巴水彩渐变是由那多个颜色值内插出的。光栅化不仅仅会对 gl_Position 举办,还大概会对 varying 变量插值。
    4. gl.drawArrays()方法使得缓冲区举办绘图,gl.T奥迪R8IANGLES 钦赐绘制三角形,也可以改换参数绘制点、折线等等。

    关于 ArrayBuffer 的详细音信,能够参照:

    • ArrayBuffer@MDN
    • 阮一峰的 ArrayBuffer 介绍
    • 张鑫旭的 ArrayBuffer 介绍

    有关 gl.T讴歌RDXIANGLES 等任何绘制情势,可以参照下边那张图或那篇博文。

    图片 17

    程序

    这一节解释绘制上述现象(三角形)的 WebGL 程序。点其一链接,查看源代码,试图通晓一下。这段代码出自WebGL Programming Guide,小编作了有的修改以适应本文内容。即便一切平常,你看看的应该是下面那样:

    图片 18

    演讲几点(纵然从前不精通 WebGL ,多半会对下边包车型客车代码困惑,无碍):

    1. 字符串 VSHADER_SOURCE 和 FSHADER_SOURCE 是终极着色器和片元着色器的源码。能够将着色器精通为有确定地点输入和出口格式的程序。开垦者须要事先编写好着色器,再依据一定格式着色器发送绘图命令。

    2. Part2 将着色器源码编写翻译为 program 对象:先分别编写翻译顶点着色器和片元着色器,然后连接两个。借使编写翻译源码错误,不会报 JS 错误,但足以因此任何 API(如gl.getShaderInfo等)获取编译状态新闻(成功与否,假设出错的错误音信)。

      // 顶点着色器
      var vshader = gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vshader, VSHADER_SOURCE);
      gl.compileShader(vshader);
      // 同样新建 fshader
      var program = gl.createProgram();
      gl.attachShader(program, vshader);
      gl.attachShader(program, fshader);
      gl.linkProgram(program);
      
    3. program 对象急需内定使用它,才得以向着色器传数据并绘制。复杂的次序日常有八个program 对 象,(绘制每一帧时)通过切换 program 对象绘制场景中的差别功能。

      gl.useProgram(program);
      
    4. Part3 向正在使用的着色器传入数据,富含逐顶点的 attribute 变量和大局的 uniform 变量。向着色器传入数据必得运用 ArrayBuffer,并非例行的 JS 数组。

      var varray = new Float32Array([-1, -1, 0, 1, -1, 0, 0, 1, 0])
      
    5. WebGL API 对 ArrayBuffer 的操作(填充缓冲区,传入着色器,绘制等)都以因此 gl.A福睿斯RAY_BUFFE昂Cora举办的。在 WebGL 系统中又相当多好像的事态。

      // 只有将 vbuffer 绑定到 gl.ARRAY_BUFFER,才可以填充数据
      gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
      // 这里的意思是,向“绑定到 gl.ARRAY_BUFFER”的缓冲区中填充数据
      gl.bufferData(gl.ARRAY_BUFFER, varray, gl.STATIC_DRAW);
      // 获取 a_Position 变量在着色器程序中的位置,参考顶点着色器源码
      var aloc = gl.getAttribLocation(program, 'a_Position');
      // 将 gl.ARRAY_BUFFER 中的数据传入 aloc 表示的变量,即 a_Position
      gl.vertexAttribPointer(aloc, 3, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray(aloc);
      
    6. 向着色器传入矩阵时,是按列存款和储蓄的。能够相比较一下 mmatrix 和矩阵调换一节中的模型矩阵(第 3 个)。

    7. 顶点着色器计算出的 gl_Position 就是 CCV 中的坐标,比如最上边包车型客车顶峰(金红)的 gl_Position 化成齐次坐标正是(0,0.5,0.5,1)。

    8. 向终极着色器传入的只是八个极点的水彩值,而三角形表面包车型地铁水彩渐变是由那多少个颜色值内插出的。光栅化不独有会对 gl_Position 实行,还也许会对 varying 变量插值。

    9. gl.drawArrays()方法使得缓冲区举办绘图,gl.T中华VIANGLES 钦点绘制三角形,也得以转移参数绘制点、折线等等。

    有关 ArrayBuffer 的详细音讯,能够参照:

    • ArrayBuffer@MDN
    • 阮一峰的 ArrayBuffer 介绍
    • 张鑫旭的 ArrayBuffer 介绍

    有关 gl.T库罗德IANGLES 等别的绘制情势,能够参照他事他说加以考察上面那张图或那篇博文。

    图片 19

    纵深检查评定

    当多少个外表重叠时,后边的模型会掩盖后边的模型。比如这几个事例,绘制了多少个交叉的三角形( varray 和 carray 的长度变为 18,gl.drawArrays 最终二个参数变为 6)。为了简单,那些事例去掉了矩阵转换进度,直接向着色器传入 CCV 坐标。

    图片 20

    图片 21

    终端着色器给出了 6 个极端的 gl_Position ,经过光栅化,片元着色器获得了 2X 个片元(就算 X 为种种三角形的像素个数),每一种片元都离散的 x,y 坐标值,还应该有 z 值。x,y 坐标便是三角形在 Canvas 上的坐标,但要是有多个颇具一样 x,y 坐标的片元同期出现,那么 WebGL 就能取 z 坐标值十分小的极度片元。

    在深度检测从前,必得在绘制前拉开三个常量。不然,WebGL 就能安分守己在 varray 中定义的逐一绘制了,后边的会覆盖后面包车型地铁。

    JavaScript

    gl.enable(gl.DEPTH_TEST);

    1
    gl.enable(gl.DEPTH_TEST);

    骨子里,WebGL 的逻辑是这般的:依次拍卖片元,若是渲染缓冲区(这里正是Canvas 了)的非常与近来片元对应的像素还未曾绘制时,就把片元的颜料画到渲染缓冲区对应像素里,同期把片元的 z 值缓存在另三个纵深缓冲区的均等地点;假设当前缓冲区的呼应像素已经绘制过了,就去查看深度缓冲区中对应地方的 z 值,即使当前片元 z 值小,就重绘,不然就放任当前片元。

    WebGL 的那套逻辑,对掌握蒙版(前面会聊起)有一点点补助。

    纵深检查测量试验

    当五个外表重叠时,前面包车型地铁模型会掩盖前面包车型地铁模子。比方本条例子,绘制了多个交叉的三角( varray 和 carray 的尺寸变为 18,gl.drawArrays 最后三个参数变为 6)。为了轻巧,那些事例去掉了矩阵转换进度,直接向着色器传入 CCV 坐标。

    图片 22

    图片 23

    顶点着色器给出了 6 个顶峰的 gl_Position ,经过光栅化,片元着色器得到了 2X 个片元(即使 X 为各种三角形的像素个数),各种片元都离散的 x,y 坐标值,还可能有 z 值。x,y 坐标正是三角形在 Canvas 上的坐标,但假如有五个具备同样 x,y 坐标的片元相同的时间出现,那么 WebGL 就能取 z 坐标值非常小的不得了片元。

    在深度检验从前,必需在绘制前拉开一个常量。不然,WebGL 就能够依照在 varray 中定义的各种绘制了,后边的会覆盖后面包车型大巴。

    gl.enable(gl.DEPTH_TEST);
    

    实际上,WebGL 的逻辑是这么的:依次拍卖片元,若是渲染缓冲区(这里就是Canvas 了)的分外与当下片元对应的像素还一直不绘制时,就把片元的颜色画到渲染缓冲区对应像素里,同一时间把片元的 z 值缓存在另三个纵深缓冲区的等同位置;假诺当前缓冲区的呼应像素已经绘制过了,就去查看深度缓冲区中对应地点的 z 值,要是当前片元 z 值小,就重绘,不然就放弃当前片元。

    WebGL 的那套逻辑,对明白蒙版(后边会提起)有一点赞助。

    顶点索引

    gl.drawArrays()是遵照顶点的逐个绘制的,而 gl.drawElements()能够令着色器以二个索引数组为顺序绘制顶点。例如以此例子。

    图片 24

    那边画了三个三角形,但只用了 5 个终端,有二个终极被四个三角共用。那时须求建设构造索引数组,数组的每一个元素表示顶点的索引值。将数组填充至gl.ELEMENT_ARRAY,然后调用 gl.drawElements()。

    JavaScript

    var iarray = new Uint8Array([0,1,2,2,3,4]); var ibuffer = gl.createBuffer(gl.ARRAY_BUFFER, ibuffer); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, iarray, gl.STATIC_DRAW);

    1
    2
    3
    4
    var iarray = new Uint8Array([0,1,2,2,3,4]);
    var ibuffer = gl.createBuffer(gl.ARRAY_BUFFER, ibuffer);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, iarray, gl.STATIC_DRAW);

    顶点索引

    gl.drawArrays()是依照顶点的次第绘制的,而 gl.drawElements()能够令着色器以一个索引数组为顺序绘制顶点。比方那个事例。

    图片 25

    此间画了三个三角,但只用了 5 个顶峰,有贰个巅峰被四个三角共用。那时急需树立索引数组,数组的各种成分表示顶点的索引值。将数组填充至gl.ELEMENT_ARRAY,然后调用 gl.drawElements()。

    var iarray = new Uint8Array([0,1,2,2,3,4]);
    var ibuffer = gl.createBuffer(gl.ARRAY_BUFFER, ibuffer);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, iarray, gl.STATIC_DRAW);
    

    纹理

    attribute 变量不只能够传递顶点的坐标,还足以传递别的任何逐顶点的数码。举例HelloTriangle 程序把单个顶点的颜料传入了 a_Color,片元着色器收到 v_Color 后平昔赋给 gl_FragmentColor,就调节了颜色。

    attribute 变量还足以扶持绘制纹理。绘制纹理的基本原理是,为各类终端钦赐一个纹理坐标(在(0,0)与(1,1,)的方框形中),然后传入纹理对象。片元着色器拿到的是对应片元的内插后的纹理坐标,就应用这几个纹理坐标去纹理对象上取颜色,再画到片元上。内插后的纹理坐标很只怕不正好对应纹理上的某些像素,而是在多少个像素之间(因为日常的图样纹理也是离散),那时或者会透过相近多少个像素的加权平均算出该像素的值(具体有几多种分歧格局,能够仿效)。

    比如那一个事例。

    图片 26

    纹理对象和缓冲区指标很周边:使用 gl 的 API 函数创立,须要绑定至常量 gl.AEvoqueRAY_BUFFER 和 gl.TEXTURE_2D ,都经过常量对象向在那之中填入图像和数码。分化的是,纹理对象在绑定时还供给激活贰个纹理单元(此处的gl.TEXTURE0),而 WebGL 系统援救的纹理单元个数是很单薄的(经常为 8 个)。

    JavaScript

    var texture = gl.createTexture(); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, textureImage); var sloc = gl.getUniformLocation(program, 'u_Sampler'); gl.uniform1i(sloc, 0);

    1
    2
    3
    4
    5
    6
    7
    8
    var texture = gl.createTexture();
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, textureImage);
    var sloc = gl.getUniformLocation(program, 'u_Sampler');
    gl.uniform1i(sloc, 0);

    片元着色器内注解了 sampler2D 类型的 uniform 变量,通过texture2D函数取样。

    JavaScript

    precision mediump float; uniform sampler2D u_Sampler; varying vec2 v_TexCoord; void main() { gl_FragColor = texture2D(u_Sampler, v_TexCoord); };

    1
    2
    3
    4
    5
    6
    precision mediump float;
    uniform sampler2D u_Sampler;
    varying vec2 v_TexCoord;
    void main() {
      gl_FragColor = texture2D(u_Sampler, v_TexCoord);
    };

    纹理

    attribute 变量不只好传递顶点的坐标,仍是能够传递别的任何逐顶点的数量。比方HelloTriangle 程序把单个顶点的颜料传入了 a_Color,片元着色器收到 v_Color 后直接赋给 gl_FragmentColor,就决定了颜色。

    attribute 变量还能匡助绘制纹理。绘制纹理的基本原理是,为每一种终端内定三个纹理坐标(在(0,0)与(1,1,)的方框形中),然后传入纹理对象。片元着色器得到的是对应片元的内插后的纹路坐标,就应用那一个纹理坐标去纹理对象上取颜色,再画到片元上。内插后的纹路坐标很可能不正好对应纹理上的某部像素,而是在多少个像素之间(因为平日的图片纹理也是离散),那时或许会因此周边多少个像素的加权平均算出该像素的值(具体有多少种区别措施,能够参照)。

    比如其一例子。

    图片 27

    纹理对象和缓冲区目的很类似:使用 gl 的 API 函数创设,必要绑定至常量 gl.ARRAY_BUFFER 和 gl.TEXTURE_2D ,都通过常量对象向里面填入图像和数量。分裂的是,纹理对象在绑按时还亟需激活贰个纹理单元(此处的gl.TEXTURE0),而 WebGL 系统帮衬的纹路单元个数是很有限的(平时为 8 个)。

    var texture = gl.createTexture();
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, textureImage);
    var sloc = gl.getUniformLocation(program, 'u_Sampler');
    gl.uniform1i(sloc, 0);
    

    片元着色器内表明了 sampler2D 类型的 uniform 变量,通过texture2D函数取样。

    precision mediump float;
    uniform sampler2D u_Sampler;
    varying vec2 v_TexCoord;
    void main() {
      gl_FragColor = texture2D(u_Sampler, v_TexCoord);
    };
    

    混合与蒙版

    晶莹剔透效果是用混合机制产生的。混合机制与深度检查评定类似,也发出在计划向某些已填写的像素填充颜色时。深度检验通过相比z值来规定像素的颜料,而掺杂机制会将两种颜色混合。比方那些事例。

    图片 28

    掺杂的次第是绳趋尺步绘制的次第进行的,要是绘制的顺序有变化,混合的结果常常也比不上。借使模型既有非透明表面又有透明表面,绘制透明表面时张开蒙版,其指标是锁定深度缓冲区,因为半透明物体前面包车型地铁物体依然得以看出的,如若不这么做,半晶莹剔透物体前面的物体将会被深度检查实验机制排除。

    张开混合的代码如下。gl.blendFunc主意钦点了混合的点子,这里的意趣是,使用源(待混合)颜色的 α 值乘以源颜色,加上 1-[源颜色的 α]乘以指标颜色。

    JavaScript

    gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

    1
    2
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

    所谓 α 值,正是颜色的第 4 个轻重。

    JavaScript

    var carray = new Float32Array([ 1,0,0,0.7,1,0,0,0.7,1,0,0,0.7, 0,0,1,0.4,0,0,1,0.4,0,0,1,0.4 ]);

    1
    2
    3
    4
    var carray = new Float32Array([
      1,0,0,0.7,1,0,0,0.7,1,0,0,0.7,
      0,0,1,0.4,0,0,1,0.4,0,0,1,0.4
      ]);

    错落与蒙版

    晶莹剔透效果是用混合机制作而成功的。混合机制与深度检验类似,也时有发生在准备向有个别已填写的像素填充颜色时。深度检查评定通过相比较z值来鲜明像素的颜色,而掺杂机制会将三种颜色混合。举例那些事例。

    图片 29

    错落的次第是根据绘制的顺序实行的,若是绘制的相继有生成,混合的结果平日也不一样。假设模型既有非透明表面又有晶莹剔透表面,绘制透明表面时张开蒙版,其目标是锁定深度缓冲区,因为半透明物体前面包车型大巴实体照旧得以阅览的,假使不那样做,半透明物体前面包车型大巴物体将会被深度检查实验机制排除。

    开启混合的代码如下。gl.blendFunc方式钦定了混合的格局,这里的情致是,使用源(待混合)颜色的 α 值乘以源颜色,加上 1-[源颜色的 α]乘以目的颜色。

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    

    所谓 α 值,正是颜色的第 4 个轻重。

    var carray = new Float32Array([
      1,0,0,0.7,1,0,0,0.7,1,0,0,0.7,
      0,0,1,0.4,0,0,1,0.4,0,0,1,0.4
      ]);
    

    浏览器的WebGL系统

    WebGL 系统依次组成都部队分在既定准则下互匹同盟。稍作梳理如下。

    图片 30

    那张图比较随便,箭头上的文字表示 API,箭头方向大约表现了数量的流淌方向,不必深究。

    浏览器的WebGL系统

    WebGL 系统依次组成部分在既定规则下相互称合。稍作梳理如下。

    图片 31

    那张图相比较随意,箭头上的文字表示 API,箭头方向大致表现了数量的流动方向,不必深究。

    光照

    WebGL 未有为光照提供其余内置的不二等秘书籍,须要开拓者在着色器中完成光照算法。

    只不过有颜色的,模型也可以有颜色的。在光照下,最后物体呈现的水彩是两岸一齐功用的结果。

    兑现光照的不二诀要是:将光照的多少(点光源的职位,平行光的动向,以及光的颜料和强度)作为 uniform 变量传入着色器中,将物体表面各种顶点处的法线作为 attribute 变量传入着色器,遵循光照准绳,修订最终片元展现的颜料。

    光照又分为逐顶点的和逐片元的,两个的分歧是,将法线光线交角因素位居顶点着色器初级中学毕业生升学考试虑或许放在片元着色器初级中学完成学业生升学考试虑。逐片元光照更是维妙维肖,三个非常的例证是:

    图片 32

    那时候,点光源在离开多少个外界较近处,表面中心 A 处较亮,四周较暗。不过在逐顶点光照下,表面包车型客车颜色(的熏陶因子)是由顶点内插出来的,所以表面中心也会比较暗。而逐片元光照直接使用片元的岗位和法线总计与点光源的交角,因而表面中心会比较亮。

    光照

    WebGL 未有为光照提供任何内置的秘诀,须要开辟者在着色器中达成光照算法。

    只不过有颜色的,模型也可能有颜色的。在光照下,最终物体显示的水彩是五头一同效用的结果。

    达成光照的诀窍是:将光照的数目(点光源的职责,平行光的可行性,以及光的颜料和强度)作为 uniform 变量传入着色器中,将物身体表面面每一种顶点处的法线作为 attribute 变量传入着色器,遵循光照准绳,修订最后片元呈现的颜料。

    光照又分为逐顶点的和逐片元的,两个的区分是,将法线光线交角因素位居顶点着色器初中结业生升学考试虑依然放在片元着色器初级中学毕业生升学考试虑。逐片元光照更是活龙活现,一个Infiniti的例证是:

    图片 33

    这会儿,点光源在离开三个外界较近处,表面中心 A 处较亮,四周较暗。不过在逐顶点光照下,表面包车型地铁颜色(的熏陶因子)是由顶点内插出来的,所以表面中心也会相比暗。而逐片元光照直接运用片元的地方和法线计算与点光源的交角,由此表面中心会相比亮。

    复杂模型

    复杂模型大概有蕴含子模型,子模型或许与父模型有相对运动。举个例子开着雨刮器的小车,雨刮器的世界坐标是受父模型小车,和我的状态共同决定的。若要总括雨刮器某顶点的地点,需求用雨刮器相对汽车的模型矩阵乘SAIC车的模型矩阵,再乘以顶点的一些坐标。

    复杂模型也许有成千上万外界,可能各类表面使用的着色器就分裂。平常将模型拆解为组,使用同样着色器的外表为一组,先绘制同一组中的内容,然后切换着色器。每一趟切换着色器都要再度将缓冲区中的数据分配给着色器中相应变量。

    复杂模型

    复杂模型也许有囊括子模型,子模型大概与父模型有相对运动。比方开着雨刮器的小车,雨刮器的世界坐标是受父模型汽车,和本身的情况共同决定的。若要总括雨刮器某顶点的职位,须要用雨刮器相对汽车的模型矩阵乘SAIC车的模子矩阵,再乘以顶点的一部分坐标。

    复杂模型恐怕有广大表面,或许各种表面使用的着色器就分化。经常将模型拆解为组,使用同一着色器的外界为一组,先绘制同一组中的内容,然后切换着色器。每一遍切换着色器都要双重将缓冲区中的数据分配给着色器中相应变量。

    动画

    动画的原理正是快速地擦除和重绘。常用的法子是响当当的 requestAnimationFrame 。不熟知的同校,可以参照正美的介绍。

    动画

    动画片的规律正是高速地擦除和重绘。常用的艺术是引人注目标requestAnimationFrame 。目生的同校,能够参谋正美的牵线。

    WebGL库

    时下最流行的 WebGL 库是 ThreeJS,很强劲,官网,代码。

    WebGL库

    方今最流行的 WebGL 库是 ThreeJS,很强劲,官网,代码。

    调解工具

    正如早熟的 WebGL 调节和测验工具是WebGL Inspector。

    调解工具

    正如早熟的 WebGL 调节和测量检验工具是WebGL Inspector。

    网络能源和书本

    韩语的有关 WebGL 的能源有为数相当的多,包含:

    • learning webgl
    • WebGL@MDN
    • WebGL Cheat Sheet

    国内最初的 WebGL 教程是由郝稼力翻译的,放在 hiwebgl 上,最近 hiwebgl 已经关门,但教程还是能在这里找到。郝稼力近日运行着Lao3D。

    本国曾经问世的 WebGL 书籍有:

    • WebGL入门指南:其实是一本讲 ThreeJS 的书
    • WebGL高档编制程序:尚可的一本
    • WebGL编制程序指南:极其可信赖的巨细无遗教程

    提起底再混合一点走私物品吧。读书时期本人曾花了小八个月时光翻译了一本WebGL的书,也正是上边的第 3 本。这本书真的优异可靠,网络各样课程里非常多没说通晓的事物,那本书说得很明白,况兼还提供了一份很完整的API文档。翻译那本书的进程也使笔者有异常的大的收获。若是有同学愿意系统学一下 WebGL 的,提出购买一本(文青提出买英文版)。

    1 赞 2 收藏 1 评论

    图片 34

    网络能源和本本

    法语的有关 WebGL 的能源有无数,包蕴:

    • learning webgl
    • WebGL@MDN
    • WebGL Cheat Sheet

    境内最先的 WebGL 教程是由郝稼力翻译的,放在 hiwebgl 上,近期 hiwebgl 已经关门,但教程还足以在这里找到。郝稼力前段时间运行着Lao3D。

    境内曾经问世的 WebGL 书籍有:

    • WebGL入门指南:其实是一本讲 ThreeJS 的书
    • WebGL高档编制程序:还不易的一本
    • WebGL编程指南:相当可信赖的两全教程

    本文由美高梅网投网址发布于Web前端,转载请注明出处:本文是自己读书 WebGL,本文是自己读书 WebGL

    关键词: