总要有人来改变世界的,为什么不能是你呢

通过three.js源码学习计算机图形学/webgl系列之camera、renderer、scene

无论你是在用three.js还是babylon.js还是其他B端三维引擎,你似乎都能经常见到标题所提到的如下三个概念:camera(相机)、renderer(渲染器)、scene(场景)

那么这三者究竟是通过怎样的方式将三维物体呈现在浏览器中的呢,今天我们就通过three.js的相关源码来一探究竟(默认你已经有了webgl的相关基础)

1.相机

通常我们使用的都是正交相机PerspectiveCamera

 

该相机构造函数四个参数共同决定了camera的视椎体

具体可百度透视投影

我们通常通过这样一句话来初始化正交相机:

    this.camera = new THREE.PerspectiveCamera( 70, dom.clientWidth / dom.clientHeight, 1, 1000 );

这句话到底做了什么呢?

除了给成员变量初始化值之外,最重要的就是更新该相机下的人物视角(视图矩阵)

蓝色框是结合setViewOffset方法来移动可视区中心点的(默认是上下左右居中)

最终,相机的构造函数通过提供的各种参数计算出了该相机的视图矩阵和视图矩阵的逆矩阵:

2.场景

其实不难看出Scene继承自Object3D对象,自然就有了Object3D对象的一些属性和方法(例如:add、remove...)

除此之外,通过上面的代码可以看出,scene对象还有额外的方法和属性(例如:toJSON、dispose、background(背景属性值类型的灵活性,大大方便了开发者))

这样就不难理解我们通常新建了一个three.js提供的基本图元之后,就通过

this.scene.add()

将其加入到场景中了。

3.渲染器

我们在这里一般都是使用webgl渲染器,所以这里也只讨论webgl渲染器

通常我们会结合指定的canvas容器来生成一个webgl渲染器(主要是尺寸):

    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setSize( dom.clientWidth, dom.clientHeight );
    dom.appendChild( this.renderer.domElement );

不难看出,webgl渲染器可以接受一个对象型的参数来实例化渲染器对象,如果没有提供canvas对象,会自动生成一个canvas对象供后续使用;

然后就是一系列的变量初始化(webgl上下文对象相关)以及webgl上下文的获取:

然后就是webgl上下文对象的初始化了

这里通过相关webgl的原生api获取了WEBGL的扩展,并且提炼了一些自定义工具方法并将其挂载在渲染器对象下(注意这里的一个rendererLists)。

再接下来是设置canvas视图尺寸:

注意,这里的_viewport是一个四维向量(x,y,z,w),上图括号里的一长串其实只是针对不同设备对该四维向量做了一个缩放而已。

最终执行的是

gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );

 

 

所以,针对canvas,左下角是(0,0),右上角是(width,height);

另外,查看WebGLState相关代码,不难看出,这个类产生的效果是用来作用于场景中所有的元素的,所以将其挂载在渲染器下,使得后续场景中所有物体都能轻易使用该效果

最后我们通常通过requestAnimationFrame(callback)来逐帧进行场景中元素的渲染,callback函数将会执行如下方法:

this.renderer.render(this.scene,this.camera);

进一步查看该方法:

 

首先在宏观的角度上,由于人为的将观察视角通过拖拽鼠标进行了改变,那么渲染器渲染的时候就需要将scene、camera的世界矩阵进行更新(后续将会提到各种矩阵是如何共同作用于物体的);

然后,通过相关api获取所有待渲染对象:

 

posted @ 2020-02-01 00:08  桔子桑  阅读(1310)  评论(0编辑  收藏  举报