欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

WebGL+Three.js- 第 10 章 可视化调试工具

最编程 2024-04-02 11:35:53
...

10.1 可视化调试工具简介

        在深入学习three.js之前,我们先掌握好一些图形界面的调试工具,因为后续three.js的材质、光源等会有大量的属性。如果配合UI调试工具,将会非常方便我们对每个属性的掌握。

        在这里介绍两个UI调试工具,一个是dat.gui,一个是lil.gui。两个工具的使用方式都非常相似,也十分简单。

        dat.gui是一个可视化的属性面板UI工具库,它可以把你想调试的属性列在面板上,设置它的取值范围,然后就可以在面板中随意改变它的值,它会通过回调函数把值返回,我们再进行对应的操作。

        lil.gui是three.js社区中非常流行的UI库,dat.gui是它的前身。它的使用方法跟dat.gui非常类似,也是一个语法简单、上手快的一个可视化的属性面板UI工具库。

        以下是dat.GUI与lil.gui的结构图:          image.png

        说明:由于dat.gui与lil.gui使用方式基本完全一致,在这里就一起讲解。

10.2 dat-gui与lil.gui

10.2.1 使用流程

        1、引入库文件

            (1)dat.gui

                1.普通方式

<script src="dat.gui.js">

                    推荐一个可用的在线库:lf6-cdn-tos.bytecdntp.com/cdn/expire-…

                2.npm

npm i dat.gui

import * as dat from 'dat.gui';

            (2)lil.gui

import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min';

        2、实例化对象

            (1)dat.gui

const gui = new dat.GUI();

            (2)lil.gui

const gui = new GUI();

        3、定义设置的属性对象

            假设你有2个属性需要通过gui工具监听,那么可以设置一个对象,把需要监听的属性包裹在内:

const controls = {
  color: 0xffffff,
  numberInput: 0
}

        4、属性对象绑定到gui

            绑定属性主要是通过add和addColor两个方法,addColor顾名思义是用来监听颜色的,它会生成一个颜色面板,其余属性统一通过add方法。

            add方法总共有4个参数,第一个参数是属性对象,第二个参数是需要监听的属性名,第三和第四个参数需要根据属性的类型进行设置,在往下会有详细讲述。前两个参数必选,而addColor方法只有前两个参数。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    color: 0xffffff,
    numberInput: 0.2
  }
  gui.addColor(controls, 'color')
  gui.add(controls, 'numberInput')
}
initControl();

image.png

10.2.2 控件类型

10.2.2.1 Number类型

    1、不设置限制条件(默认)

        如果没有设置限制条件,则为一个input输入框。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberInput: 0.2
  }
  gui.add(controls, 'numberInput')
}
initControl();

image.png

    2、设置最小值最大值

        可以设置最小值最大值范围,则显示为slider滑块组件(当然右侧还是有input输入)

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberSlider: 3
  }
  gui.add(controls, 'numberSlider', 0, 10)
}
initControl();

image.png

    3、单独设置最小值最大值

        还可以只单独限制最小值或者最大值,这个同样为一个input输入框。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberMin: 3,
    numberMax: 3
  }
  gui.add(controls, 'numberMin').min(0)
  gui.add(controls, 'numberMax').max(10)
}
initControl();

image.png

    4、设置步长

        它可以通过step方法设置它的步长。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberStep: 3
  }
  gui.add(controls, 'numberStep').step(0.2)
}
initControl();

image.png

    5、下拉框

        如果数字只是有限的几种固定值,那还可以使用下拉框的形式。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberSelect: 1
  }
  gui.add(controls, 'numberSelect', {
    selectOption1: 1,
    selectOption2: 2,
    selectOption3: 3,
  })
}
initControl();

image.png

    6、混合模式

        它既可以设置最大最小值,同时也可以设置步长。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberMix: 1
  }
  gui.add(controls, 'numberMix', 0, 10).step(0.2)
}
initControl();

image.png

10.2.2.2 String类型

    1、不设置限制条件(默认)

            如果没有设置限制条件,则为一个input输入框。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    stringInput: 'test'
  }
  gui.add(controls, 'stringInput')
}
initControl();

image.png

    2、下拉框

        如果只是有限的几种固定值,那还可以使用下拉框的形式。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    stringSelect: 'test1'
  }
  gui.add(controls, 'stringSelect', ['test1', 'test2', 'test3'])
}
initControl();

image.png

10.2.2.3 Boolean类型

    使用复选框(Checkbox)的形式控制。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    checkbox: true
  }
  gui.add(controls, 'checkbox')
}
initControl();

image.png

10.2.2.4 自定义函数

    使用按钮(button)的形式控制,点击按钮会调用相应的方法。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    checkbox: true
  }
  gui.add(controls, 'checkbox')
}
initControl();

image.png

10.2.2.5 颜色

    dat.GUI一共提供了4种类型颜色输入控制:CSS、RGB、RGBA、Hue(注意:颜色使用addColor方法添加控件)

    1、CSS

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    CssString: '#ffffff'
  }
  gui.add(controls, 'CssString')
}
initControl();

image.png

    2、RGB

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    RGB: [0, 128, 255]
  }
  gui.add(controls, 'RGB')
}
initControl();

image.png

    3、RGBA

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    RGBA: [0, 128, 255, 0.3]
  }
  gui.add(controls, 'RGBA')
}
initControl();

image.png

    4、HSL

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    HSL: {h: 350, s: 0.9, v: 0.3}
  }
  gui.add(controls, 'HSL')
}
initControl();

image.png

10.2.3 回调函数

        dat.gui的回调函数有两个方法:一个是onChange,一个是onFinishChange。onChange是在面板值变化的过程中实时返回值,onFinishChange顾名思义是面板值变化结束之后再返回值。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    onChange: '#ffffff',
    onFinishChange: 1
  }
  gui.addColor(controls, 'onChange').onChange(value => {
    console.log('onChange值:' + value)
  })
  gui.add(controls, 'onFinishChange', 0, 10).onFinishChange(value => {
    console.log('onFinishChange值:' + value)
  })
}
initControl();

image.png

        注意:监听颜色的时候,尽量避免使用十六进制的形式,虽然它也可以识别,但是它的返回值是一串数字,不利于我们使用。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    onChangeHex: 0xffffff
  }
  gui.addColor(controls, 'onChangeHex').onChange(value => {
    console.log('onChange值:' + value)
  })
}
initControl();

image.png

10.2.4 创建文件夹

        如果需要监听的属性太多,有可能会显示不全,而且也显得有点杂乱无章。这个时候可以使用gui提供的addFolder方法,字面意思是创建文件夹,实际上相当于建一个目录,把属性进行一个归类整理。

        使用方法也很简单,首先用gui实例使用addFolder方法,只需要传入文件夹名参数即可。然后把需要归类的属性,通过文件夹名调用add方法添加进去。

function initControl() {
  const gui = new dat.GUI();
  const controls = {
    numberInput: 0.2,
    numberSlider: 3,
    numberMin: 3,
    numberMax: 3,
    numberStep: 3,
    numberSelect: 1,
    numberMix: 1,
    stringInput: 'test',
    stringSelect: 'test1',
    checkbox: true,
    fn: function() {
      console.log('自定义函数')
    },
    CssString: '#ffffff',
    RGB: [0, 128, 255],
    RGBA: [0, 128, 255, 0.3],
    HSL: {h: 350, s: 0.9, v: 0.3},
    onChange: '#ffffff',
    onFinishChange: 1,
    onChangeHex: 0xffffff,
  }

  const numberFolder = gui.addFolder('Number类型');
  numberFolder.add(controls, 'numberInput')
  ......

  const stringFolder = gui.addFolder('String类型');
  stringFolder.add(controls, 'stringInput')
  stringFolder.add(controls, 'stringSelect', ['test1', 'test2', 'test3'])

  const checkboxFolder = gui.addFolder('Boolean类型');
  checkboxFolder.add(controls, 'checkbox')

  const fnFolder = gui.addFolder('自定义函数类型');
  fnFolder.add(controls, 'fn')

  const colorFolder = gui.addFolder('颜色类型');
  colorFolder.addColor(controls, 'CssString')
  ......

  const callbackFolder = gui.addFolder('回调函数');
  callbackFolder.addColor(controls, 'onChange').onChange(value => {
    console.log('onChange值:' + value)
  })
  ......
}
initControl();

image.png

image.png

10.2.5 示例代码

    1、dat.gui

    2、lil.gui

10.3 结合three.js

        学习完可视化调试工具之后,可以结合threejs场景进行控制,这里我们采用lil.gui作为例子,对以下几种类型进行结合演示。

        1、函数类型:全屏、退出全屏

        2、Number类型:控制立方体的x、y、z轴位置

        3、Boolean类型:物体材质是否为线框模式

        4、颜色类型:控制立方体颜色

10.3.1 全屏与退出全屏

data() {
  return {
    eventObj: {
      // 全屏
      fullScreen: function() {
        document.body.requestFullscreen();
      },
      // 退出全屏
      exitFullScreen: function() {
        document.exitFullscreen();
      }
    }
  }
},
method: {
  // 初始化lil.gui调试工具
  initControl() {
    const gui = new GUI();
    gui.add(this.eventObj, "fullScreen");
    gui.add(this.eventObj, "exitFullScreen");
  }
}

image.png

        这里还可以修改一下它的别名,就是它默认会显示我们绑定的属性名字,假设我们想给它起一个别名,例如这里把fullScreen改成显示全屏,可以调用它的name方法:

method: {
  // 初始化lil.gui调试工具
  initControl() {
    const gui = new GUI();
    gui.add(this.eventObj, "fullScreen").name('全屏');
    gui.add(this.eventObj, "exitFullScreen").name('退出全屏');
  }
}

image.png

10.3.2 控制立方体位置

// 设置父元素旋转
parentCube.rotation.x = Math.PI / 4;
// 设置子元素旋转
this.cube.rotation.x = Math.PI / 4;

initControl() {
  const gui = new GUI();

  // 控制全屏、退出全屏
  gui.add(this.eventObj, "fullScreen").name('全屏');
  gui.add(this.eventObj, "exitFullScreen").name('退出全屏');

  // 控制立方体的位置
  gui.add(this.cube.position, 'x', -10, 10).step(1).name('立方体x轴位置')
  gui.add(this.cube.position, 'y', -10, 10).step(1).name('立方体y轴位置')
  gui.add(this.cube.position, 'z', -10, 10).step(1).name('立方体z轴位置')
}

image.png

        注意:我们这里控制的是子立方体的位置,由于它的父立方体旋转了45°,因此它在y轴的方向也是旋转了45°(自己旋转的的角度不算),因此在控制它的y轴位置的时候,它是朝着y轴的45°的方向上下移动,而不是垂直。

10.3.3 控制立方体是否线框模式

initControl() {
  const gui = new GUI();

  ......

  // 控制父立方体是否线框模式
  folder.add(this.parentCubeMaterial, 'wireframe').name('父元素线框模式')
}

image.png

10.3.4 控制立方体颜色

initControl() {
  const gui = new GUI();

  ......

  // 控制立方体颜色
  folder.addColor(this.eventObj, 'cubeColor').name('立方体颜色').onChange(val => {
    this.cube.material.color.set(val);
  })
}

image.png

10.3.5 代码示例