[Three.js-02] Three.js 中的辅助神器
这是我的学习总结,水平有限,如有错误或不妥的地方还希望大家能够指出来 (^_^)respect! 另外我自己收集的【webgl\three.js\图形学】相关的关资源我已经放在微信群(WX: Galloping_Leo )里面了,需要的话,加群,一起学习共同进步。
lil-gui
首先要介绍一下 lil-gui,它可以为网页中的控制器添加可视化操作面板。接下来就介绍一下它的基本操作。
- 创建 gui 实例
const gui = new GUI()
默认会创建一个空的控制器在屏幕的右上方,在被自动添加到 body 元素内。
我们也可以自己控制元素的位置,传入一个参数 autoPlace: false,这时候就不会创建控制器,需要自己通过 gui.domElement 来拿到结构自行决定放在哪里。
const gui = new GUI({ autoPlace: false })
gui.domElement.classList.add('custom-place')
container.appendChild(gui.domElement)
container 中可以设置 css 来控制控制器渲染的位置
.container {
position: relative;
.custom-place {
position: absolute;
top: 0;
right: 0;
max-height: 100%;
}
}
然后我们来看看具体的用法:
- addFolder 向控制器中添加一个目录结构
const control = gui.addFolder('new Folder')
control.add 添加控制器,值范围控制器,状态切换控制器等等...
add 方法用很多重载,提供不同的参数展示出不同的控制器。
参数及其类型如下: add(object: object, property: string, $1?: number | object | any[], max?: number, step?: number): Controller; 最终返回的也是 Contoller 对象,也就是后支持链式调用。
第一个参数是一个对象,里面提供了控制器需要的操作或者是默认值。
- 按钮控制器
type add<T extends Object> = (obj: T, property: keyof T) => Controller
参数二一定是参数一中的属性,并且这个属性的值是一个函数,此函数中包含了自己需要的控制逻辑。使用 .name('xxxx') 来为此按钮命名。
const [num, setNum] = useSate(0)
const controlConfigs = {
add: {
run(){
setNum(x=> x+1)
}
}
}
control.add(controlConfigs.add, 'run').name('add 1')
- 范围控制器
type add<T extends Object> = (obj: T, property: keyof T, min: number, max: number, step: number) => Controller
第一个参数之前一样,第二个参数的对应的值的类型必须是 number ,后面的参数依次代表:最小值,最大值,每一次改变时最小步长。
通过 onChange 方法监听范围条值的变化,通过回到参数 e 拿到当前值,然后写出自己的逻辑。
const [num, setNum] = useSate(0)
const controlConfigs = {
range: num, // 默认初始值,要是 number 类型
}
control.add(controlConfigs, 'range', 0, 10, 1)
.name('change')
.onChange((e: number) => setNum(e))
- 选择控制器
type add<T extends Object, K extends keyof T> = (obj: T, property: K, options: T[K][]) => void Controller
const [num, setNum] = useSate(0)
const controlConfigs = {
select: num, // 默认初始值
}
control.add(controlConfigs, 'select', [1, 2, 3, 4])
.name('change')
.onChange((e: number) => setNum(e))
- checkbox控制器
add方法的参数与按钮的一样,只不过参数二对应的不是一个函数而是一个 bool 值
const [show, setShow] = useState(true)
const controlConfigs = {
select: num, // 默认初始值
}
control.add(controlConfigs, 'isShow').onChange((e: boolean) => setShow(e))
lil-gui 就介绍到这里,如果想要更深入了解请移步 => 官方文档
坐标轴辅助工具
在 three.js 中有几种坐标体系的视觉辅助工具,使用它们可以帮助我们开发 three.js 应用,让我们更清楚的知道3D对象在空间中的位置。
- THREE.AxesHelper 三维直角坐标系辅助器
- THREE.GridHelper 网格辅助器
- THREE.PolarGridHelper 极坐标辅助器
const helperControl = gui.addFolder('Helper')
const axesHelperName = 'axesHelper'
const gridHelperName = 'gridHelper'
const polarGridHelperName = 'polarGridHelper'
const props = {
axesHelper: {
toggle() {
toggle(axesHelperName, () => {
// 创建三维直角坐标系
// 参数一 size,设置坐标轴的大小,即每根坐标的长度
const helper = new THREE.AxesHelper(10)
helper.name = axesHelperName
// 向场景中添加
scene.add(helper)
})
}
},
gridHelper: {
toggle() {
toggle(gridHelperName, () => {
// 网格辅助器的创建
// 参数一 size 大小
// 参数二 division 设置几乘几的网格
// 参数三 参数四 分别设置水平垂直的网格线的颜色
const helper = new THREE.GridHelper(20, 10)
helper.name = gridHelperName
scene.add(helper)
})
}
},
polarGridHelper: {
toggle() {
toggle(polarGridHelperName, () => {
// 极坐标辅助器
// 参数依次是:半径、多少条放射轴,多少圈,每一圈多少分段组成
const helper = new THREE.PolarGridHelper(10, 16, 8, 128)
helper.name = polarGridHelperName
scene.add(helper)
})
}
}
}
helperControl.add(props.axesHelper, 'toggle').name(axesHelperName)
helperControl.add(props.gridHelper, 'toggle').name(gridHelperName)
helperControl.add(props.polarGridHelper, 'toggle').name(polarGridHelperName)
function toggle(name: string, creator: () => void) {
const helper = scene.getObjectByName(name)
if (helper) {
scene.remove(helper)
} else {
creator()
}
}
最终的效果如下
轨道控制器
three.js 提供了一个 OrbitControl 类,它可以让我们通过鼠标触控板来拖动缩放视图。实际上是通过改变相机的位置来达到这样的效果,通过轨道控制器可以让相机从不同的位置观察物体,更好的展现出物体在空间中的状态。
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 轨道控制器
const orbitContorl = new OrbitControls(camera, renderer.domElement)
orbitContorl.enableDamping = true // 开启操作阻尼效果
orbitContorl.dampingFactor = 0.15 // 阻尼系数
orbitContorl.maxPolarAngle = Math.PI * 2 // 最大旋转角
orbitContorl.minPolarAngle = 0 // 最小旋转角
orbitContorl.maxDistance = 100 // 最大距离
orbitContorl.minDistance = 0.1 // 最小距离
效果如下
如果开启了操作阻尼效果orbitContorl.enableDamping = true ,那么必须要在 animation 函数中调用
function animation() {
orbitContorl.update()
// 省略其它代码......
}
性能监控
three.js 提供了性能监控的面板,包含三个关键值 帧率、内存、多久执行一次更新
import Stats from 'three/examples/jsm/libs/stats.module'
// 性能监控
const stats = Stats()
// 添加类自定义显示的位置
stats.domElement.classList.add('stats-bar')
container.appendChild(stats.domElement)
同样的需要在 animation 函数中调用
function animation() {
stats.update()
// 省略其它代码......
}
相机辅助工具
这个放到后面讲相机的部分再来细说。传送门->