菜单

js55金沙娱乐WebGL 技术储备指南

2019年3月16日 - 金沙前端

WebGL技术储备指南

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

初稿出处: Tmall前端团队(FED)-
叶斋   

澳门金沙app 1

WebGL 是 HTML 5 草案的一部分,能够使得 Canvas 渲染三维场景。WebGL
即便还未有广泛应用,但极具潜力和想象空间。本文是本人上学 WebGL
时梳理知识系统的产物,花点时间整理出来与大家分享。

WebGL 是 HTML 5 草案的一片段,能够使得 Canvas 渲染三维场景。WebGL
纵然还未有广泛应用,但极具潜力和设想空间。本文是自个儿学习 WebGL
时梳理知识系统的产物,花点时间整理出来与大家大快朵颐。

WebGL 是 HTML 5 草案的一局地,可以使得 Canvas 渲染三维场景。WebGL
尽管还未有广泛应用,但极具潜力和想象空间。本文是本人读书 WebGL
时梳理知识系统的产物,花点时间整理出来与大家大饱眼福。

着色器只好用在OpenGLES 2.X上述等可编制程序管道里,而在OpenGLES
1.X是不能够选拔的。

示例

WebGL 很酷,有以下 demos 为证:

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

示例

WebGL 很酷,有以下 demos 为证:

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

示例

管线,Pipeline,显卡执行的、从几何体到最后渲染图像的、数据传输处理总计的进度

正文的对象

本文的意料读者是:不熟悉图形学,熟知前端,希望驾驭或系统学习 WebGL
的同窗。

本文不是 WebGL 的概述性文章,也不是欧洲经济共同体详细的 WebGL
教程。本文只愿意变成一篇供 WebGL 初学者使用的纲要。

本文的对象

正文的预想读者是:不熟悉图形学,明白前端,希望了解或系统学习 WebGL
的同学。

正文不是 WebGL 的概述性文章,也不是全部详细的 WebGL
教程。本文只愿意变成一篇供 WebGL 初学者使用的纲要。

WebGL 很酷,有以下 demos 为证:

OpenGLES1.X中它是稳定管道,全体式封闭的,中间的各道工艺按一定的流水生产线顺序走。如图所示:

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 的越来越多文化,能够参考:

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

唯独接下去,假使想画3个矩形的话,就没那样简单了。实际上,Canvas
是浏览器封装好的1个绘制环境,在实际上海展览中心开绘图操作时,浏览器依然要求调用
OpenGL API。而 WebGL API 差不离正是 OpenGL API 未经封装,直接套了一层壳。

Canvas 的愈多学问,可以参照:

探寻奥兹国

澳门金沙app 2

矩阵变换

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

假设有2个最简便的模子:三角形,多个极端分别为(-1,-1,0),(1,-1,0),(0,1,0)。那多少个数据是从文件中读出来的,是三角形最开始的坐标(局地坐标)。如下图所示,右手坐标系。

澳门金沙app 3

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

澳门金沙app 4

绘图三维场景必须钦赐多个观望者,假如阅览者位于(0,0,1)处而且看向三角形,那么多个极点相对于观望者的坐标为(-1,-1,-2),(1,-1,-2),(0,1,-2),即视图坐标。

澳门金沙app 5

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

澳门金沙app 6

将四棱台体映射为专业立方(CCV,宗旨为原点,边长为2,边与坐标轴平行)。顶点在
CCV 中的坐标,离它最终在 Canvas 中的坐标已经很接近了,假使把 CCV
的前表面看成 Canvas,那么最后三角形就画在图中宝蓝三角形的地点。

澳门金沙app 7

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

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

以(0,1,0)为例,它的齐次向量为(0,0,1,1),上述变换的代表经过可以是:

澳门金沙app 8

地方多个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。四个矩阵的值分别取决于:观看者的理念和视野距离,观看者在世界中的状态(地方和自由化),模型在世界中的状态(地点和趋势)。总括的结果是(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
坐标。

有关坐标变换的越多内容,能够参考:

相比较复杂的是模型变换中的绕任意轴旋转(平日用四元数生成矩阵)和投影变换(下面的例证都没收涉及到)。

至于绕任意轴旋转和四元数,能够参见:

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

矩阵变换

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

一旦有一个最简易的模型:三角形,四个极点分别为(-1,-1,0),(1,-1,0),(0,1,0)。那八个数据是从文件中读出来的,是三角形最初始的坐标(局地坐标)。如下图所示,右手坐标系。

澳门金沙app 9

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

澳门金沙app 10

绘制三维场景必须钦点一个观察者,假若阅览者位于(0,0,1)处而且看向三角形,那么三个顶峰相对于观察者的坐标为(-1,-1,-2),(1,-1,-2),(0,1,-2),即视图坐标。

澳门金沙app 11

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

澳门金沙app 12

将四棱台体映射为规范立方(CCV,中心为原点,边长为2,边与坐标轴平行)。顶点在
CCV 中的坐标,离它最终在 Canvas 中的坐标已经很接近了,如若把 CCV
的前表面看成 Canvas,那么最后三角形就画在图中法国红三角形的职位。

澳门金沙app 13

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

有的坐标 –(模型变换)-> 世界坐标 –(视图变换)-> 视图坐标
–(投影变换)–> CCV 坐标。

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

澳门金沙app 14

上面三个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。八个矩阵的值分别取决于:观察者的意见和视野距离,旁观者在世界中的状态(地点和样子),模型在世界中的状态(地方和可行性)。计算的结果是(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
坐标。

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

比较复杂的是模型变换中的绕任意轴旋转(平时用四元数生成矩阵)和投影变换(下面的例证都没收涉及到)。

至于绕任意轴旋转和四元数,能够参见:

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

超跑游戏

从上海体育场合能够观察,那个工艺顺序是定点的,整个经过又分为:处理顶点,处理片元,验证片元新闻并存入内部存款和储蓄器

着色器和光栅化

在 WebGL
中,开发者是透过着色器来成功上述变换的。着色器是运作在显卡中的程序,以
GLSL 语言编写,开发者须要将着色器的源码以字符串的款型传给 WebGL
上下文的连锁函数。

着色器有二种,顶点着色器和片元(像素)着色器,它们成对出现。顶点着色器职责是接受顶点的一些坐标,输出
CCV 坐标。CCV
坐标经过光栅化,转化为逐像素的多少,传给片元着色器。片元着色器的职务是鲜明每个片元的颜料。

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

澳门金沙app 15

着色器功用很多,上述只是基本成效。当先三分之一炫酷的作用都以凭借着色器的。假诺您对着色器完全没有定义,能够试着明亮下一节
hello world 程序中的着色器再回首一下本节。

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

着色器和光栅化

在 WebGL
中,开发者是由此着色器来形成上述变换的。着色器是运转在显卡中的程序,以
GLSL 语言编写,开发者需求将着色器的源码以字符串的方式传给 WebGL
上下文的有关函数。

着色器有二种,顶点着色器和片元(像素)着色器,它们成对现身。顶点着色器职务是收到顶点的片段坐标,输出
CCV 坐标。CCV
坐标经过光栅化,转化为逐像素的数量,传给片元着色器。片元着色器的天职是规定每一个片元的水彩。

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

澳门金沙app 16

着色器效用很多,上述只是基本效能。领先四分之二炫酷的效益都以依靠着色器的。要是您对着色器完全没有概念,可以试着明亮下一节
hello world 程序中的着色器再回看一下本节。

关于更加多着色器的学识,能够参照:

泛舟的男孩(Goo
EngineDemo)

Rasterizer:光栅化处理,当顶点处理完,会付出rasterizer来展开光栅化处理,结果会吧顶点的坐标消息转换来能在荧屏彰显的像素新闻,即片元(Fragments)

程序

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

澳门金沙app 17

解释几点(假如以前不领会 WebGL ,多半会对上面的代码疑忌,无碍):

  1. 字符串 VSHADER_SOURCE 和 FSHADER_SOUENCORECE
    是极限着色器和片元着色器的源码。能够将着色器精通为有一定输入和输出格式的程序。开发者供给事先编写好着色器,再依照一定格式着色器发送绘图命令。
  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.AENCORERAY_BUFFE牧马人进行的。在 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.TPRADOIANGLES
    钦命绘制三角形,也得以变更参数绘制点、折线等等。

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

有关 gl.T宝马X5IANGLES
等别的绘制方式,能够参考上面那张图或那篇博文。

澳门金沙app 18

程序

这一节解释绘制上述现象(三角形)的 WebGL
程序。点其一链接,查看源代码,试图领会一下。那段代码出自WebGL
Programming
Guide,小编作了一部分改动以适应本文内容。若是一切符合规律,你见到的应该是上面那样:

澳门金沙app 19

表明几点(假若在此之前不打听 WebGL ,多半会对下边包车型大巴代码质疑,无碍):

  1. 字符串 VSHADER_SOURCE 和 FSHADER_SOUCRUISERCE
    是终极着色器和片元着色器的源码。能够将着色器掌握为有定点输入和出口格式的先后。开发者须要事先编写好着色器,再根据一定格式着色器发送绘图命令。

  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_BUFFEKoleos实行的。在 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.TQashqaiIANGLES
    钦赐绘制三角形,也足以变动参数绘制点、折线等等。

至于 ArrayBuffer 的详细信息,能够参考:

有关 gl.T奥迪Q3IANGLES
等别的绘制情势,能够参考上面那张图或那篇博文。

澳门金沙app 20

正文的对象

生成片元后,接下去正是对fragments片元的各类申明,即过滤掉无用的片元,裁剪掉不在视野内的片元,最终把有效片元存款和储蓄入内部存储器中。

深度检查和测试

当八个外表重叠时,前边的模子会遮掩前边的模型。比如以此例子,绘制了五个交叉的三角形(
varray 和 carray 的长度变为 18,gl.drawArrays 最后3个参数变为
6)。为了简单,那一个事例去掉了矩阵变换进程,直接向着色器传入 CCV 坐标。

澳门金沙app 21

澳门金沙app 22

极端着色器给出了 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 坐标。

澳门金沙app 23

澳门金沙app 24

顶点着色器给出了 6 个极点的 gl_Position ,经过光栅化,片元着色器获得了
2X 个片元(假如 X 为各样三角形的像素个数),每种片元都离散的 x,y
坐标值,还有 z 值。x,y 坐标正是三角形在 Canvas
上的坐标,但假若有多少个有着同样 x,y 坐标的片元同时出现,那么 WebGL
就会取 z 坐标值较小的10分片元。

在深度检测从前,必须在绘制前拉开1个常量。否则,WebGL 就会依照在 varray
中定义的顺序绘制了,前面包车型客车会覆盖前边的。

gl.enable(gl.DEPTH_TEST);

实则,WebGL 的逻辑是如此的:依次拍卖片元,假使渲染缓冲区(那里就是Canvas
了)的不胜与当下片元对应的像素还尚未绘制时,就把片元的水彩画到渲染缓冲区对应像素里,同时把片元的
z
值缓存在另一个深度缓冲区的等同地方;假使当前缓冲区的相应像素已经绘制过了,就去查看深度缓冲区中对应地点的
z 值,假使当前片元 z 值小,就重绘,不然就遗弃当前片元。

WebGL 的这套逻辑,对领会蒙版(前边会说到)有一对声援。

本文的料想读者是:面生图形学,熟知前端,希望精晓或类别学习 WebGL
的同窗。

光栅化处理进度,就是把矢量图转化成像素点的历程。大家显示器上海展览中心示的镜头都是由像素结合,而三维物体都以点线面构成的。要让点线面变成能在显示屏上显示的像素,就供给Rasterizer这几个历程。

顶点索引

gl.drawArrays()是遵守顶点的顺序绘制的,而
gl.drawElements()能够令着色器以3个索引数组为顺序绘制顶点。比如其一事例。

澳门金沙app 25

此处画了八个三角,但只用了 5个极端,有3个极限被四个三角形共用。那时急需树立索引数组,数组的各类成分表示顶点的索引值。将数组填充至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()能够令着色器以一个索引数组为顺序绘制顶点。比如以此事例。

澳门金沙app 26

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

本文不是 WebGL 的概述性小说,也不是一体化详细的 WebGL
教程。本文只愿意成为一篇供 WebGL 初学者使用的纲要。

OpenGLES2.X可编制程序管道,由两VertexShader(顶点着色器)、FragmentsShader(片元着色器)组成,分别对应上图中的Coordinates
和Texture等灰白块

纹理

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

attribute
变量还足以支持绘制纹理。绘制纹理的基本原理是,为各类终端钦命1个纹理坐标(在(0,0)与(1,1,)的纺锤形中),然后传入纹理对象。片元着色器获得的是对应片元的内插后的纹路坐标,就利用那些纹理坐标去纹理对象上取颜色,再画到片元上。内插后的纹路坐标极大概不凑巧对应纹理上的某部像素,而是在多少个像素之间(因为一般的图片纹理也是离散),那时或者会由此周围多少个像素的加权平均算出该像素的值(具体有若干种差别方法,能够参见)。

比如其一例子。

澳门金沙app 27

纹理对象和缓冲区目的很接近:使用 gl 的 API 函数创立,供给绑定至常量
gl.AENCORERAY_BUFFER 和 gl.TEXTURE_2D
,都通过常量对象向当中填入图像和数目。差异的是,纹理对象在绑定时还亟需激活2个纹理单元(此处的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,)的四方形中),然后传入纹理对象。片元着色器获得的是对应片元的内插后的纹路坐标,就采取那几个纹理坐标去纹理对象上取颜色,再画到片元上。内插后的纹路坐标很大概不正好对应纹理上的某部像素,而是在多少个像素之间(因为普通的图形纹理也是离散),那时恐怕会经过周围多少个像素的加权平均算出该像素的值(具体有几各类不一致方法,能够参见)。

比如本条例子。

澳门金沙app 28

纹理对象和缓冲区指标很接近:使用 gl 的 API 函数创设,必要绑定至常量
gl.A奥德赛RAY_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);
};

Canvas

OpenGLES2.0可渲染管道图:

错落与蒙版

透明效果是用混合机制形成的。混合机制与深度检查和测试类似,也发生在打算向有些已填写的像素填充颜色时。深度检查和测试通过比较z值来规定像素的水彩,而掺杂机制会将两种颜色混合。比如其一例子。

澳门金沙app 29

混合的顺序是遵循绘制的相继实行的,假如绘制的相继有变化,混合的结果常常也不比。借使模型既有非透明表面又有晶莹剔透表面,绘制透明表面时打开蒙版,其目标是锁定深度缓冲区,因为半晶莹剔透物体后边的物体还可以观看的,要是不这么做,半晶莹剔透物体后边的实体将会被深度检查和测试机制排除。

敞开混合的代码如下。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值来明确像素的水彩,而掺杂机制会将三种颜色混合。比如那几个事例。

澳门金沙app 30

混合的次第是比照绘制的顺序进行的,若是绘制的相继有浮动,混合的结果经常也分歧。假设模型既有非透明表面又有晶莹剔透表面,绘制透明表面时打开蒙版,其指标是锁定深度缓冲区,因为半晶莹剔透物体后边的实体依旧得以看来的,借使不那样做,半透明物体前面包车型客车实体将会被深度检查和测试机制排除。

打开混合的代码如下。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
  ]);

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

澳门金沙app 31

浏览器的WebGL系统

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

澳门金沙app 32

那张图相比较轻易,箭头上的文字表示
API,箭头方向差不多表现了数据的流淌方向,不必深究。

浏览器的WebGL系统

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

澳门金沙app 33

那张图相比自由,箭头上的文字表示
API,箭头方向差不多表现了数据的流淌方向,不必深究。

var context = canvas.getContext(‘2d’);

VertexShader:顶点着色器

光照

WebGL 没有为光照提供别的内置的情势,需求开发者在着色器中落实光照算法。

只可是有颜色的,模型也是有颜色的。在光照下,最后物体显示的颜料是两者一起效能的结果。

达成光照的情势是:将光照的多少(点光源的职位,平行光的来头,以及光的颜色和强度)作为
uniform 变量传入着色器中,将物体表面各个顶点处的法线作为 attribute
变量传入着色器,服从光照规则,修订最后片元展现的颜色。

光照又分为逐顶点的和逐片元的,两者的区分是,将法线光线交角因素位居顶点着色器初级中学毕业生升学考试虑可能放在片元着色器中考虑。逐片元光照更是有声有色,三个极其的事例是:

澳门金沙app 34

此刻,点光源在相距1个表面较近处,表面大旨 A
处较亮,四周较暗。可是在逐顶点光照下,表面包车型客车水彩(的震慑因子)是由顶点内插出来的,所以表面中央也会相比较暗。而逐片元光照间接利用片元的地点和法线总结与点光源的交角,由此表面中心会比较亮。

光照

WebGL 没有为光照提供任何内置的法门,必要开发者在着色器中贯彻光照算法。

只不过有颜色的,模型也是有颜色的。在光照下,最后物体显示的颜料是互相联手功效的结果。

达成光照的法门是:将光照的数码(点光源的任务,平行光的趋向,以及光的水彩和强度)作为
uniform 变量传入着色器中,将物体表面每一个顶点处的法线作为 attribute
变量传入着色器,遵从光照规则,修订最后片元显示的水彩。

光照又分为逐顶点的和逐片元的,两者的区分是,将法线光线交角因素位居顶点着色器初级中学结业生升学考试虑照旧放在片元着色器初级中学结束学业生升学考试虑。逐片元光照更是绘声绘色,二个无比的例子是:

澳门金沙app 35

澳门金沙app,那时候,点光源在离开1个外部较近处,表面宗旨 A
处较亮,四周较暗。可是在逐顶点光照下,表面包车型大巴颜色(的熏陶因子)是由顶点内插出来的,所以表面中心也会比较暗。而逐片元光照间接使用片元的岗位和法线总结与点光源的交角,由此表面中心会比较亮。

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

极限着色器输入包罗:

复杂模型

复杂模型恐怕有包蕴子模型,子模型也许与父模型有相对运动。比如开着雨刮器的小车,雨刮器的世界坐标是受父模型小车,和小编的状态共同决定的。若要计算雨刮器某顶点的任务,要求用雨刮器相对小车的模型矩阵乘北京汽车工业集团总公司车的模型矩阵,再乘以顶点的某个坐标。

复杂模型可能有很多外表,恐怕每一种表面使用的着色器就不一致。平常将模型拆解为组,使用相同着色器的表面为一组,先绘制同一组中的内容,然后切换着色器。每一趟切换着色器都要双重将缓冲区中的数据分配给着色器中相应变量。

复杂模型

复杂模型可能有包罗子模型,子模型只怕与父模型有相对运动。比如开着雨刮器的小车,雨刮器的世界坐标是受父模型小车,和自己的情状共同决定的。若要总括雨刮器某顶点的任务,供给用雨刮器相对小车的模型矩阵乘北小车的模子矩阵,再乘以顶点的有个别坐标。

复杂模型只怕有那些外表,或然各样表面使用的着色器就分化。平日将模型拆解为组,使用相同着色器的表面为一组,先绘制同一组中的内容,然后切换着色器。每一趟切换着色器都要双重将缓冲区中的数据分配给着色器中相应变量。

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

着色器程序——描述顶点上实施操作的终极着色器程序源代码可能可执行文件

动画

动画的原理就是急迅地擦除和重绘。常用的措施是有名的
requestAnimationFrame
。不熟悉的同窗,可以参照正美的牵线。

动画

动画片的规律便是便捷地擦除和重绘。常用的点子是响当当的
requestAnimationFrame
。不熟练的同窗,能够参考正美的介绍js55金沙娱乐,。

context.fillRect(0, 0, 50, 50);

顶点着色器输入(或性质)——用极端数组提供的每一个终端的数据

WebGL库

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

WebGL库

近年来最流行的 WebGL 库是
ThreeJS,很强劲,官网,代码。

WebGL 同样供给取得绘图上下文:

联合变量(uniform)——顶点(或部分)着色器使用的不变多少

调剂工具

相比较成熟的 WebGL 调节和测试工具是WebGL
Inspector。

调剂工具

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

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

采集样品器——代表顶点着色器使用纹理的 特殊统一变量类型

互联网财富和书籍

英文的关于 WebGL 的能源有过多,包蕴:

境内最早的 WebGL 教程是由郝稼力翻译的,放在 hiwebgl 上,如今 hiwebgl
已经关闭,但教程还足以在这里找到。郝稼力如今营业着Lao3D。

境内曾经出版的 WebGL 书籍有:

终极再混合一点私货吧。读书时期笔者曾花了小7个月岁月翻译了一本WebGL的书,也正是地点的第2本。那本书真的十分可相信,网上各样学科里很多没说清楚的东西,这本书说得很清楚,而且还提供了一份很完整的API文书档案。翻译那本书的进程也使自个儿收益匪浅。假如有同学愿意系统学一下
WebGL
的,建议购买一本(文青提议买英文版)。

1 赞 2 收藏 1
评论

澳门金沙app 36

互连网财富和书本

英文的有关 WebGL 的财富有不少,包蕴:

国内最早的 WebGL 教程是由郝稼力翻译的,放在 hiwebgl 上,如今 hiwebgl
已经倒闭,但教程还能在这里找到。郝稼力近来运转着Lao3D。

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

而是接下去,要是想画五个矩形的话,就没这么简单了。实际上,Canvas
是浏览器封装好的2个制图环境,在骨子里开展绘图操作时,浏览器依旧需求调用
OpenGL API。而 WebGL API 大致正是 OpenGL API 未经封装,间接套了一层壳。

终点着色器的出口在OpenGLES2.0称作可变变量(varying),但在OpenGLES3.0中改名为巅峰着色器输出变量。

Canvas 的越来越多知识,能够参见:

在光栅化阶段,为各样生成的部分总计顶点着色器输出值,并视作输入传递给一部分着色器。

JS
权威指南的
21.4 节或JS
高级程序设计中的
15 章

插值:光栅器对从终端着色器传递的变量举行插值

W3CSchool

为了在显示器上实在呈现,必须将顶点着色器vs的输出变量设置为gl_Position,gl_Position是多个保留着顶点齐次坐标的4维向量。ZYZ分量被W分量分割(称作视角分割)并且XYZ分量上跨越单位化盒子([-1,
1])的局地会被裁剪掉。最后的结果会被更换成显示屏坐标系然后三角形(或别的图元类型)被光栅器生成对应的像素。

阮一峰的 Canvas
教程

OpenGLES3.0新增了三个作用——变换反馈,使顶点着色器输出能够选拔性地写入3个输出缓冲区(除了传递给一些着色器之外,也可用那种传递替代)

矩阵变换

终极着色器的输入和出口如下图所示:

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

澳门金沙app 37

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

先看看剧本:

澳门金沙app 38

private final String mVertexShader =

模型平时不会放在场景的原点,即便三角形的原点位于(0,0,-1)处,没有转动或缩放,四个终端分别为(-1,-1,-1),(1,-1,-1),(0,1,-1),即世界坐标。

“uniform mat4 uMVPMatrix;\n” +

澳门金沙app 39

“attribute vec4 aPosition;\n” +

绘制三维场景必须钦赐一个观看者,若是观看者位于(0,0,1)处而且看向三角形,那么多个顶峰相对于旁观者的坐标为(-1,-1,-2),(1,-1,-2),(0,1,-2),即视图坐标。

“attribute vec4 a_color;\n” +

澳门金沙app 40

“attribute vec2 aTextureCoord;\n” +

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

“varying vec2 vTextureCoord;\n” +

澳门金沙app 41

“out vec4 v_color;\n”

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

“void main() {\n” +

澳门金沙app 42

” gl_Position = uMVPMatrix * aPosition;\n” +

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

” vTextureCoord = aTextureCoord;\n” +

某个坐标 –(模型变换)-> 世界坐标 –(视图变换)-> 视图坐标
–(投影变换)–> CCV 坐标。

“ v_color = a_color;\n”

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

“}\n”;

澳门金沙app 43

private final String mFragmentShader =

地点多个矩阵依次是看破投影矩阵,视图矩阵,模型矩阵。四个矩阵的值分别取决于:阅览者的见地和视野距离,观看者在世界中的状态(地方和方向),模型在世界中的状态(地方和大势)。总结的结果是(0,1,1,2),化成齐次坐标是(0,0.5,0.5,1),就是那个点在CCV中的坐标,那么(0,0.5)正是在Canvas中的坐标(认为
Canvas 大旨为原点,长宽都为2)。

“precision mediump float;\n” +

地点现身的(0,0,1,1)是(0,0,1)的齐次向量。齐次向量(x,y,z,w)可以象征三维向量(x,y,z)参加矩阵运算,通俗地说,w
分量为 1 时表示地点,w 分量为 0 时表示位移。

“varying vec2 vTextureCoord;\n” +

WebGL 没有提供别的关于上述变换的体制,开发者必要亲自计算顶点的 CCV
坐标。

“uniform sampler2D sTexture;\n” +

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

“void main() {\n” +

微型总结机图形学中的5-7章

“gl_FragColor = texture2D(sTexture, vTextureCoord);\n” +

转移矩阵@维基百科

“}\n”;

透视投影详解

当中脚本语句关键字:

相关文章

发表评论

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

网站地图xml地图