“哥,你又来啦?”
“是啊,我随便逛逛。”
“别介啊……给我20分钟,成不?”
“5分钟吧,我很忙的。”
“不行,20分钟,不然我真很难跟你讲清楚。”
“好吧……”
“行,那进来吧,咱好好聊聊”

一、我们讲什么?

我们讲两个东西:
1、WebGL背后的工作原理是什么?
2、以Three.js为例,讲述框架在背后扮演什么样的角色?

二、我们为什么要了解原理?

我们假定你对WebGL已经有一定了解,或者用Three.js做过了一些东西,这个时候,你可能碰到了这样一些问题:
1、很多东西还是做不出来,甚至没有任何思路;
2、碰到bug无法解决,甚至没有方向;
3、性能出现问题,完全不知道如何去优化。
这个时候,我们需要了解更多。

三、先了解一个基础概念

1、什么是矩阵?
简单说来,矩阵用于坐标变换,如下图:

2、那它具体是怎么变换的呢,如下图:

3、举个实例,将坐标平移2,如下图:

如果这时候,你还是没有理解,没有关系,你只需要知道,矩阵用于坐标变换。

四、WebGL的工作原理

4.1、WebGL API

在了解一门新技术前,我们都会先看看它的开发文档或者API。
查看Canvas的绘图API,我们会发现它能画直线、矩形、圆、弧线、贝塞尔曲线。
于是,我们看了看WebGL绘图API,发现:

它只能会点、线、三角形?一定是我看错了。
没有,你没看错。

就算是这样一个复杂的模型,也是一个个三角形画出来的。

4.2、WebGL绘制流程

简单说来,WebGL绘制过程包括以下三步:
1、获取顶点坐标
2、图元装配(即画出一个个三角形)
3、光栅化(生成片元,即一个个像素点)

接下来,我们分步讲解每个步骤。

4.2.1、获取顶点坐标

顶点坐标从何而来呢?一个立方体还好说,如果是一个机器人呢?
没错,我们不会一个一个写这些坐标。
往往它来自三维软件导出,或者是框架生成,如下图:

写入缓存区是啥?
没错,为了简化流程,之前我没有介绍。
由于顶点数据往往成千上万,在获取到顶点坐标后,我们通常会将它存储在显存,即缓存区内,方便GPU更快读取。

4.2.2、图元装配

我们已经知道,图元装配就是由顶点生成一个个图元(即三角形)。那这个过程是自动完成的吗?答案是并非完全如此。
为了使我们有更高的可控性,即自由控制顶点位置,WebGL把这个权力交给了我们,这就是可编程渲染管线(不用理解)。
WebGL需要我们先处理顶点,那怎么处理呢?我们先看下图:

我们引入了一个新的名词,叫“顶点着色器”,它由opengl es编写,由javascript以字符串的形式定义并传递给GPU生成。
比如如下就是一段顶点着色器代码:

attribute vec4 position;
void main() {
gl_Position = position;
}

attribute修饰符用于声明由浏览器(javascript)传输给顶点着色器的变量值;
position即我们定义的顶点坐标;
gl_Position是一个内建的传出变量。
这段代码什么也没做,如果是绘制2d图形,没问题,但如果是绘制3d图形,即传入的顶点坐标是一个三维坐标,我们则需要转换成屏幕坐标。
比如:v(-0.5, 0.0, 1.0)转换为p(0.2, -0.4),这个过程类似我们用相机拍照。

4.2.2.1、顶点着色器处理流程

回到刚才的话题,顶点着色器是如何处理顶点坐标的呢?

如上图,顶点着色器会先将坐标转换完毕,然后由GPU进行图元装配,有多少顶点,这段顶点着色器程序就运行了多少次。
你可能留意到,这时候顶点着色器变为:

attribute vec4 position;
uniform mat4 matrix;
void main() {
gl_Position = position * matrix;
}

这就是应用了矩阵matrix,将三维世界坐标转换成屏幕坐标,这个矩阵叫投影矩阵,由javascript传入,至于这个matrix怎么生成,我们暂且不讨论。

4.2.3、光栅化

和图元装配类似,光栅化也是可控的。

在图元生成完毕之后,我们需要给模型“上色”,而完成这部分工作的,则是运行在GPU的“片元着色器”来完成。
它同样是一段opengl es程序,模型看起来是什么质地(颜色、漫反射贴图等)、灯光等由片元着色器来计算。
如下是一段简单的片元着色器代码:

precision mediump float;
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

gl_FragColor即输出的颜色值。

4.2.3.1、片元着色器处理流程

片元着色器具体是如何控制颜色生成的呢?

如上图,顶点着色器是有多少顶点,运行了多少次,而片元着色器则是,生成多少片元(像素),运行多少次。

4.3、WebGL的完整工作流程

至此,实质上,WebGL经历了如下处理流程:
1、准备数据阶段
在这个阶段,我们需要提供顶点坐标、索引(三角形绘制顺序)、uv(决定贴图坐标)、法线(决定光照效果),以及各种矩阵(比如投影矩阵)。
其中顶点数据存储在缓存区(因为数量巨大),以修饰符attribute传递给顶点着色器;
矩阵则以修饰符uniform传递给顶点着色器。
2、生成顶点着色器
根据我们需要,由Javascript定义一段顶点着色器(opengl es)程序的字符串,生成并且编译成一段着色器程序传递给GPU。
3、图元装配
GPU根据顶点数量,挨个执行顶点着色器程序,生成顶点最终的坐标,完成坐标转换。
4、生成片元着色器
模型是什么颜色,看起来是什么质地,光照效果,阴影(流程较复杂,需要先渲染到纹理,可以先不关注),都在这个阶段处理。
5、光栅化
能过片元着色器,我们确定好了每个片元的颜色,以及根据深度缓存区判断哪些片元被挡住了,不需要渲染,最终将片元信息存储到颜色缓存区,最终完成整个渲染。

五、Three.js究竟做了什么?

我们知道,three.js帮我们完成了很多事情,但是它具体做了什么呢,他在整个流程中,扮演了什么角色呢?
我们先简单看一下,three.js参与的流程:

黄色和绿色部分,都是three.js参与的部分,其中黄色是javascript部分,绿色是opengl es部分。
我们发现,能做的,three.js基本上都帮我们做了。

  • 辅助我们导出了模型数据;
  • 自动生成了各种矩阵;
  • 生成了顶点着色器;
  • 辅助我们生成材质,配置灯光;
  • 根据我们设置的材质生成了片元着色器。

而且将webGL基于光栅化的2D API,封装成了我们人类能看懂的 3D API。

5.1、Three.js顶点处理流程

从WebGL工作原理的章节中,我们已经知道了顶点着色器会将三维世界坐标转换成屏幕坐标,但实际上,坐标转换不限于投影矩阵。
如下图:

之前WebGL在图元装配之后的结果,由于我们认为模型是固定在坐标原点,并且相机在x轴和y轴坐标都是0,其实正常的结果是这样的:

5.1.1、模型矩阵

现在,我们将模型顺时针旋转Math.PI/6,所有顶点位置肯定都变化了。

box.rotation.y = Math.PI/6;

但是,如果我们直接将顶点位置用javascript计算出来,那性能会很低(顶点通常成千上万),而且,这些数据也非常不利于维护。
所以,我们用矩阵modelMatrix将这个旋转信息记录下来。

5.1.2、视图矩阵

然后,我们将相机往上偏移30。

camera.position.y = 30;

同理,我们用矩阵viewMatrix将移动信息记录下来。

5.1.3、投影矩阵

这是我们之前介绍过的了,我们用projectMatrix记录。

5.1.4、应用矩阵

然后,我们编写顶点着色器:

gl_Position = position * modelMatrix * viewMatrix * projectionMatrix;

这样,我们就在GPU中,将最终顶点位置计算出来了。
实际上,上面所有步骤,three.js都帮我们完成了。

5.2、片元着色器处理流程

我们已经知道片元着色器负责处理材质、灯光等信息,但具体是怎么处理呢?
如下图:

5.3、three.js完整运行流程:

当我们选择材质后,three.js会根据我们所选的材质,选择对应的顶点着色器和片元着色器。
three.js中已经内置了我们常用着色器。

全文完。

图解WebGL&Three.js工作原理的更多相关文章

  1. WebGL&Three.js工作原理

    一.我们讲什么? 我们讲两个东西:1.WebGL背后的工作原理是什么?2.以Three.js为例,讲述框架在背后扮演什么样的角色? 二.我们为什么要了解原理? 我们假定你对WebGL已经有一定了解,或 ...

  2. require.js工作原理(初始)

    详情:请见阮一峰老师的日志:http://www.ruanyifeng.com/blog/2012/11/require_js.html: 导入:<script data-main=" ...

  3. 技术分享:JS工作原理

    一 浏览器组成可分两部分:Shell+内核. 浏览器内核又可以分成两部分:渲染引擎(layout engineer或者Rendering Engine)和JS引擎. 渲染引擎功能作用 渲染引擎,负责对 ...

  4. Ajax工作原理和原生JS的ajax封装

    前言: 之所以用ajax作为博客的开篇,是因为无论从ajax的出现还是从它的作用上来说,ajax对于前端无疑是意义重大的.甚至可以说,是ajax带来了前端这个行业.当然,历史并不能说明当下,曾经的辉煌 ...

  5. Node.js的require()的工作原理

    大多数人都知道Node.js中require()函数做什么的,但是有多少人知道它的工作原理呢?我们每天使用它加载库包和模块,但是它的内部行为原理很神秘. 我们追寻Node模块系统的核心: module ...

  6. js:我们应该如何去了解JavaScript引擎的工作原理(转)

    http://www.nowamagic.net/librarys/veda/detail/1579 昨天收到一封来自深圳的一位前端童鞋的邮件,邮件内容如下(很抱歉,未经过他的允许,公开邮件内容,不过 ...

  7. js中Ajax工作原理(转)

    在写这篇文章之前,曾经写过一篇关于AJAX技术的随笔,不过涉及到的方面很窄,对AJAX技术的背景.原理.优缺点等各个方面都很少涉及null.这次写这篇文章的背景是因为公司需要对内部程序员做一个培训.项 ...

  8. 深入理解JS中的对象(二):new 的工作原理

    目录 序言 不同返回值的构造函数 深入 new 调用函数原理 总结 参考 1.序言 在 深入理解JS中的对象(一):原型.原型链和构造函数 中,我们分析了JS中是否一切皆对象以及对象的原型.原型链和构 ...

  9. 深入理解JS中的对象(三):class 的工作原理

    目录 序言 class 是一个特殊的函数 class 的工作原理 class 继承的原型链关系 参考 1.序言 ECMAScript 2015(ES6) 中引入的 JavaScript 类实质上是 J ...

随机推荐

  1. 偶尔发生File has been moved - cannot be read again,其实是个误解

    使用poi上传.xlsx文件时,出现如下错误 Exception in thread "pool-3-thread-2" java.lang.IllegalStateExcepti ...

  2. Jmeter接口压力测试

    SOAP百科:Soap简单对象访问协议,是交换数据的一种协议规范,是一种轻量的.简单的.基于XML(标准通用标记语言下的一个子集)的协议,它被设计成在WEB上交换结构化的和固化的信息.webServi ...

  3. 重磅消息:微信小程序支持长按二维码进入

    之前微信小程序一般通过以下入口进入: 而用户经常使用“长按二维码”识别应用的功能一直未开放,据酷客多了解,微信安卓6.5.6内测版已经支持长按二维码识别和进入小程序,意味着把小程序二维码分享给朋友,或 ...

  4. ASP.NET Core MVC 源码学习:Routing 路由

    前言 最近打算抽时间看一下 ASP.NET Core MVC 的源码,特此把自己学习到的内容记录下来,也算是做个笔记吧. 路由作为 MVC 的基本部分,所以在学习 MVC 的其他源码之前还是先学习一下 ...

  5. Git的安装使用和基本命令(一)

    版本控制系统是每一个程序员的必备神器,我相信任何一个程序员都要用到版本控制系统,它的强大之处我就不作解释了,在这我将Git(分布式版本控制系统)的安装使用和基本的命令给初学者介绍一下(在linux系统 ...

  6. HTML 表单常用的代码元素

    表单: 将数据通过浏览器提交到服务器的媒介.<form action="" method="get/post" ></form> get ...

  7. 【Unity游戏开发】浅谈 NGUI 中的 UIRoot、UIPanel、UICamera 组件

    简介 马三最近换到了一家新的公司撸码,新的公司 UI 部分采用的是 NGUI 插件,而之前的公司用的一直是 Unity 自带的 UGUI,因此马三利用业余时间学习了一下 NGUI 插件的使用,并把知识 ...

  8. 部署在服务器中的WebService

    1.继上篇之后,我把我的WebService部署在了比较小的Tomcat中,首先要把Jax-ws.jar架包放在lib里面 2.在我的WEB-INF里面增加了一个xml文件:sun-jaxws.xml ...

  9. Java常量笔记

    在添加文件名的同时,文件名和内容可以不相同!! 1·Java 常量 常量就是固定不变的量,一旦被定义,它的值就不能被改变. 例实: 书中的代码不全,在这里不补充一下: 书中的源代码: public c ...

  10. 转载 webstrom识别 React语法

    对于程序员而言:驼峰和下划线之间是一场宗派战争:大括号是否换行会成为一种党派:逗号写在行尾还是行首的人来自不同星球-- 然而,无规矩不成方圆,任何一个团队,要想有高质量的产出,第一步必须要对一些基本的 ...