自制React-three-fiber
??Threejs101
代碼1 設(shè)置了舞臺(tái),創(chuàng)建了三個(gè)基本組件:renderer, scene, camera
代碼2 往場(chǎng)景中增加物體,將根節(jié)點(diǎn)加到dom里
代碼3 定義renderLoop
通過(guò)上面的代碼,可以創(chuàng)建出一個(gè)幾何體
??擁抱React
Canvas組件
為了在React中使用Threejs,可以創(chuàng)建一個(gè)Canvas組件,代碼如下:
組件中只封裝了canvas,在hook中定義了設(shè)置舞臺(tái)的代碼,定義了renderLoop,并且開啟了render loop,現(xiàn)在要在頁(yè)面中顯示出物體,只差一步:創(chuàng)建物體,往場(chǎng)景中添加。
如何往場(chǎng)景(scene)里添加物體
選項(xiàng)1: ?Javascript方式
直接就在hook里創(chuàng)建幾何體,創(chuàng)建材質(zhì),再創(chuàng)建mesh,然后直接加到scene里
這樣子的話,其實(shí)React只是一層皮,實(shí)際的Threejs完全就是當(dāng)作普通JS代碼在寫
選項(xiàng)2: React jsx
這里需要知道的一個(gè)點(diǎn)是scene作為整個(gè)場(chǎng)景的根節(jié)點(diǎn),其他所有的mesh都是往這里加,而每個(gè)mesh也可以有自己的child,整個(gè)場(chǎng)景是一個(gè)樹狀。我們要做的就是往樹的根節(jié)點(diǎn)加節(jié)點(diǎn),使用JS的方式就是我們顯示創(chuàng)建,自己給加進(jìn)去。而React創(chuàng)建dom樹是通過(guò)聲明式構(gòu)建出的,所以也可以通過(guò)jsx聲明式的方式創(chuàng)建mesh,讓react幫我們構(gòu)建場(chǎng)景樹。
我們期望可以用下面方式創(chuàng)建場(chǎng)景
在Canvas組件內(nèi)部通過(guò)jsx定義mesh,構(gòu)建mesh的geometry,material通過(guò)props指定,然后React會(huì)自動(dòng)給我創(chuàng)建mesh加到scene里。
自定義Renderer
React是如何創(chuàng)建dom的
React是由ReactDOM負(fù)責(zé)根據(jù)虛擬dom創(chuàng)建dom,并且加到根節(jié)點(diǎn)的,所以我們也需要一個(gè)類似的render函數(shù)
這個(gè)render函數(shù)類似ReactDOM的render函數(shù),接收虛擬dom和場(chǎng)景根節(jié)點(diǎn),然后幫我們創(chuàng)建mesh,加到scene里。
仿照ReactDOM寫個(gè)render函數(shù)
創(chuàng)建一個(gè)renderer,render函數(shù)中通過(guò)renderer調(diào)用updateContainer去更新,我們需要實(shí)現(xiàn)傳入Renconciler的參數(shù)。
填充Reconciler參數(shù)
拷貝十幾個(gè)函數(shù),我們關(guān)心的只有幾個(gè):createInstance,appendChild, appendChildToContainer, appendInitialChild,finalizeInitialChildren,因?yàn)橹恍鑼?shí)現(xiàn)這幾個(gè)就可以完成渲染,而我只想明白為什么可以通過(guò)React渲染3D物體,不關(guān)心更新卸載等問(wèn)題,所以其他函數(shù)不實(shí)現(xiàn)了。
createInstance函數(shù):根據(jù)虛擬dom創(chuàng)建實(shí)例的方法,通過(guò)它可以創(chuàng)建自定義的標(biāo)簽節(jié)點(diǎn),這里就是從Threejs里找到標(biāo)簽對(duì)應(yīng)的類生成并返回。
finalizeInitialChildren:可以在這里做屬性賦值的工作,也可以在createInstance直接就完成。
appendChild:將子節(jié)點(diǎn)加到父節(jié)點(diǎn)中,構(gòu)建樹狀的方法
appendInitialChild:和上面那個(gè)一樣,將子節(jié)點(diǎn)加到父節(jié)點(diǎn)(暫不清楚為什么要分兩個(gè)方法)
appendChildToContainer:加到根節(jié)點(diǎn)中的方法
效果:
https://codesandbox.io/s/elastic-wood-ux0mkj?file=/src/App.js
免責(zé)聲明
本篇文章完全是個(gè)人出于好奇,想了解為什么React-three-fiber可以用React語(yǔ)法寫threejs應(yīng)用,因此著重點(diǎn)在實(shí)現(xiàn)渲染的基本思路,對(duì)于更新卸載等都未關(guān)注。另外,使用到的react-reconciler也是老版本,對(duì)其api也未深入探索。