最通俗的threejs原理介绍

5,288 阅读5分钟

threejs原理介绍

我在这篇文章threejs开发入门介绍中介绍了threejs开发入门,不过大部分人还是对实战更感兴趣,都希望能对着文章直接撸出一个3D的小项目出来。可以理解,毕竟对照着能做出来就相当于"会了"嘛!

webgl与opengl

不过,咱还是不着急!通过前面的文章中的小例子我们能了解threejs开发是怎么回事,体会下3D效果,不过在进入开发实战之前,我先讲下threejs原理。这有一张架构图:

简单一句话说就是,threejs是基于目前浏览器的3D图形渲染标准--webgl进行封装的3D库。webgl是一套与OpenGL ES 2.0 绑定的 API,而OpenGL ES 2.0是 OpenGL 三维图形 API 的子集,是针对手机、PDA和游戏主机等嵌入式设备而设计的API,OpenGL存在于Windows,部分UNIX平台和Mac OS。

WebGL与OpenGL的关系可以用这张图来理解:

OpenGL是一个C语言运行时函数库,它只规定函数执行规范及输出值,具体实现由openGL开发者根据硬件(pc、手机及嵌入式设备等)实现,而这些硬件设备实现通过OpenGL对外提供接口。在浏览器端,主要靠WebGL来调用OpenGL这套API。

总结下来就是,js是无法调用硬件能力的,所以需要通过webgl来调用opengl这套api。到这一步其实就可以实现前端的3D渲染了,只不过直接用WebGL来开发,会比较麻烦,比如我们需要自己开发着色器程序并编译传给GPU,而threejs这样的js框架就可以在你选择图形的材质后直接生成着色器,省了很多复杂工作。

对threejs这个框架来说,它的关键部分就是webgl,webgl的底层相当于是封装了能调用硬件GPU的加速渲染能力的OpenGL这个API库,上层就是基于webgl进行的再封装,再封装的可以是threejs,也可以是cesium,也可以是BabylonJS,这些都是webgl的js封装库。看下图,大部分浏览器都已经支持webgl。

canvas

上图中对webgl的描述是:3D canvas graphics,翻译过来就是--3D画布上的图形,也就是说所谓的3D效果,最终也是要在canvas这个画布上展现的。

在HTML5统一前端之前,前端的图形展示主要靠插件来实现,比较典型的有flash、silverlight。HTML5的canvas画布元素使得浏览器无需Flash或Silverlight等插件就能直接显示绚丽图形或动画图像。这里提到的Canvas是一个绘图元素,绘图2D图形时需要获取2d上下文,而WebGL就是基于Canvas的3d上下文实现的一个API,webgl目前在大部分浏览器上都是被支持的,所以没了各种插件,通过html5的canvas就可以在浏览器显示3D图形了。

在这里我多说一句,什么3D不3D的,其实就是2D,真正的3D只在现实世界中存在,其他的全是用2D图形来骗人的,你看的3D效果只是用2D成像来欺骗你的。就好比你看了场3D电影,那真是3D吗?并不是!那玩意就是在那一块电影布上面呈现的近乎3D的视觉效果,本质上仍然是一个2D影像(不过全息影像这种是奔着真正的3D呈现去实现的)而已。就好比这张图,给你的视觉效果,你能分辨出这是个房间,你甚至感觉能放个床进去,实际上它就是个2D图像,之所以看着有3D效果,是因为它满足3维坐标系的一些规律。

同样的,我们的浏览器本质上也是2D的,所以你看到的3D图像就是要在2D画布上呈现3D效果。你可以回忆下初中数学中画的那些立体几何图形,在脑海里想象一下立体的感觉是如何产生的过程。在浏览器中,canvas就是那你的作业本,我们知道canvas主要是用来做2d图形的,类似于echarts这种图形库,而它也可以呈现3D图形,道理是一样的,我们在纸上画立体有xyz三个坐标轴,那我们在浏览器的3D世界里同样也有xyz坐标轴。这个图就是threejs框架里的三维坐标体系,这个我在前面重点讲过,这里不再赘述,你需要时刻把这个坐标系印在脑海里。

canvas上下文

前面虽说我们看到的所谓3D图形其实也是2D图像,只不过借助了三维坐标系让我们"感觉"是3D的,事实就是这样的。不过,对于webgl来说,它借助canvas呈现时,使用的上下文是一不一样的。什么是canvas上下文?它最常用的有2D上下文和3D上下文。

这是获取2D上下文的代码:

var 2d=document.getElementById("2d");

//确定浏览器支持<canvas>元素
if(2d.getContext){
	var context=2d.getContext("2d");
	context.strokeStyle="red";
	context.fillStyle="#0000ff";
}

这是获取3D上下文的代码:

const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgl'); // 获取webgl上下文

我们再来看下threejs的部分源码,这是在render中的部分源码:

if ( _gl === null ) {
  const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
  if ( _this.isWebGL1Renderer === true ) {
    contextNames.shift();
  }
  _gl = getContext( contextNames, contextAttributes );
  if ( _gl === null ) {
    if ( getContext( contextNames ) ) {
      throw new Error( 'Error creating WebGL context with your selected attributes.' );
    } else {
      throw new Error( 'Error creating WebGL context.' );
    }
  }
}

由于webgl是有版本的,它这里其实就是遍历各个版本,看浏览器支持哪一个版本的webgl。

不管是2D上下文还是3D上下文,我们最终要在Canvas这块画布发挥,其中3D上下文一般就是WebGL,我们也可以用WebGL进行2D绘制,并且WebGL提供硬件渲染加速,性能更好。

好了,到这里,threejs原理讲得差不多了,不过也只是皮毛,概念之中的内核还是有很多值得深入学习的,光是webgl绘制过程就挺复杂的。大部分还是讲概念之间的关系,而threejs本身讲的比较少,还是那句话,threejs本身只是个js框架,跟canvas、webgl、opengl这些比起来要简单多了,看官网就足够了。