[Three.js-02] Three.js 中的辅助神器

1,702 阅读4分钟

[Three.js-02] Three.js 中的辅助神器

这是我的学习总结,水平有限,如有错误或不妥的地方还希望大家能够指出来 (^_^)respect! 另外我自己收集的【webgl\three.js\图形学】相关的关资源我已经放在微信群(WX: Galloping_Leo )里面了,需要的话,加群,一起学习共同进步。

lil-gui

首先要介绍一下 lil-gui,它可以为网页中的控制器添加可视化操作面板。接下来就介绍一下它的基本操作。

  • 创建 gui 实例
const gui = new GUI()

默认会创建一个空的控制器在屏幕的右上方,在被自动添加到 body 元素内。

gui-1.png

我们也可以自己控制元素的位置,传入一个参数 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')

gui-3.png

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')

gui-4.png

  • 范围控制器

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))

gui-5.gif

  • 选择控制器

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))

gui-6.gif

  • checkbox控制器

add方法的参数与按钮的一样,只不过参数二对应的不是一个函数而是一个 bool

const [show, setShow] = useState(true)
const controlConfigs = {
   select: num, // 默认初始值
}

control.add(controlConfigs, 'isShow').onChange((e: boolean) => setShow(e))

gui-7.gif

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()
    }
}

最终的效果如下

坐标轴辅助器.gif

轨道控制器

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 // 最小距离

效果如下

轨道控制器.gif

如果开启了操作阻尼效果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()
   
    // 省略其它代码......
}

custom-gemotry.gif

相机辅助工具

这个放到后面讲相机的部分再来细说。传送门->