Skip to content

GUI

GUI介绍

GUI 系统允许开发者创建用户界面(UI),以与 3D 场景中的对象进行交互。
GUI 主要由 AdvancedDynamicTexture 和 Control 类及其子类组成。
Babylon官网提供了一个在线GUI编辑器,https://gui.babylonjs.com/
image

AdvancedDynamicTexture

AdvancedDynamicTexture 是一个可以容纳多个控件的纹理。可以把它看作是一个容器,可以在其中添加按钮、文本框、图像等控件。

Control

Control 是所有 GUI 控件的基类。它包含一些基本的属性和方法,如位置、大小、颜色等。

常见的 Control 子类

  Button: 一个可以点击的按钮。
  TextBlock: 用于显示文本的控件。
  Image: 显示图像的控件。
  Slider: 允许用户通过滑动来选择值的控件。
  CheckBox: 一个可以选中或取消选中的复选框。
  RadioButton: 一组中的一个选项,用户可以从中选择一个。
  ColorPicker: 允许用户选择颜色的控件。

GUI的创建方式

GUI 通常涉及以下步骤:

1、创建 AdvancedDynamicTexture:
  创建一个 AdvancedDynamicTexture 实例,并指定其大小和其他属性。
2、添加 Control:
  创建并配置各种 Control 实例,并将其添加到 AdvancedDynamicTexture 中。
3、处理事件:
  对于像按钮这样的交互式控件,需要添加事件监听器来处理用户交互。

方式一:全屏模式,只能创建一个

javascript
// GUI
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.
CreateFullscreenUI('UI',true);
//渲染分辨率和纹理大小之间的比率为 1。但可以使用
//advancedTexture.renderScale. 例如,如果想要更清晰的文本,这可能会很有用。
//设置分辨率
advancedTexture.idealWidth = 500
advancedTexture.idealHeight = 500
const button1=BABYLON.GUI.Button.CreateSimpleButton('btn','按钮')
button1.width = 5
button1.height = 1
button1.color = 'white'
button1.background = 'red'
button1.fontSize = 50
button1.onPointerUpObservable.add(function(){
  sphere.scaling.y = 5
})

// 追踪model的位置来定位,放大缩小移动屏幕,button1也会跟随model
button1.linkWithMesh(model)

advancedTexture.addControl(button1)

方式二:纹理模式

javascript
const advancedTexture1 = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(
    plane,
    1024,
    1024,
    false
)
const button1 = BABYLON.GUI.Button.CreateSimpleButton('btn','按钮')
button1.width = 5
button1.height = 1
button1.color = 'white'
button1.background = 'red'
button1.fontSize = 50
button1.onPointerUpObservable.add(function(){
    sphere.scaling.y = 5
})
advancedTexture1.addControl(button1)

在复杂的网格上处理指针移动事件可能代价高昂,因此可以使用第四个参数关闭支持指针移动事件。

observables属性

所有控件都有以下 observables:
onPointerMoveObservable:当光标移到控件上时引发。仅在全屏模式下可用。
onPointerEnterObservable:当光标进入控件时引发。仅在全屏模式下可用。
onPointerOutObservable:当光标离开控件时引发。仅在全屏模式下可用。
onPointerDownObservable:当指针在控件上向下时引发。
onPointerUpObservable:当指针在控件上时引发。
onPointerClickObservable:单击控件时引发。
onClipboardObservable:在触发剪贴板事件时引发。

粘贴板示例:

javascript
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI');
//设置分辨率
advancedTexture.idealWidth=500
advancedTexture.idealHeight=500
//即使设置了理想尺寸,全屏 UI 也会以与画布相同的分辨率呈现
//但可以决定(主要是出于性能原因)强制纹理也使用理想尺寸的分辨率
advancedTexture.renderAtIdealSize = true
const textblock = new BABYLON.GUI.TextBlock();
textblock.text = '复制(ctr+c)\n 点击网格';
textblock.fontSize = 24;
textblock.top = -100;
textblock.color = 'white';
advancedTexture.addControl(textblock);

//注册粘贴板事件
advancedTexture.registerClipboardEvents();

//将事件监听器添加到粘贴板的observabel
advancedTexture.onClipboardObservable.add((ev) => {
    //复制事件
    if (ev.type === BABYLON.ClipboardEventTypes.COPY){
        let pick = scene.pick(scene.pointerX, scene.pointerY);
        if (pick.hit){
            //SceneSerializer:场景序列化,SerializeMesh:序列化网格
            let selializedData =   BABYLON.SceneSerializer.SerializeMesh(pick.pickedMesh);
            let blob = new Blob([JSON.stringify(selializedData)], {type: 'application/json;charset=utf-8'});
            let url = URL.createObjectURL(blob);
            //将二进制数据流添加到粘贴板
            ev.event.clipboardData.setData('text/uri-list', url);
            textblock.text = 'ctr+v粘贴\n' + pick.pickedMesh.name;
        }
        
    }
    //粘贴事件
    if (ev.type === BABYLON.ClipboardEventTypes.PASTE){
        //粘贴板数据中存在text/uri-list
        if (ev.event.clipboardData.types.indexOf('text/uri-list') > -1){
            let blobURL = ev.event.clipboardData.getData('text/uri-list');
            //SceneLoader:场景阅读器
            BABYLON.SceneLoader.ImportMesh('', '', blobURL, scene,
                function(meshes){
                let position = new BABYLON.Vector3(Math.random() * 10 +
                Math.random() * (-10), Math.random() * 10 +
                Math.random() * (-10), Math.random() * 10);
                meshes[0].position = position;
            });
            textblock.text = '';
        }
    }
});

/* 
* 30秒后取消注册,这不是必需的,但在以下情况下很有用:
* 具有相同键绑定的任何其他事件。
*/
setTimeout(() => {
    textblock.text = '粘贴结束'
    //删除粘贴板事件
    advancedTexture.unRegisterClipboardEvents();
}, 60000);

鼠标的observables示例:

javascript
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI');
//设置分辨率
advancedTexture.idealWidth=500
advancedTexture.idealHeight=500
const panel = new BABYLON.GUI.StackPanel();    
advancedTexture.addControl(panel);   

const button = BABYLON.GUI.Button.CreateSimpleButton('but', 'Click Me');
button.width = 0.2;
button.height = '40px';
button.color = 'white';
button.background = 'green';
//右对齐
/*
*取值值可以取自BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_*
*BABYLON.GUI.Control.VERTICAL_ALIGNMENT_*
*/
button.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;
button.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;

let text = 0
button.onPointerDownObservable.add(function() {
    textblock.text = 'Down!';
});
button.onPointerUpObservable.add(function() {
    textblock.text = 'Up!';
    text += 1
    button.children[0].text='单机次数'+text
});
button.onPointerEnterObservable.add(function() {
    textblock.text = 'Enter!';
});
button.onPointerOutObservable.add(function() {
    textblock.text = 'Out!';
});    
button.onPointerMoveObservable.add(function(coordinates) {
    const relative = button.getLocalCoordinates(coordinates);
    textblock.text = relative.x + ', ' + relative.y;
});    
panel.addControl(button);