three.js基礎(chǔ)結(jié)構(gòu)
目錄
一個three.js項目至少需要的東西有——
[ ] scene:場景
[ ] camera:攝像機(jī)
[ ] render:渲染器
[ ] light:燈光
可能需要的有——
[ ] controls:攝像機(jī)控制器
[ ] raycaster:點擊射線,用于點擊事件
[ ] loader:加載器,特殊的物體例如模型需要使用加載器,而且不同格式的模型需要不同的加載器
[ ] object:場景內(nèi)的物體對象
場景
在three.js中,場景是作為最外層容器存在的,它相當(dāng)于html中的window對象,所有three.js中的對象,都可以在scene中找到。
它作為three.js的載體,是一個可自定義的三維模擬空間,定義方式如下(改代碼使用MVC結(jié)構(gòu))——
initScene: function() {
// 聲明場景
appModel.threeSceneObject.scene = new THREE.Scene();
// 可選擇,是否啟動霧化效果,參數(shù)1是霧的顏色,參數(shù)2,3是霧化起始距離和最遠(yuǎn)距離,是以場景的坐標(biāo)點(0,0,0)為起始點。
appModel.threeSceneObject.scene.fog = new THREE.Fog(0xffffff, 200, 1300);
}
攝像機(jī)
攝像機(jī),或者說它是視角,同一個場景上,不同的視角看到的內(nèi)容自然會不一樣。視角和場景不一樣,不僅僅是需要定義,還需要在渲染器`render`中,進(jìn)行進(jìn)一步的設(shè)定,這里先不講,只要知道這個攝像機(jī)的“攝像功能”需要被不停的執(zhí)行,才能讓三維的場景看起來動作流暢。
這個很好理解——攝像機(jī)照出來的是照片,是靜止的。但是我們看到的是場景,里面的內(nèi)容是可以動的,那么這要如何實現(xiàn)?自然是參考動畫的制作——連續(xù)切換的靜止圖片組成一個動圖。
攝像機(jī)的初始化方式如下:
// 初始化攝像機(jī)
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
// 設(shè)置攝像機(jī)位置
camera.position.set(cameraPosition.x, cameraPosition.y, cameraPosition.z);
攝像機(jī)的伙伴,control控制器
攝像機(jī)也是一個物體,一個對象,但是一般的攝像機(jī)只能設(shè)置一些靜態(tài)屬性,如位置,朝向等等參數(shù)。但是,使用control插件,我們就可以動態(tài)的操控攝像機(jī),如:
OrbitControls:軌道控制器,以中心點(可自定義其他的點)為圓心,左右拉動場景可以使攝像機(jī)圍繞著這個中心點旋轉(zhuǎn),旋轉(zhuǎn)半徑在初始化的時候設(shè)定。
FlyControls:飛行控制器,第一人稱視角控制器,一版的PFS射擊游戲視角,可以使用asdw進(jìn)行前后左右操控移動。
燈光
場景中燈光也是必要的,沒有光,場景中的任何東西就處于“看不見”狀態(tài),就像站在在一片大地上,卻沒有太陽,理所當(dāng)然看到的是一片漆黑。
燈光有三種光源,平行光,點光源,聚光燈光源。
平行光類似于太陽光,點光源類似于燈泡,聚光燈如其名是個聚光燈。三種光源的效果差距在于渲染物體時物體表面上的光的范圍。如果物體正對于太陽光,那么它對著平行光的面上每一個部分接收到的“陽光”都是一樣的。而點光源在同樣情況下,光在投射到物體表面的中心點處最強(qiáng),然后逐漸衰弱。聚光燈則處于兩者之間,在某一個照射范圍內(nèi),內(nèi)部的光可以看成是平行光,而超過這個范圍,則完全看不到。
大部分情況下,點光源和平行光并沒有明顯的區(qū)別,不過在使用另一個系統(tǒng)——影子之后,差距就會出來了。太陽光下的影子和點光源下的影子差距還是挺大的。
燈光的初始化如下:
// 點光源
var light2 = new THREE.PointLight(0xFFFFFF);
light2.position.set(6, 6, 24);
scene.add(light2);
// 平行光
var sun1 = new THREE.DirectionalLight(0xffffff);
sun1.position.set(-1000, 500, -1000);
//sun1.castShadow = true;
appModel.threeSceneObject.scene.add(sun1);
可以看到,兩者的初始化的方式幾乎一摸一樣。陽光的渲染原理其實很簡單:將陽光的顏色和物體的顏色進(jìn)行融合,同時顯示面對陽光的對象的部分內(nèi)容。所以將上述代碼的光色改成紅色,就會發(fā)現(xiàn)物體也會被染色。
陽光照射不到的部分會顯示黑色。
渲染器
渲染器的核心方法只有一句:
render.render(scene, camera);
這句話會使得整個場景的內(nèi)容刷新一次,所以這個方法需要放在requestAnimationFrame中不停地執(zhí)行。
條用渲染器的render方法會刷新內(nèi)容,這個內(nèi)容可以是某個物體的位置移動,翻轉(zhuǎn),變形,例如攝像機(jī),單純的物體,也可以是隨著時間而執(zhí)行的某種代碼,如添加倒計時,時間一到便刪除某個物體。
<strong>可以說,three中所有動態(tài)活動,不管是場景視角的移動,還是物體的屬性變動,其代碼都會在這里執(zhí)行。</strong>
最基礎(chǔ)的render方法如下:
render: function() {
render.render(scene, camera);
requestAnimationFrame(appController.render);
},
<strong> 第一行是一個render方法,所有的動態(tài)代碼將寫在這個方法中</strong>
<strong>第二行有兩個render,第一個render是render渲染器,第二個是渲染器內(nèi)部的方法,所以這三行的render的意義其實都不一樣。這個render傳入的是當(dāng)前的場景對象和攝像機(jī)對象,通過他們three會計算出當(dāng)前場景的"截圖"</strong>
<strong>第三行使用requestAnimationFrame方法,瘋狂調(diào)用render方法自身,即第一行的render,達(dá)到不停的截圖,串成一個動畫的效果</strong>
而render自身的初始化方法是:
// new 一個render對象
render = new THREE.WebGLRenderer({
antialias: true
});
// 設(shè)置render分辨率
render.setPixelRatio(window.devicePixelRatio);
// 設(shè)置render渲染范圍大小
render.setSize(window.innerWidth, window.innerHeight);
// 將整個three場景轉(zhuǎn)成canvas,放到id為container的div中。
document.getElementById('container').appendChild(render.domElement);
// 設(shè)置場景的渲染顏色和透明度
render.setClearColor(0xFFFFFF, 1.0);
<strong>這一段代碼優(yōu)先級非常高,使用three的時候,請將其第一個初始化。</strong>