three.js基礎前置知識

  • 2019 年 10 月 3 日
  • 筆記

這一節是純理論知識,用於介紹three.js的入門概念,也就是開發前需要準備的理論基礎。

 

一,三劍客

  當然就是scene,camera,renderer這三個基本要素。

  scene是一個用於容納三維空間的場景,相當於一個容器;

  camera則是一雙幫助我們觀察3d世界的眼睛;

  而renderer是一個渲染器,它負責把無色無相的三維物體繪製成肉眼可見的物體;

 

二,選什麼相機

  選透視相機(PerspectiveCamera)。

  簡單來說,透視相機有距離感,遠的物體看起來小一點,近的物體看起來大一點,符合現實生活中的人眼觀感;

  而正交投影相機沒有距離感,所有的物體看起來都是在一條直線上;

  

  (左為透視相機,右為正交投影相機)

 

三,如何生成一個基礎物體?

  基礎物體mesh = 幾何結構(geometry)+ 貼片材質(material)

  幾何結構就像一個骨架,three.js內置了不少幾何結構,像常見的球體,正方體,圓環等等;

  而貼片材質則決定這個骨架的樣式,可以畫上純色,也可以貼上圖片紋理等;

 

四,該選什麼材質?

  材質主要分為與光照沒有任何交集的基礎材質(MeshBasicMaterial),以及必須要光照才能看見,可以配合光照產生陰影效果的標準材質(MeshStandardMaterial);

  一般來說,全景圖的視角在物體內部,只觀察圖片紋理,不需要陰影效果,可選用基礎材質;

  而像3d物體,給物體打上平行光,顯現出物體的影子,可以讓畫面更真實,因此選用標準材質。但此時環境光要慎用,因為如果物體是純色材質,視覺上環境光會和物體混色。如:在標準材質下:黃色環境光+藍色材質物體 = 視覺上物體呈綠色;

 

五,初始化透視相機的參數如何設置?

  var camera = new PerspectiveCamera(fov, aspect, near, far)幫助我們初始化一個相機,參數依次為:視野,可觀測距離比,最近觀測距離,最遠觀測距離。

  如果你和我一樣沒什麼圖形學基礎,不太懂透視,可以使用一個通用的參數設定:

  var camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 1000);

 

六,相機該看哪兒?

  默認情況下,相機處於空間直角坐標系的原點;

  一般的做法是,通過相機的position屬性把它擺放到三維空間的某個位置;

  再通過lookAt屬性設置一下相機該看向哪裡,一般看向物體的正中心(new THREE.Vector3(0, 0, 0));

 

七,如何實現實時渲染(循環渲染)?

  結合requestAnimationFrame獲得一個合適的幀率,然後遞歸調用渲染器的render方法就行了,requestAnimationFrame本質上就是一個非同步延時函數。

  程式碼如下所示:

function animate() {      renderer.render(scene, camera);      requestAnimationFrame(animate);  }  

  

八,圖片紋理默認貼在幾何體外部,如何讓其貼在幾何體內壁?

  一般做法是將幾何體的scale屬性的某一個坐標設為負值就行了,如:

geometry.scale(- 1, 1, 1);  

  

九,自由拖動查看全景圖,該怎麼搞?

  這裡的大體思路是這樣的:根據拖動事件計算出一個新的經緯度,然後通過某種換算公式將新的經緯度換算為三維空間坐標(x,y,z),然後camera看向這個三維坐標。

  換言之,就是camera被安裝在球體內部的球心,然後探頭可以轉來轉去,查看球體內壁的不同區域。

  關於經緯度轉三維坐標,如果你並不想去過多了解這個轉換函數的具體意義,也可以直接使用,程式碼如下:

  

function transCoord(sphereRadius,lon,lat) { // 參數分別表示球體的半徑,經度,緯度    			lat = Math.max(-85, Math.min(85, lat));  			let phi = THREE.Math.degToRad(90 - lat);  			let theta = THREE.Math.degToRad(lon);    			camera.target.x = sphereRadius * Math.sin(phi) * Math.cos(theta);  			camera.target.y = sphereRadius * Math.cos(phi);  			camera.target.z = sphereRadius * Math.sin(phi) * Math.sin(theta);    			camera.lookAt(camera.target);  		}  

 

十,自由拖動查看3d物體,該怎麼弄?

  與全景圖相對應,3d物體拖動查看也是很常見的東西;

  它的大體思路可能是這樣的:

  (1)先把相機安裝在物體外部的某一個點,然後相機探頭固定看著物體中心,當我們拖動物體時,實際上就是在令物體圍著自身的中心點做各種旋轉,相機在外部一動不動,“靜靜地看著物體裝逼”;

  (2)然後相機探頭固定看著物體中心,當我們進行拖動時,3d物體不懂,相機在物體外圍的空間“飛來飛去”;

  如果你不想考慮這麼多坐標換算的東西,不想搞這麼多數學,也可以當個api的調用者,three.js官方提供了OrbitControls,用來定於用戶對物體的旋轉查看行為,其使用十分簡單。

  

十一,滑鼠縮放如何比較科學地解決?

  滑鼠縮放畫面,其實就是在縮放透視相機的視野(fov);

  視野越大,則表示看到的範圍越大,離物體也就越遠;

  視野越小,則表示看到的範圍很小,說明離物體很近,有“一葉障目”之感;

  明白了這一點,我們就可以通過調用內置api來實現這個縮放的功能,內置的api封裝了很多細節,也簡化了我們的運算,程式碼如下:

function mouseWheelHandler(event) {    			let fov = camera.fov + event.deltaY * 0.05;    			camera.fov = THREE.Math.clamp(fov, 10, 75); // 後兩個參數表示最小視野,最大視野,也就是縮放範圍    			camera.updateProjectionMatrix();    		}  

  

  以上就是three.js一些比較入門的理論知識,下一節我們將從一個實際頁面出發,動手完成一個可交互的簡單3d物體。