WebGL技巧储备指南

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

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

365bet 1

WebGL 是 HTML 5 草案的生龙活虎局地,能够使得 Canvas 渲染三个维度场景。WebGL 即便尚未广泛应用,但极具潜质和虚构空间。本文是本人上学 WebGL 时梳理知识系统的付加物,花点时间整理出来与我们享用。

示例

WebGL 很酷,有以下 demos 为证:

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

正文的指标

本文的预想读者是:不熟谙图形学,纯熟前端,希望明白或系统学习 WebGL 的同班。

正文不是 WebGL 的概述性文章,亦非风度翩翩体化详细的 WebGL 教程。本文只盼望产生一篇供 WebGL 初读书人使用的总纲。

Canvas

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

JavaScript

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

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

context上调用各样函数绘制图形,比方:

JavaScript

// 绘制左上角为(0,0卡塔尔(英语:State of Qatar),右下角为(50, 50卡塔尔(英语:State of Qatar)的矩形 context.fillRect(0, 0, 50, 50卡塔尔(英语:State of Qatar);

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 章
  • 365bet,W3CSchool
  • 阮大器晚成峰的 Canvas 教程

矩阵转变

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

即便有叁个最轻便易行的模子:三角形,八个终端分别为(-1,-1,0卡塔尔国,(1,-1,0卡塔尔(英语:State of Qatar),(0,1,0卡塔尔国。那多个数据是从文件中读出来的,是三角形最起始的坐标(局地坐标卡塔尔(英语:State of Qatar)。如下图所示,右边手坐标系。

365bet 2

模型常常不会放在场景的原点,倘若三角形的原点坐落于(0,0,-1卡塔尔(قطر‎处,未有转动或缩放,三个终端分别为(-1,-1,-1卡塔尔(英语:State of Qatar),(1,-1,-1卡塔尔国,(0,1,-1卡塔尔(قطر‎,即世界坐标。

365bet 3

绘制三个维度场景必得钦定两个观望者,假若观望者坐落于(0,0,1卡塔尔(قطر‎处况且看向三角形,那么八个终端相对于观察者的坐标为(-1,-1,-2卡塔尔,(1,-1,-2卡塔尔,(0,1,-2卡塔尔国,即视图坐标。

365bet 4

观望者的眸子是四个点(那是看破投影的前提卡塔尔国,水平视角和垂直视角都以90度,视界范围(目力所及卡塔尔(英语:State of Qatar)为[0,2]365bet官网,在Z轴上,观望者能够看出的区域是一个四棱台体。

365bet 5

将四棱台体映射为正规立方(CCV,主题为原点,边长为2,边与坐标轴平行卡塔尔国。顶点在 CCV 中的坐标,离它最后在 Canvas 中的坐标已经超近似了,要是把 CCV 的前表面看成 Canvas,那么最后三角形就画在图中藕荷色三角形的职位。

365bet 6

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

局地坐标 –(模型转换卡塔尔(英语:State of Qatar)-> 世界坐标 –(视图转换卡塔尔(英语:State of Qatar)-> 视图坐标 –(投影转变卡塔尔–> CCV 坐标。

以(0,1,0卡塔尔(قطر‎为例,它的齐次向量为(0,0,1,1卡塔尔(英语:State of Qatar),上述调换的象征经过能够是:

365bet 7

位置八个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。四个矩阵的值分别决定于:观看者的见解和视界间距,观看者在世界中的状态(地点和趋向卡塔尔,模型在世界中的状态(地方和动向卡塔尔(قطر‎。计算的结果是(0,1,1,2卡塔尔(英语:State of Qatar),化成齐次坐标是(0,0.5,0.5,1卡塔尔(英语:State of Qatar),正是以此点在CCV中的坐标,那么(0,0.5卡塔尔(قطر‎正是在Canvas中的坐标(以为Canvas 中央为原点,长度宽度都为2卡塔尔。

上面现身的(0,0,1,1卡塔尔(قطر‎是(0,0,1卡塔尔的齐次向量。齐次向量(x,y,z,w卡塔尔(英语:State of Qatar)能够表示三个维度向量(x,y,z卡塔尔参预矩阵运算,通俗地说,w 分量为 1 时表示地方,w 分量为 0 时表示位移。

WebGL 未有提供其余关于上述转换的建制,开采者供给亲自总计极点的 CCV 坐标。

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

  • 微型机图形学中的5-7章
  • 退换矩阵@维基百科
  • 透视投影详整

相比较复杂的是模型调换中的绕任意轴旋转(常常用四元数生成矩阵卡塔尔(英语:State of Qatar)和投影转换(上面的事例都没收涉及到卡塔尔(英语:State of Qatar)。

关于绕任性轴旋转和四元数,可以参照:

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

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

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

着色器和光栅化

在 WebGL 中,开拓者是因而着色器来形成上述转变的。着色器是运维在显卡中的程序,以 GLSL 语言编写,开荒者需求将着色器的源码以字符串的花样传给 WebGL 上下文的有关函数。

着色器有二种,极点着色器和片元(像素卡塔尔(英语:State of Qatar)着色器,它们成对现身。极点着色器职责是抽出极点的片段坐标,输出 CCV 坐标。CCV 坐标经过光栅化,转变为逐像素的数目,传给片元着色器。片元着色器的天职是规定每一种片元的水彩。

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

365bet 8

着色器作用非常多,上述只是基本作用。超越六分之三光彩夺目的意义都是信任着色器的。如若您对着色器完全没有定义,能够试着明亮下大器晚成节 hello world 程序中的着色器再回顾一下本节。

有关越来越多着色器的知识,能够参谋:

  • GLSL@维基百科
  • WebGL@MSDN

程序

那风流倜傥节解释绘制上述现象(三角形卡塔尔(قطر‎的 WebGL 程序。点本条链接,查看源代码,试图明白一下。这段代码出自WebGL Programming Guide,小编作了有些退换以适应本文内容。假设一切符合规律,你看来的相应是底下那样:

365bet 9

分解几点(假使以前不打听 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.A福睿斯RAY_BUFFECRUISER进行的。在 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 中的坐标,比方最上边的极端(米黄卡塔尔(英语:State of Qatar)的 gl_Position 化成齐次坐标正是(0,0.5,0.5,1)。
  3. 向终极着色器传入的只是多个终端的颜料值,而三角形表面包车型大巴颜色渐变是由那三个颜色值内插出的。光栅化不独有会对 gl_Position 举行,还也许会对 varying 变量插值。
  4. gl.drawArrays(卡塔尔方法使得缓冲区举办绘图,gl.TENVISIONIANGLES 钦定绘制三角形,也能够更改参数绘制点、折线等等。

关于 ArrayBuffer 的详细音讯,能够参见:

  • ArrayBuffer@MDN
  • 阮后生可畏峰的 ArrayBuffer 介绍
  • 张鑫旭的 ArrayBuffer 介绍

有关 gl.TKoleosIANGLES 等其余绘制情势,能够参照上边那张图或这篇博文。

365bet 10

深度检查实验

当四个外表重叠时,前面包车型地铁模子会隐讳前边的模型。举例这么些事例,绘制了多少个交叉的三角形( varray 和 carray 的长度变为 18,gl.drawArrays 最终一个参数变为 6卡塔尔(قطر‎。为了轻便,这一个事例去掉了矩阵调换进程,直接向着色器传入 CCV 坐标。

365bet 11

365bet 12

终端着色器给出了 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 了卡塔尔(英语:State of Qatar)的非常与日前片元对应的像素还并未有绘制时,就把片元的颜色画到渲染缓冲区对应像素里,同有的时候间把片元的 z 值缓存在另三个深度缓冲区的相像地方;要是当前缓冲区的相应像素已经绘制过了,就去查看深度缓冲区中对应地点的 z 值,假如当前片元 z 值小,就重绘,不然就遗弃当前片元。

WebGL 的那套逻辑,对驾驭蒙版(前边会聊到卡塔尔国有部分声援。

极点索引

gl.drawArrays(卡塔尔国是比照极点的各类绘制的,而 gl.drawElements(卡塔尔(قطر‎可以令着色器以贰个索引数组为顺序绘制极点。举个例子其一事例。

365bet 13

此地画了八个三角,但只用了 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);

纹理

attribute 变量不仅可以够传递顶点的坐标,还足以传递别的任何逐极点的数量。比方HelloTriangle 程序把单个极点的水彩传入了 a_Color,片元着色器收到 v_Color 后一向赋给 gl_FragmentColor,就控制了颜色。

attribute 变量还足以扶持绘制纹理。绘制纹理的基本原理是,为种种终端钦定叁个纹理坐标(在(0,0卡塔尔(قطر‎与(1,1,卡塔尔国的方框形中卡塔尔国,然后传入纹理对象。片元着色器得到的是对应片元的内插后的纹理坐标,就动用那一个纹理坐标去纹理对象上取颜色,再画到片元上。内插后的纹理坐标很大概不适逢其时对应纹理上的有个别像素,而是在多少个像素之间(因为平日来说的图纸纹理也是离散卡塔尔(英语:State of Qatar),当时大概会经过附近多少个像素的加权平均算出该像素的值(具体有好两种分裂措施,能够参照他事他说加以考查卡塔尔国。

比如本条例子。

365bet 14

纹理对象和缓冲区指标很周围:使用 gl 的 API 函数成立,必要绑定至常量 gl.A讴歌ZDXRAY_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);
};

错落与蒙版

透明效果是用混合机制形成的。混合机制与深度质量评定相近,也发出在计算向某些已填写的像素填充颜色时。深度检查实验通过相比较z值来规定像素的水彩,而掺杂机制会将三种颜色混合。譬如本条例子。

365bet 15

混合的豆蔻梢头一是安份守己绘制的大器晚成大器晚成进行的,借使绘制的各样有变化,混合的结果平时也比不上。假设模型既有非透明表面又有透明表面,绘制透明表面时打开蒙版,其指标是锁定深度缓冲区,因为半透明物体后边的物体依旧得以见见的,假若不这么做,半晶莹剔透物体前面包车型客车物体将会被深度检查评定机制消除。

开启混合的代码如下。gl.blendFunc主意内定了混合的方式,这里的意趣是,使用源(待混合卡塔尔(英语:State of Qatar)颜色的 α 值乘以源颜色,加上 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
  ]);

浏览器的WebGL系统

WebGL 系统依次组成都部队分在既定法规下互匹协作。稍作梳理如下。

365bet 16

这张图相比随意,箭头上的文字表示 API,箭头方向差十分的少展现了数码的流淌方向,不必搜求。

光照

WebGL 未有为光照提供任何内置的法子,要求开垦者在着色器中落到实处光照算法。

只不过有颜色的,模型也会有颜色的。在光照下,最后物体展现的水彩是互相一齐功用的结果。

贯彻光照的法子是:将光照的数码(点光源的职位,平行光的大方向,以致光的颜料和强度卡塔尔国作为 uniform 变量传入着色器中,将物体表面各类极点处的法线作为 attribute 变量传入着色器,遵守光照准绳,修定最后片元展现的颜料。

光照又分为逐极点的和逐片元的,两个的分裂是,将法线光线交角因素位居极点着色器初级中学毕业生升学考试虑依旧放在片元着色器初级中学结业生升学考试虑。逐片元光照更是绘身绘色,三个无限的例证是:

365bet 17

那时,点光源在相距七个表面较近处,表面宗旨 A 处较亮,四周较暗。不过在逐极点光照下,表面的水彩(的震慑因子卡塔尔国是由极点内插出来的,所以表面大旨也会比较暗。而逐片元光照直接利用片元的任务和法线总括与点光源的交角,因此表面中心会比较亮。

复杂模型

复杂模型也有满含子模型,子模型恐怕与父模型有绝对运动。比如开着雨刮器的小车,雨刮器的世界坐标是受父模型小车,和自家的情景协同决定的。若要总计雨刮器某极点的职分,需求用雨刮器相对小车的模型矩阵乘SAIC车的模子矩阵,再乘以极点的风姿罗曼蒂克部分坐标。

复杂模型大概有过多外表,也许各个表面使用的着色器就分化。常常将模型拆解为组,使用同一着色器的表面为风华正茂组,先绘制同风流倜傥组中的内容,然后切换着色器。每趟切换着色器都要双重将缓冲区中的数据分配给着色器中相应变量。

动画

动漫片的规律正是高速地擦除和重绘。常用的方法是著名的 requestAnimationFrame 。素不相识的同学,能够参见正美的牵线。

WebGL库

此时此刻最盛行的 WebGL 库是 ThreeJS,很有力,官网,代码。

调整工具

正如早熟的 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 评论

365bet 18