Three.js 文档:https://threejs.org/
哔哩哔哩配套视频学习教程地址:https://www.bilibili.com/video/BV1HPYQz7Ed2?spm_id_from=333.788.videopod.episodes&vd_source=628c735d0423e2bd1153ac15c47d3d87
GUI 顾名思义就是图形用户界面,具体就是通过编程的方式在画布界面上出现图形界面,通过该界面可视化调整物体参数,达到预期效果后,记录图形界面参数值,然后把这些参数值写到代码中。具体效果请看下面的动图(右上角就是GUI):

其实就和浏览器网页开发中调整CSS样式一样,打开浏览器控制台的元素标签页,定位元素后就可以在控制台调整其CSS样式属性值,达到效果后再把控制台调整好的CSS复制或手动写到代码文件中。
注意:Threejs本身没有GUI库,需要借助第三方库 dat.gui 来实现。
NPM地址:https://www.npmjs.com/package/dat.gui
API文档地址:https://github.com/dataarts/dat.gui/blob/HEAD/API.md
在项目根目录下执行下面的命令进行安装 dat.gui:
npm install --save dat.gui
在 main.js 中文件开头引入 dat.gui:
#file src/main.js
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 引入 dat.gui
import * as dat from 'dat.gui'
在 main.js 增加一个名称为 createGUI() 的方法在其中来编写 GUI 相关代码:
#file src/main.js
// 创建 GUI 工具
function createGUI() {
// 创建 GUI 对象
const gui = new dat.GUI()
}
// …… 为了更好的阅读,此处省略更多代码,文末会提供完整示例代码
// 创建 GUI
createGUI()
// 渲染循环
renderLoop()
注意:调用createGUI()的位置必须是在GUI控制对象创建之后,渲染循环函数之前。下文中的实践代码都在该方法中实现。
下面介绍几个常用的添加控制器的重要方法,如果需要了解更过阅读API文档:https://github.com/dataarts/dat.gui/blob/HEAD/API.md
该方法向图形用户界面添加一个新的控制器。所创建控制器的类型根据控制对象[属性]的初始值推断得出。
注意:颜色属性,需要单独使用 addColor() 方法来添加。
语法如下:
gui.add(object, property, [min], [max], [step]) ⇒ Controller
参数说明:
该方法可以添加一个颜色选择控制器到图形界面。语法如下:
gui.addColor(object, property) ⇒ Controller
参数说明:
该方法创建一个新的子文件夹图形用户界面实例,可以在该实例下继续添加控制器。
通俗讲,就是说在GUI图形界面上创建了一个分组,在分组下可以继续添加控制对象。语法如下:
gui.addFolder(name) ⇒ dat.gui.GUI
参数说明:
以下示例代码都是在main.js 中的 createGUI() 的方法中来编写的。每个示例代码块只展示与本示例相关的代码,本文最后章节会提供完整的代码。
示例1:添加一个输入框控制器,来控制 document 对象的标题属性title。
function createGUI() {
const gui = new dat.GUI()
gui.add(document, 'title')
}
示例2:添加一个单选框控制器,来控制立方体对象 cube 对象的显示控制属性visible,从而控制立方体的显示与隐藏。
function createGUI() {
const gui = new dat.GUI()
gui.add(cube, 'visible')
}
示例3:添加一个按钮控制器,来调用控制轨道控制器回归初始角度的方法 reset()。
function createGUI() {
const gui = new dat.GUI()
gui.add(controls, 'reset')
}
示例4:添加一个数字滑动控制器,来控制立方体对象 cube 对象的 x 轴坐标的位置属性position.x,从而控制立方体在 x 轴上的位置。
function createGUI() {
const gui = new dat.GUI()
gui.add(cube.position, 'x', 0, 5, 0.1)
}
示例5:添加一个下拉选择框控制器,通过监听下拉框选中值的变化,从而通过代码实现对 cube 对象的位置坐标进行控制。
function createGUI() {
const gui = new dat.GUI()
gui.add({ type: '1' }, 'type', { 方案一: '1', 方案二: '2' }).onChange((val) => {
switch (val) {
case '1':
cube.position.set(0, 0, 0)
break
case '2':
cube.position.set(1, 1, 1)
break
}
})
}
示例6:添加一个颜色选择控制器,来控制 cube 对象的颜色。
注意:由于 Threejs 中对 cube 颜色的处理相对复杂,还要兼容不同格式的颜色值,所以处理上与上面示例稍有不同。
function createGUI() {
const gui = new dat.GUI()
// 借助一个中间色值储存对象变量
const colorObj = {
col: '#' + cube.material.color.getHexString(),
}
// GUI控制上面创建的中间对象变量
gui.addColor(colorObj, 'col').onChange((val) => {
// 通过颜色控制器的事件,及时获取颜色控制器的选择值的变化,并转化处理色值的格式,然后更新立方体的颜色属性
cube.material.color = new THREE.Color(val)
})
}
示例7:添加一个分组控制器,然后在该分组下添加分别控制立方体 cube 在各个坐标轴的位置。
分组的意义就是,根据某个规则把多个控制器放到一起,更容易使用。
function createGUI() {
const gui = new dat.GUI()
const cubePoiFolder = gui.addFolder('cube_position')
cubePoiFolder.add(cube.position, 'x', 0, 5, 0.1)
cubePoiFolder.add(cube.position, 'y', 0, 5, 0.1)
cubePoiFolder.add(cube.position, 'z', 0, 5, 0.1)
}
下面为综合示例代码:
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import * as dat from 'dat.gui'
// 场景,摄像机,渲染器
let scene, camera, render
// 轨道控制器
let controls
// 立方体
let cube
// 初始化三要素
function init() {
// 1. 创建场景对象
scene = new THREE.Scene()
// 2. 创建摄像机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
// 移动摄像机 z 轴 5 个单位(默认摄像机和物体的坐标轴的都在原点)
camera.position.z = 5
// 3. 创建渲染器
render = new THREE.WebGLRenderer({
antialias: true, // 开启抗锯齿 - 优化
})
render.setSize(window.innerWidth, window.innerHeight) // 设置画布大小
document.body.append(render.domElement)
}
/**
* 绘制立方体步骤:
* 1. 创建图形,宽高深为 1 单位
* 2. 创建材质,颜色为绿色 0x00ff00
* 3. 创建网格物体对象,传入图形和材质
* 4. 把物体对象添加到场景
* 注意:
* 1. 默认物体中心与坐标轴重合,所以摄像机需要位移才能看到物体,也就是摄像机需要拉远一些才能看到物体
* 2. 渲染器需要调用 render 才能渲染画面(等待物体添加到场景后,再调用)
*/
function createCube() {
// 1. 创建图形,宽深高为 1 单位(立体缓冲几何体)
const geometry = new THREE.BoxGeometry(1, 1, 1)
// 2. 创建材质,颜色为绿色 0x00ff00 (网格基础材质 - 线面纯颜色描绘表面)
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
// 3. 创建网格物体对象,传入图形和材质(网格物体对象)
cube = new THREE.Mesh(geometry, material)
// 4. 把物体加入到场景中
scene.add(cube)
}
/**
* 轨道控制器:
* 使摄像机围绕目标进行轨道运动
* 作用:右键拖动,左键旋转,滚轮拉进,拉远摄像机
* 使用:
* 1. 单独引入 OrbitControls 轨道控制器构造函数
* 2. 创建轨道控制器
* 3. 在 渲染循环中更新场景渲染
*/
function createControls() {
controls = new OrbitControls(camera, render.domElement)
// 启用阻尼
controls.enableDamping = true
/*
// 自动微淘目标旋转旋转
controls.autoRotate = false
controls.autoRotateSpeed = 5
// 垂直角度范围的控制(0 上面,Math.PI 下面)
controls.maxPolarAngle = Math.PI
controls.minPolarAngle = 0
// 水平角度方位的控制,以下配置不能看到正面
controls.maxAzimuthAngle = 1.5 * Math.PI
controls.minAzimuthAngle = 0.5 * Math.PI
// 摄像机移动范围控制(拉进、拉远)
controls.minDistance = 2
controls.maxDistance = 10
*/
}
/**
* 渲染循环
*/
function renderLoop() {
render.render(scene, camera)
// 手动 JS 代码更新过摄像机信息,必须调用轨道控制器 update 方法
controls.update()
// cube.rotation.x += 0.01
// 根据当前计算机浏览器刷新帧率(默认 60 次/秒),不断递归调用此函数渲染最新的画面状态
// 好处:当前页面切换到后台,暂停递归
requestAnimationFrame(renderLoop)
}
function createHelper() {
/**
* 用于简单模拟3个坐标轴的对象.
* 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
*/
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)
}
/**
* 优化 - 适配场景大小
* 目标:浏览器窗口,尺寸改变时,画布自适应
* 步骤:
* 1. 创建适配函数,监听浏览器 resize 事件
* 2. 调整渲染器画布宽高,摄像机宽高比和更新视椎体空间
*/
function resizeRender() {
window.addEventListener('resize', () => {
render.setSize(window.innerWidth, window.innerHeight)
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
})
}
/**
* 移动立方体
* 使用:所有物体继承自 Object3D 类
* 1. 位移 position 属性
* 2. 旋转 rotation 属性
* 3. 缩放 scale 属性
*/
function moveCube() {
// cube.position.x = 2
// cube.position.set(2, 0, 0)
// 旋转属性值为 Eular 角对象(弧度制),在轴正方形来看物体,默认是绕着轴进行逆时针旋转
// cube.rotation.x = Math.PI / 4
//cube.rotation.set(Math.PI / 4, 0, 0)
//cube.scale.set(1, 1, 2)
}
// 创建 GUI 工具
function createGUI() {
// 创建 GUI 对象
const gui = new dat.GUI()
// 添加具体控制对象
// 示例1:添加控制 document 对象的标题属性 (属性值为字符串时,图形界面渲染为输入框)
gui.add(document, 'title')
// 示例2:添加控制立方体显示与隐藏(属性值为布尔值时,图形界面渲染为多选框)
gui.add(cube, 'visible')
// 示例2:添加控制轨道控制器回归初始角度(属性值为函数或方法时,图形界面渲染为按钮)
gui.add(controls, 'reset')
// 示例3:控制立方体的颜色
const colorObj = {
col: '#' + cube.material.color.getHexString(),
}
gui.addColor(colorObj, 'col').onChange((val) => {
cube.material.color = new THREE.Color(val)
})
// 示例4:添加GUI分组 - 控制立方体的位移
const cubePoiFolder = gui.addFolder('cube_position')
cubePoiFolder.add(cube.position, 'x', 0, 5, 0.1)
cubePoiFolder.add(cube.position, 'y', 0, 5, 0.1)
cubePoiFolder.add(cube.position, 'z', 0, 5, 0.1)
// 示例4:添加下拉菜单
gui.add({ type: '1' }, 'type', { 方案一: '1', 方案二: '2' }).onChange((val) => {
switch (val) {
case '1':
cube.position.set(0, 0, 0)
break
case '2':
cube.position.set(1, 1, 1)
break
}
})
}
// 初始化三要素
init()
// 轨道控制器
createControls()
// 坐标轴
createHelper()
// 视频浏览器视口
resizeRender()
// 创建立方体
createCube()
// 变换立方体
moveCube()
// 添加GUI
createGUI()
// 渲染循环
renderLoop()
至此本文结束了,希望有助于您!
🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。