文章目錄
- 簡介
- 從 dat.GUI 到 lil-gui
- 例子
- 安裝 lil-gui 并實例化
- 不同類型的調整
- 改變位置
- 針對非屬性的調整
- 復選框
- 顏色
- 功能/按鈕
- 調整幾何形狀
- 文件夾
- 調整 GUI
- 寬度
- 標題
- 關閉文件夾
- 隱藏
- 按鍵切換
- 結論
簡介
每一個創意項目的一個基本方面是能夠輕松調整。開發人員和參與項目的其他參與者(如設計師甚至客戶)必須能夠更改盡可能多的參數。
您必須考慮到這一點,以便他們找到完美的顏色、速度、數量等,獲得最佳體驗。您甚至可能會得到意想不到的很棒的結果。
首先,我們需要一個調試 UI。
雖然您可以使用 HTML / CSS / JS 創建自己的調試 UI,但已經有多個庫:
- dat.GUI
- lil-gui
- control-panel
- ControlKit
- Uil
- Tweakpane
- Guify
- Oui
所有這些庫都可以做我們想做的事,但我們將使用lil-gui,因為它很流行、維護良好、并且易于使用
從 dat.GUI 到 lil-gui
最初,Three.js
練習都是使用 dat.GUI
一段時間以來,這個庫一直沒有更新,NPM 在安裝它時開始觸發漏洞警告。這些漏洞已經修復,但替代方案已經開始出現,這就是 lil-gui
作為 dat.GUI
的替代品越來越受歡迎的原因。額外的好處是它甚至有更好的功能。
所有 Three.js
練習現在都使用 lil-gui
順便說一下,GUI 代表圖形用戶界面。
例子
https://bruno-simon.com/#debug
安裝 lil-gui 并實例化
npm i lil-gui
引入并使用
import GUI from 'lil-gui'/*** Debug*/
const gui = new GUI()
不同類型的調整
- 范圍— 針對具有最小值和最大值的數字
- 顏色— 適用于各種格式的顏色
- 文本— 用于簡單文本
- 復選框— 用于布爾值(true或false)
- 選擇— 從值列表中進行選擇
- 按鈕——觸發功能
改變位置
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)gui.add(mesh.position, 'y')
或者寫一個范圍,這樣 ui
就會變成一個滑桿
gui.add(mesh.position, 'y', - 3, 3, 0.01)
也可以使用鏈式調用
gui.add(mesh.position, 'y').min(- 3).max(3).step(0.01)
針對非屬性的調整
這里需要注意的一點是 lil-gui 只能修改屬性。如果你想更新變量,則不能:
let myVariable = 1337
gui.add(myVariable, '???')
但是您可以使用一些技巧來實現這一點,例如創建一個對象,其目的是保存 lil-gui 在該對象上使用的屬性:
const myObject = {myVariable: 1337
}
gui.add(myObject, 'myVariable')
復選框
lil-gui 會自動檢測你想要調整的屬性類型,并使用相應的接口。Object3D visible
的屬性就是一個很好的例子。它是一個布爾值,如果,false
則會隱藏對象:
gui.add(mesh, 'visible')
顏色
處理顏色有點麻煩。讓我們嘗試修改 color
的屬性 material
。
需要通過回調函數里的 value 來設置值, GUI
上的 hex
并不是最終的值
你最終得到了錯誤的顏色:
這是因為 Three.js
應用了一些顏色管理來優化渲染。因此,調整中顯示的顏色值與內部使用的值不同。
我們現在不討論色彩管理, 有兩種方法可以解決這個問題。
gui.addColor(material, 'color')
需要通過回調函數來覆蓋掉 ui 上顯示的值
debugObject.color = '#3a6ea6'const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)
const material = new THREE.MeshBasicMaterial({ color: debugObject.color, wireframe: false })cubeTweaks.addColor(debugObject, 'color').onChange(() =>{material.color.set(debugObject.color)})
功能/按鈕
有時,我們只想按需觸發指令。現在,當我們點擊調試 UI 中的某個位置時,我們希望讓立方體執行一點旋轉動畫。
我們可以通過向包含函數的 tweak 發送一個屬性來實現這一點。不幸的是,這意味著我們不能讓一個函數像這樣獨立存在,然后將其發送給 lil-gui
const myFunction = () => {console.log('do something')
}
gui.add(myFunction, '???')
但是我們可以為我們之前創建的對象添加一個spin屬性debugObject,并將 GSAP 動畫集成到其中:
debugObject.spin = () =>
{gsap.to(mesh.rotation, { duration: 1, y: mesh.rotation.y + Math.PI * 2 })
}
最后,我們可以將調整添加到 debugObject.spin
debugObject.spin = () =>
{// ...
}
gui.add(debugObject, 'spin')
調整幾何形狀
gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onChange(() =>{console.log('subdivision changed')})
對于 CPU 來說,構建幾何圖形可能是一個相當漫長的過程。現在,我們正在監聽更改事件,如果用戶過多地拖放范圍調整,則可能會多次觸發該事件。
onChange
我們不會使用 ,而是使用onFinishChange
,它僅當我們停止調整值時才會觸發:
gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onFinishChange(() =>{console.log('subdivision finished changing')})
除此之外console.log(),我們還可以使用 構建一個新的幾何體,并通過將其分配給其屬性來debugObject.subdivision將其與 關聯:meshgeometry
gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onFinishChange(() =>{mesh.geometry = new THREE.BoxGeometry(1, 1, 1,debugObject.subdivision, debugObject.subdivision, debugObject.subdivision)})
就是這樣,但我們犯了一個小錯誤。舊幾何圖形仍位于 GPU 內存中的某個位置,這可能會導致內存泄漏。
dispose()為了解決這個問題,我們可以在創建新的幾何圖形之前在舊幾何圖形上調用該方法:
gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onFinishChange(() =>{mesh.geometry.dispose()mesh.geometry = new THREE.BoxGeometry(1, 1, 1,debugObject.subdivision, debugObject.subdivision, debugObject.subdivision)})
文件夾
假設我們有很多調整,調試 UI 開始變得擁擠。我們可以使用此addFolder()方法將它們分成文件夾。
要創建文件夾,請調用addFolder()并發送您想要的名稱作為參數。請確保在調整之前執行此操作并將其保存為cubeTweaks:
const cubeTweaks = gui.addFolder('Awesome cube')
然后,不要使用gui來創建調整,而是使用cubeTweaks變量:
const cubeTweaks = gui.addFolder('Awesome cube')cubeTweaks.add(mesh.position, 'y')// ...cubeTweaks.add(mesh, 'visible')cubeTweaks.add(material, 'wireframe')cubeTweaks.addColor(material, 'color')// ...// ...
cubeTweaks.add(debugObject, 'spin')// ...
cubeTweaks.add(debugObject, 'subdivision')// ...
可以默認
const cubeTweaks = gui.addFolder('Awesome cube')
cubeTweaks.close()
調整 GUI
寬度
const gui = new GUI({width: 300
})
標題
const gui = new GUI({width: 300,title: 'Nice debug UI'
})
關閉文件夾
const gui = new GUI({width: 300,title: 'Nice debug UI',closeFolders: true
})
隱藏
const gui = new GUI({width: 300,title: 'Nice debug UI',closeFolders: false,
})
// gui.close()
gui.hide()
按鍵切換
window.addEventListener('keydown', (event) =>
{if(event.key == 'h')gui.show(gui._hidden)
})
結論
隨著你的 項目的進行,來添加各種各樣的 gui
參數