制作GUI的两种方法

更新时间: 2025-04-03 14:34:55

在本教程中,我们将了解如何创建图形界面,以便能够将数据输入到babylon.js应用程序中。

# GUI模块

GUI文档 (opens new window) npm install -S @babylonjs/gui @babylonjs/materials @babylonjs/gui-editor @babylonjs/serializers

在项目中引入GUI

import * as GUI from '@babylonjs/gui/2D'  
1

简单的创建一个AdvancedDynamicTexture的全屏实例,参数中的字符串只是一个可选的名称

const advancedTexture = GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI')
1

现在我们已经准备好了动态纹理实例,现在我们向其中引入元素

# 普通按钮

要做的第一件事是添加一个按钮

const button = GUI.Button.CreateSimpleButton('myBtn', '点我!')  
advancedTexture.addControl(button)  
1
2


如图,我们得到了按钮,但按钮的背景不可见,而且它占据了整个画布。
为了解决这个问题,我们需要为按钮设置宽度和高度,因为正常情况下,大多数空间都占用动态纹理的整个宽度和高度

button.width = '200px'
button.height = '40px'
1
2

我们还可以修改按钮的颜色,颜色名字和css中一样

button.color = 'white'
button.background = 'deepskyblue' 
1
2

# 有背景图的按钮

我们可以创建另一种类型的按钮,这些按钮包含图像

  const advancedTexture = GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI')
  const button = GUI.Button.CreateImageButton('myBtn','点我!','vite.svg')  
  button.width = '200px'
  button.height = '40px'
  button.color = 'white'
  button.background = 'deepskyblue'
  advancedTexture.addControl(button)
1
2
3
4
5
6
7

修改按钮中图片的位置

button.image.left = '30px'
1

绑定事件

button.onPointerUpObservable.add(function(){
    planeMat.emissiveTexture = null 
    planeMat.emissiveColor = BABYLON.Color3.Teal()
})
1
2
3
4

# 文本块

可以将文本添加到动态纹理中

const text = new GUI.TextBlock()
text.text = 'Hello World!' 
text.color = 'white'
text.fontSize = 72
text.fontFamily = 'Montserrat Black'  
text.shadowColor = '#000'  
text.shadowOffsetX = 2  
text.shadowOffsetY = 2
advancedTexture.addControl(text)
1
2
3
4
5
6
7
8
9

# 文本输入

const input = new GUI.InputText()  
// 宽度为canvas的2%
input.width = 0.2  
input.height = '40px'
input.text = 'Default text'
input.color = 'black'
input.background = 'deepskyblue'
input.focusedBackround = 'white'
input.onTextChangedObservable.add(function(value){
    planeMat.emissiveTexture = null
    planeMat.emissiveColor = new BABYLON.Color3(0, 0, value.text)
})
advancedTexture.addControl(input)
1
2
3
4
5
6
7
8
9
10
11
12
13

# 滑块

const slider = new GUI.Slider()  
slider.minimum = 0
slider.maximum = 1
slider.height = '20px'
slider.width = '200px'
slider.value = 1
slider.onValueChangedPObservable.add(function(value){
    planeMat.emissiveTexture = null
    planeMat.emissiveColor = new BABYLON.Color3(0, 0, value)
})
advancedTexture.addControl(slider)
1
2
3
4
5
6
7
8
9
10
11

# 颜色选择器

  const picker = new GUI.ColorPicker()
  picker.onValueChangedObservable.add(function(value) {
    planeMat.emissiveTexture = null
    planeMat.emissiveColor.copyFrom(value)
  })
  advancedTexture.addControl(picker)
1
2
3
4
5
6

# 单选框

  const checkbox = new GUI.Checkbox()
  checkbox.width = '20px'
  checkbox.height = '20px'
  checkbox.color = 'white'
  checkbox.isChecked = false
  checkbox.onIsCheckedChangedObservable.add(function(value){
    planeMat.wireframe = value
  })
  advancedTexture.addControl(checkbox)
1
2
3
4
5
6
7
8
9

但这个单选框没有lable,我们来给单选框添加label

  const checkboxHeader = GUI.Control.AddHeader(checkbox, 'Wireframe', '100px', {
    isHorizontal: true,
    controlFirst: false
  })
  checkboxHeader.color = 'white'
  advancedTexture.addControl(checkboxHeader)
1
2
3
4
5
6

不过有更简单的方式:

  const advancedTexture = GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI')
  const cBoxWithHeader = GUI.Checkbox.AddCheckBoxWithHeader('Wireframe:', function(value) {
    planeMat.wireframe = value
  })
  cBoxWithHeader.children[0].isChecked = false
  cBoxWithHeader.children[1].fontSize = 38
  advancedTexture.addControl(cBoxWithHeader)
1
2
3
4
5
6
7

# clone方法

我们来复制一个按钮

 const button = GUI.Button.CreateImageButton('myBtn','点我!','vite.svg')  
  button.width = '200px'
  button.height = '40px'
  button.color = 'white'
  button.background = 'deepskyblue'
  button.onPointerUpObservable.add(function() {
    planeMat.emissiveTexture = null
    planeMat.emissiveColor = BABYLON.Color3.Teal()
  })
  advancedTexture.addControl(button)

  const button2 = button.clone()
  button2.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT  
  advancedTexture.addControl(button2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

但是按钮绑定的事件是不会被复制的,需要重新为复制的按钮绑定事件

# 如何定位控件

  • 左中右水平对齐
  button.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT  
  button.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_CENTER  
  button.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT  
1
2
3
  • 上中下垂直对齐
  button2.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
  button2.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER
  button2.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_BOTTOM
1
2
3
  • 将控件设置在某个点
  button.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT  
  button.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP
  button.left = '100px'
  button.top = '100px'  
1
2
3
4

# 容器

  const container = new GUI.Container()
  container.background = 'black'
  container.width = 0.5
  container.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT  
  // 阻止container将事件传递到下层  
  container.isPointerBlocker = true
  advancedTexture.addControl(container)
1
2
3
4
5
6
7

有几种类型的容器,其中一种是矩形,它是一个带边框的矩形

  const rectangle = new GUI.Rectangle()
  rectangle.width = '300px'
  rectangle.height = '300px'
  rectangle.cornerRadius = 50
  rectangle.addControl(button2)
  container.addControl(rectangle)
1
2
3
4
5
6

椭圆形容器

  const ellipse = new GUI.Ellipse()
  ellipse.width = '300px'
  ellipse.height = '300px'
  ellipse.thickness = 5
  container.addControl(ellipse)
1
2
3
4
5

堆叠面板 它的特殊之处在于可以自动定位和组织子元素

  const panel = new GUI.StackPanel()
  const b1 = button.clone()
  panel.addControl(b1)
  const b2 = button.clone()
  panel.addControl(b2)
  const b3 = button.clone()
  panel.addControl(b3)
  advancedTexture.addControl(panel)
1
2
3
4
5
6
7
8

调试这些控件的css可以使用babylon的Inspector

Inspector.Show(scene, {})
1

# 让控件粘附在网格上

  panel.linkWithMesh(plane)
  panel.linkOffsetX = -500
  panel.linkOffsetY = 100
1
2
3

# 让控件呈现网格的形状

  const mesh = new BABYLON.MeshBuilder.CreatePlane('',{
    width: 5,
    height: 5
  })
  mesh.position.y = 2
  mesh.rotation.y = Math.PI / 4

  const advancedTexture2 = GUI.AdvancedDynamicTexture.CreateForMesh(mesh)

  const picker = new GUI.ColorPicker()
  picker.width = '500px'
  advancedTexture2.addControl(picker)
1
2
3
4
5
6
7
8
9
10
11
12

  const mesh = new BABYLON.MeshBuilder.CreateSphere('',{
    diameter: 5
  })
  mesh.position.y = 2

  const advancedTexture2 = GUI.AdvancedDynamicTexture.CreateForMesh(mesh)

  const picker = new GUI.ColorPicker()
  picker.width = '500px'
  advancedTexture2.addControl(picker)
1
2
3
4
5
6
7
8
9
10

让控件始终面向摄像机

mesh.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL  
1

我们学会了如何用代码去创建GUI控件,并用Inspector去调试检查

# 图形化拖拽生成GUI

GUI Editor文档 (opens new window)

GUI Editor (opens new window)

编辑完成后点击保存,获取json文件

  const advancedTexture = GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI')
  
  const loadedGUI = await advancedTexture.parseFromURLAsync('/guiTexture.json')
1
2
3

不过目前控件没有绑定事件,我们可以通过名字来获取到对应的控件

const text = advancedTexture.getControlByName('Textblock')
1

剩下的步骤就和前面学的一样了