# 使用Three.js做一個React互動3D選單 ## **<font color=#BC2B86>歷史演進</font>** ![](https://i.imgur.com/l4eGQ3I.png) ``` OpenGL 能以少量努力來繪製有吸引力的、真實的3D圖像。 WebGL 讓網頁基於 OpenGL ES 2.0,在 canvas 元素中實現2D及3D渲染。 canvas 標籤只是圖形容器,必須使用JavaScript來替換圖形。 ``` ## <font color=#BC2B86>安裝套件</font> <font size=5 color="#5585A2">**Threejs**</font> npm install --save three <font color="#DCDCDC">可以匯入3d max模型,複雜圖形通常也是用匯入的</font> <font size=5 color="#5585A2">**React-three-fiber(R3F)** </font> npm i three react-three-fiber <font color="#DCDCDC"> 為了能在React裡面用 Hook 編寫,React-three-fiber 是封裝threejs的語法糖庫,並沒有改變threejs的本質,threejs對象不是DOM,React的虛擬DOM對threejs沒有用,錯誤的更新和生成threejs對象可能會造成嚴重的性能問題</font> https://www.smashingmagazine.com/2020/11/threejs-react-three-fiber/ <font size=5 color="#5585A2">**Drei**</font> npm install @react-three/drei <font color="#DCDCDC">React-three-fiber的好幫手</font> <font size=5 color="#5585A2">**react-spring** </font> npm install react-spring <font color="#DCDCDC">模擬自然動態行為(比方彈簧)的動畫庫,滿足大多數與UI相關的動畫需求。 可和R3F良好的搭配</font> https://ithelp.ithome.com.tw/articles/10247210 https://gore.wang/blog/UX/react-spring/v9/?fbclid=IwAR1iaa6gwuCWrFgmGH9I2ZnMkOlYxh8ElAczyp4uQ-fdKhGlofBuq71IBXk <font size=5 color=gray> **lottie-web**</font> 先不用但預備在腦海 https://github.com/airbnb/lottie-web <font color="#DCDCDC">以JSON格式導出的Adobe After Effects動畫</font> ## <font color=#BC2B86>基礎繪製</font> <font size=5 color="#5585A2"> **step 1. 創建畫布**</font> ![](https://i.imgur.com/c1oCuxG.png) <font color="#DCDCDC">這邊的 <Canvas> 跟 HTML裡面的 Canvas 不同,是R3F封裝過後的</font> <font size=5 color="#5585A2"> **step 2. 加入圖型**</font> ![](https://i.imgur.com/KgxShu9.png) <font color="#DCDCDC">以圓球為例,attach是必須屬性,args調整圖形的大小和面數,meshStandardMaterial處理材質,所以可以在這邊設定顏色</font> <font size=5 color="#5585A2"> **step 3. 加入轉動**</font> ![](https://i.imgur.com/INyeJaX.png) <font color="#DCDCDC"> 1. 引用useRef獲得mesh的參考</br> 2. 引用useFrame,必須使用在自己的componenet </font> <font size=5 color="#5585A2"> **step 4. 加入燈光**</font> ![](https://i.imgur.com/bVqEMTH.png) <font color="#DCDCDC"> ambientLight 環境光 全局照明 數值不要太高 </font> <font size=5 color="#5585A2"> **step 5. 相機位置**</font> ![](https://i.imgur.com/rWQMNfa.png) <font color="#DCDCDC"> fov 是視角,決定zoom in zoom out </font> <font size=5 color="#5585A2"> **step 6. 製作陰影**</font> ![](https://i.imgur.com/Sdp1Fss.png) <font color="#DCDCDC"> 1. 加入兩個 pointLight 點光源 作為補光</br> 2. 加入一個 directionLight 方向燈 是主要燈光來源</br> 3. 加入投射陰影的地平面 材質要使用<shadowMaterial></br> 4. canvas、球狀 mesh、directionLight 加入castShadow屬性</br> 5. 地平面 mesh 加入 receieveShadow屬性</br> 6. 柔化陰影 從 Drei 引入 Softshadows</br> </font> ![](https://i.imgur.com/GPB9Dei.png) <font size=5 color="#5585A2"> **step7. 視角控制**</font> <font color="#000"> 1. import { OrbitControls } from '@react-three/drei';</br> 2. </Canvas>裡面底部最下方加入<OrbitControls /></br> </font> <font size=5 color="#5585A2"> **step8. 點擊放大**</font> <font color="#000"> 1. import { useSpring, a } from "react-spring/three";</br> <font color="#DCDCDC"> 這邊的a是animation的意思</br> </font> ![](https://i.imgur.com/7RjVckK.png) 2. 設定useState控制expand參數</br> 3. 使用useSpring控制放大多少</br> 4. 球體mesh設定onClick事件,並給scale屬性和值 5. mesh必須設為a.mesh,才能作用 </font> <font size=4 color="#9A1D15">目前為止,可以有一個動態旋轉有陰影的圓球 ## <font color=#BC2B86>其他功能</font> <font size=5 color="#5585A2"> **point 1. Three.js文件**</font> https://threejs.org/docs/index.html#api/en/materials/MeshBasicMaterial <font size=5 color="#5585A2"> **point 2. GUI**</font> <font size=5 color="#5585A2"> **point 3. Loders**</font> <font size=5 color="#5585A2"> **point 4. 聲音**</font> <font size=5 color="#5585A2"> **point 5. Post Processing and GLSL**</font> <font size=5 color="#5585A2"> **point 6. Canon-自然物理互動**</font> <font size=5 color="#5585A2"> **point 7. 粒子**</font> ## <font color=#BC2B86>額外補充</font> <font size=4 color="#9A1D15">形狀/材質/燈光/控制類型</font> <font size=5 color="#5585A2"> **category 1. 控制類型**</font> <font size=4 color="#000"> Orbit Controls: 軌道控制使攝像機可以圍繞目標旋轉</br> Trackball Controls: TrackballControls與OrbitControls相似。但是,它不能保持恆定的攝像機向上矢量。這意味著,如果攝像機繞過“北極”和“南極”,則不會翻轉以保持“右側朝上”</br> Pointerlock Controls: 常用在虛擬展場房間</br> Drag Controls:桌子拖放物體 </br> Transform Controls:移動物體本身,不是移動相機</font>