新萄京娱乐场.2959.com 25

WebGL技术储备指南,技术储备指南

WebGL本领储备指南

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

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

新萄京娱乐场.2959.com 1

WebGL 是 HTML 五 草案的1部分,可以使得 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

唯独接下去,假如想画2个矩形的话,就没这么轻便了。实际上,Canvas
是浏览器封装好的叁个制图遭逢,在实质上进行绘图操作时,浏览器依旧须要调用
OpenGL API。而 WebGL API 差不多正是 OpenGL API 未经封装,直接套了一层壳。

Canvas 的更加多知识,能够参见:

  • JS
    权威指南的
    21.4 节或 JS
    高等程序设计中的
    15 章
  • W3CSchool
  • 阮1峰的 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),(一,-一,0),(0,一,0)。那两个数据是从文件中读出来的,是三角形最开始的坐标(局地坐标)。如下图所示,右手坐标系。

新萄京娱乐场.2959.com 2

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

新萄京娱乐场.2959.com 3

绘图三个维度场景必须钦赐3个观察者,假如观看者位于(0,0,一)处而且看向三角形,那么七个极端相对于观望者的坐标为(-1,-1,-2),(1,-1,-二),(0,壹,-2),即视图坐标。

新萄京娱乐场.2959.com 4

观看者的眸子是多个点(那是看破投影的前提),水平视角和垂直视角都是90度,视界范围(目力所及)为[0,2]在Z轴上,观察者可以看出的区域是1个四棱台体。

新萄京娱乐场.2959.com 5

将四棱台体映射为行业内部立方(CCV,中央为原点,边长为二,边与坐标轴平行)。顶点在
CCV 中的坐标,离它谈到底在 Canvas 中的坐标已经很类似了,假若把 CCV
的前表面看成 Canvas,那么最后三角形就画在图中灰褐三角形的职位。

新萄京娱乐场.2959.com 6

上述调换是用矩阵来实行的。

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

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

新萄京娱乐场.2959.com 7

地方多个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。八个矩阵的值分别取决于:观察者的思想和视线距离,旁观者在世界中的状态(位置和样子),模型在世界中的状态(地方和可行性)。计算的结果是(0,一,壹,二),化成齐次坐标是(0,0.5,0.伍,一),就是以此点在CCV中的坐标,那么(0,0.五)就是在Canvas中的坐标(感到Canvas 大旨为原点,长度宽度都为二)。

地方出现的(0,0,壹,一)是(0,0,一)的齐次向量。齐次向量(x,y,z,w)可以代表三维向量(x,y,z)参加矩阵运算,通俗地说,w
分量为 一 时表示地方,w 分量为 0 时表示位移。

WebGL 未有提供其余有关上述调换的机制,开垦者须要亲自总结顶点的 CCV
坐标。

关于坐标转换的越来越多内容,能够参照:

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

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

至于绕率性轴旋转和四元数,可以参考:

  • 四元数@维基百科
  • 二个鬼子对肆元数公式的表达

至于齐次向量的越多内容,可以参见。

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

矩阵转换

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

只要有一个最简便易行的模型:三角形,多个终端分别为(-1,-1,0),(壹,-壹,0),(0,1,0)。这三个数据是从文件中读出来的,是三角形最初步的坐标(局地坐标)。如下图所示,右手坐标系。

新萄京娱乐场.2959.com 8

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

新萄京娱乐场.2959.com 9

绘图三维场景必须钦点2个观察者,假设观看者位于(0,0,壹)处而且看向三角形,那么八个终端相对于观望者的坐标为(-一,-1,-贰),(一,-1,-二),(0,一,-2),即视图坐标。

新萄京娱乐场.2959.com 10

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

新萄京娱乐场.2959.com 11

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

新萄京娱乐场.2959.com 12

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

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

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

新萄京娱乐场.2959.com 13

上边三个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。多少个矩阵的值分别取决于:观看者的观点和视线距离,观望者在世界中的状态(地点和取向),模型在世界中的状态(地点和自由化)。总括的结果是(0,一,壹,二),化成齐次坐标是(0,0.5,0.5,一),正是以此点在CCV中的坐标,那么(0,0.伍)便是在Canvas中的坐标(认为Canvas 宗旨为原点,长度宽度都为二)。

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

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

关于坐标转变的越来越多内容,能够参照:

  • 微型Computer图形学新萄京娱乐场.2959.com ,中的5-7章
  • 转移矩阵@维基百科
  • 透视投影详解

相比复杂的是模型转变中的绕放4轴旋转(日常用肆元数生成矩阵)和投影调换(上面包车型大巴例子都没收涉及到)。

有关绕放肆轴旋转和4元数,能够参考:

  • 肆元数@维基百科
  • 三个鬼子对4元数公式的辨证

至于齐次向量的越来越多内容,能够参考。

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

着色器和光栅化

在 WebGL
中,开垦者是由此着色器来成功上述转换的。着色器是运维在显卡中的程序,以
GLSL 语言编写,开采者须要将着色器的源码以字符串的格局传给 WebGL
上下文的相干函数。

着色器有二种,顶点着色器和片元(像素)着色器,它们成对出现。顶点着色器职务是抽取顶点的部分坐标,输出
CCV 坐标。CCV
坐标经过光栅化,转化为逐像素的数码,传给片元着色器。片元着色器的任务是明确各类片元的颜色。

顶点着色器接收的是 attribute 变量,是逐顶点的数码。顶点着色器输出
varying 变量,也是逐顶点的。逐顶点的 varying
变量数据通过光栅化,成为逐片元的 varying
变量数据,输入片元着色器,片元着色器输出的结果就会突显在 Canvas 上。

新萄京娱乐场.2959.com 14

着色器功效很多,上述只是基本功用。超过四分之二绚烂的功效都是依靠着色器的。借使您对着色器完全没有定义,能够试着明亮下1节
hello world 程序中的着色器再回首一下本节。

至于愈来愈多着色器的学问,能够参考:

  • GLSL@维基百科
  • WebGL@MSDN

着色器和光栅化

在 WebGL
中,开辟者是通过着色器来成功上述转变的。着色器是运作在显卡中的程序,以
GLSL 语言编写,开辟者供给将着色器的源码以字符串的款式传给 WebGL
上下文的连带函数。

着色器有三种,顶点着色器和片元(像素)着色器,它们成对出现。顶点着色器职分是抽出顶点的局地坐标,输出
CCV 坐标。CCV
坐标经过光栅化,转化为逐像素的数码,传给片元着色器。片元着色器的天职是规定每个片元的水彩。

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

新萄京娱乐场.2959.com 15

着色器功效繁多,上述只是基本功效。半数以上绚烂的法力都是依靠着色器的。假如您对着色器完全未有定义,能够试着明亮下一节
hello world 程序中的着色器再回首一下本节。

至于越来越多着色器的学识,能够参见:

  • GLSL@维基百科
  • WebGL@MSDN

程序

那1节解释绘制上述情景(三角形)的 WebGL
程序。点其一链接,查看源代码,试图通晓一下。那段代码出自WebGL
Programming
Guide,笔者作了部分改变以适应本文内容。若是一切平常,你见到的应该是底下这样:

新萄京娱乐场.2959.com 16

分解几点(如若从前不打听 WebGL ,多半会对上边包车型大巴代码质疑,无碍):

  1. 字符串 VSHADER_SOURCE 和 FSHADER_SOURAV4CE
    是极限着色器和片元着色器的源码。能够将着色器理解为有一定输入和出口格式的顺序。开辟者供给事先编写好着色器,再依照一定格式着色器发送绘图命令。
  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 对 象,(绘制每1帧时)通过切换 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. Part叁 向正在利用的着色器传入数据,包蕴逐顶点的 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.A奥迪Q7RAY_BUFFERAV四举办的。在 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
    和矩阵转变壹节中的模型矩阵(第 三 个)。
  2. 顶点着色器计算出的 gl_Position 正是 CCV
    中的坐标,比方最上面的顶点(黑褐)的 gl_Position
    化成齐次坐标就是(0,0.伍,0.5,一)。
  3. 向终点着色器传入的只是三个顶峰的颜料值,而三角形表面包车型大巴颜色渐变是由那多少个颜色值内插出的。光栅化不仅会对
    gl_Position 进行,还会对 varying 变量插值。
  4. gl.drawArrays()方法使得缓冲区进行绘图,gl.THighlanderIANGLES
    钦命绘制三角形,也得以退换参数绘制点、折线等等。

有关 ArrayBuffer 的详细消息,可以参照:

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

至于 gl.T景逸SUVIANGLES
等任何绘制格局,能够参见上边那张图或那篇博文。

新萄京娱乐场.2959.com 17

程序

那一节解释绘制上述场景(三角形)的 WebGL
程序。点其一链接,查看源代码,试图理解一下。那段代码出自WebGL
Programming
Guide,作者作了1部分修改以适应本文内容。如若一切符合规律,你看看的应该是上面那样:

新萄京娱乐场.2959.com 18

表达几点(如若在此之前不打听 WebGL ,多半会对上边的代码可疑,无碍):

  1. 字符串 VSHADER_SOURCE 和 FSHADER_SOU奥迪Q3CE
    是终点着色器和片元着色器的源码。能够将着色器掌握为有定位输入和输出格式的先后。开垦者需求事先编写好着色器,再依据一定格式着色器发送绘图命令。

  2. Part二 将着色器源码编写翻译为 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. Part叁 向正在利用的着色器传入数据,包含逐顶点的 attribute
    变量和大局的 uniform 变量。向着色器传入数据必须利用
    ArrayBuffer,而不是正规的 JS 数组。

    var varray = new Float32Array([-1, -1, 0, 1, -1, 0, 0, 1, 0])
    
  5. WebGL API 对 ArrayBuffer
    的操作(填充缓冲区,传入着色器,绘制等)都以经过 gl.A奥迪Q7RAY_BUFFELX570进行的。在 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
    和矩阵调换1节中的模型矩阵(第 叁 个)。

  7. 终端着色器总计出的 gl_Position 正是 CCV
    中的坐标,比如最上边的终极(墨绿)的 gl_Position
    化成齐次坐标正是(0,0.5,0.五,壹)。

  8. 向终极着色器传入的只是四个顶峰的水彩值,而三角形表面包车型大巴水彩渐变是由那多个颜色值内插出的。光栅化不仅会对
    gl_Position 举办,还会对 varying 变量插值。

  9. gl.drawArrays()方法使得缓冲区举办绘图,gl.T景逸SUVIANGLES
    钦点绘制三角形,也足以变动参数绘制点、折线等等。

有关 ArrayBuffer 的详细新闻,能够参考:

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

关于 gl.TEscortIANGLES
等别的绘制方式,能够参照下边那张图或那篇博文。

新萄京娱乐场.2959.com 19

纵深检查评定

当四个外表重叠时,后面包车型大巴模型会遮掩前面包车型大巴模型。比如这么些事例,绘制了五个交叉的三角形(
varray 和 carray 的长短变为 1八,gl.drawArrays 最终1个参数变为
6)。为了轻巧,那些事例去掉了矩阵转变进程,直接向着色器传入 CCV 坐标。

新萄京娱乐场.2959.com 20

新萄京娱乐场.2959.com 21

极限着色器给出了 6 个极端的 gl_Position ,经过光栅化,片元着色器获得了
二X 个片元(倘若 X 为各类三角形的像素个数),每一种片元都离散的 x,y
坐标值,还有 z 值。x,y 坐标便是三角形在 Canvas
上的坐标,但只要有五个颇具同等 x,y 坐标的片元同时出现,那么 WebGL
就会取 z 坐标值十分的小的卓殊片元。

在深度检查实验之前,必须在绘制前拉开3个常量。不然,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 坐标。

新萄京娱乐场.2959.com 22

新萄京娱乐场.2959.com 23

极限着色器给出了 陆 个极端的 gl_Position ,经过光栅化,片元着色器获得了
二X 个片元(假若 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()能够令着色器以1个索引数组为顺序绘制顶点。比方以此事例。

新萄京娱乐场.2959.com 24

那边画了五个三角,但只用了 多少个极端,有一个终极被多个三角共用。这时急需树立索引数组,数组的各样成分表示顶点的索引值。将数组填充至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()可以令着色器以三个索引数组为顺序绘制顶点。比方以此事例。

新萄京娱乐场.2959.com 25

此地画了多个三角形,但只用了 5个极端,有1个巅峰被五个三角共用。那时急需建立索引数组,数组的各种成分表示顶点的索引值。将数组填充至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);

发表评论

电子邮件地址不会被公开。 必填项已用*标注