無論你是在用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 );
不難看出,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獲取所有待渲染對象: