前言:
專案需求,兩周內(nèi)架設(shè)能展示一3D模型的網(wǎng)頁。當(dāng)時我只會React,所幸能藉此機會順便學(xué)習(xí)Three.js。
今天就從頭來看看如何在網(wǎng)頁放上3D模型並播放動畫吧。
Three.js
簡單來說Three.js就是能用來渲染3D物件的Js庫
渲染方塊
渲染出一個物件,首先需要有展示的舞臺(Scene)、觀察的相機(Camera)和渲染器(Renderer)
定義基本場景、渲染器、相機
變動視窗
由於Render的size一開始就固定了,所要隨著視窗大小變動須掛載window resize事件。
Mesh
一個Mesh是由幾何形狀和材質(zhì)組成的,這裡使用預(yù)設(shè)的幾何和材質(zhì)產(chǎn)生出Cube的Mesh,並加入場景中:
關(guān)於requestAnimationFrame可以看之前的文章
在React內(nèi)使用Three.js
不建議在React內(nèi)直接使用Three.js。由於React的刷新機制,會導(dǎo)致Three.js不斷重新建立與渲染,重複產(chǎn)生很多個Scene物件。
這邊是一個解決重複產(chǎn)生Scene物件的做法:在useEffect產(chǎn)生場景,避免React重複生成scene。
簡單說明useRef跟useState的差別,useState的物件更新時會觸發(fā)重新刷新整個頁面,而useRef不會。但此作法canvas也會因為其他物件觸發(fā)更新導(dǎo)致重新渲染。
Three-Fiber
官方寫的很清楚:React-three-fiber is a React renderer for three.js.
(fiber是React 16以後的新架構(gòu))
官網(wǎng)對於效能是這麼形容的: 元件的renderLoop是置於React本生的渲染管線之外,基於React排程能力,它可能更勝three.js一籌。
但它推薦先對React和原生Three.js有基本了解,個人使用心得也是先了解Three.js比較好,react-three有滿多api不好找的,直接用直覺從three.js轉(zhuǎn)JSX語法可能比較快。
範(fàn)例
使用貼圖
在react-three中,three物件的建構(gòu)子參數(shù)大多使用args,例如<boxBufferGeometry attach="geometry" args={[3, 3, 3]} /> 的 args分別為方塊多邊形的width、height、depth數(shù)值。
先使用Loader載入貼圖,為材質(zhì)的map。
載入gltf
甚麼是gltf?
簡單說gltf是為了讓模型載入更快、更輕的儲存格式,由於網(wǎng)頁需要載入模型盡可能輕便,才不會影響瀏覽,所以常應(yīng)用在3D網(wǎng)頁上。
FBX轉(zhuǎn)gltf
如果模型師能輸出正確的gltf格式那當(dāng)然好不過,不過有時當(dāng)你只有fbx時,可透過以下作法將模型轉(zhuǎn)gltf:
轉(zhuǎn)出react可用模型 (使用cmd)
之後會得到兩包資料,.gltf檔案 ? 丟專案public資料夾 ;.js檔案 ? 丟專案src資料夾
使用方法:
*模型物件外層都建議放<Suspense>,防出錯。
使用FBX模型
當(dāng)初剛學(xué)react-fiber,別看程式碼短短的,可是費了我好大的心力跟時間才測出解答。
未上市專案用到的模型,就模糊遮一下吧><
這裡用到fbx.traverse( function ( child )... 去loop過所有child,找到是mesh的物件,才設(shè)定正確的材質(zhì)給它。但是,用此方法只會剩下該Mesh物件,能正確渲染模型跟貼圖,但動畫之類的資訊就會被捨棄掉了。
使用:
播放動畫
注意:FBX的skinnedMesh只能有一個,不然會出錯。
當(dāng)已知mesh只有一個,這裡就不用traverse去loop了。上一個範(fàn)例會那樣做是因為物件mesh不只一個時,為了找出並渲染所有mesh而做的 (不然只會渲染第一個)。
一起學(xué)習(xí)