Babylon.js 深入 - 第 3 章 - 行为(2)

Babylon.js 的行为系统允许开发者为场景中的对象添加交互性。本文介绍了如何使用 PointerDragBehavior 实现网格拖动,SixDofDragBehavior 进行六自由度拖动,MultiPointerScaleBehavior 处理多指缩放,以及 AttachToBoxBehavior 创建应用栏。此外,还展示了如何结合VR和3DUI进行更复杂的交互设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Babylon.js 深入 - 第 3 章 - 行为(2)

行为

行为是 Babylon.js v3.1 引入的一个新的基于组件的工具。行为是一个简单的类,可以附加到一个目标上,它将提供一组特定的功能。功能将由定义的事件触发。

通常

行为由以下接口定义:

  • name - 返回行为的名称。
  • init() - 当需要初始化行为时将调用此函数,这发生在附加到目标之前。
  • attach(target) - 当行为附加到目标时,将调用此函数,这是行为将与有用事件挂钩的地方,当调用此函数时,Babylon.js 将确保场景当前未加载。
  • detach() - 当行为与目标分离时,将调用此函数,该行为必须清除所有关联的资源并取消挂钩所有事件。

如果行为依赖于动画,则可以使用以下静态属性:

  • EasingFunction - 定义缓动函数使用的动画
  • EasingMode - 定义动画使用的缓动模式

您可以将行为添加到任何实现 IBehaviorAware 接口的对象(例如灯光、相机或网格)。每个 IBehaviorAware 都提供以下入口点:

  • addBehavior(behavior) - 使用此函数将行为附加到给定目标,如果场景当前正在加载,此代码将延迟到场景完成。
  • removeBehavior(behavior) - 使用此函数将行为与目标分离。
  • getBehaviorByName(name) - 返回具有给定名称的行为,如果未找到则返回 null
  • behaviors - 此只读属性返回与目标关联的行为列表。

大多数时候,行为旨在处理特定类型的目标。

有相机和网格行为。

网格行为

介绍

网格行为是可以附加到网格的行为。

指针拖动行为(PointerDragBehavior)

这用于使用鼠标或 VR 控制器围绕平面或轴拖动网格。

var pointerDragBehavior = new BABYLON.PointerDragBehavior({
    dragAxis: new BABYLON.Vector3(0, 1, 0)
});

它可以在 3 种不同的模式下初始化:

  • dragAxis - 将沿着提供的轴进行拖动
  • dragPlaneNormal- -拖动将沿着法线定义的平面发生
  • None - 将沿着面向相机的平面进行拖动

默认情况下,拖动平面/轴将根据对象的方向进行修改。要将指定的轴/平面固定在世界上,请设置 useObjectOrientationForDraggingfalse

pointerDragBehavior.useObjectOrientationForDragging = false;

默认情况下,拖动平面将在每一帧上更新。要禁用此功能,请设置 updateDragPlanefalse

pointerDragBehavior.updateDragPlane = false;

要监听拖动事件,可以使用以下内容。

pointerDragBehavior.onDragStartObservable.add((event) => {
    console.log("dragStart");
    console.log(event);
})
pointerDragBehavior.onDragObservable.add((event) => {
    console.log("drag");
    console.log(event);
})
pointerDragBehavior.onDragEndObservable.add((event) => {
    console.log("dragEnd");
    console.log(event);
})

要在不移动附加网格的情况下使用拖动行为,请设置 moveAttachedfalse。然后可以将上面的拖动事件用于自定义拖动交互。

pointerDragBehavior.moveAttached = false;

要禁用所有拖动行为,请设置enabled为 false。

pointerDragBehavior.enabled = false;

要检查拖动网格的当前状态,currentDraggingPointerID 可以检查 dragginglastDragPosition

// 当前与行为交互的指针的 id(当没有指针处于活动状态时为 -1)
pointerDragBehavior.currentDraggingPointerID;
// 指针在世界空间中碰到拖动平面的最后一个位置
pointerDragBehavior.lastDragPosition;
// 如果行为当前处于拖动状态
pointerDragBehavior.dragging;

沿轴拖动的示例:

示例链接

示例代码:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Babylon.js sample code</title>
    <!-- Babylon.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://preview.babylonjs.com/ammo.js"></script>
    <script src="https://preview.babylonjs.com/cannon.js"></script>
    <script src="https://preview.babylonjs.com/Oimo.js"></script>
    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
    <script src="https://preview.babylonjs.com/babylon.js"></script>
    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
    <style>
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
            touch-action: none;
        }
    </style>
</head>

<body>
    <canvas id="renderCanvas"></canvas>
    <script>
        var canvas = document.getElementById("renderCanvas");
        var startRenderLoop = function (engine, canvas) {
            engine.runRenderLoop(function () {
                if (sceneToRender && sceneToRender.activeCamera) {
                    sceneToRender.render();
                }
            });
        }
        var engine = null;
        var scene = null;
        var sceneToRender = null;
        var createDefaultEngine = function () {
            return new BABYLON.Engine(canvas, true, {
                preserveDrawingBuffer: true,
                stencil: true,
                disableWebGL2Support: false
            });
        };
        var createScene = function () {
            // 创建基本场景
            var scene = new BABYLON.Scene(engine);
            var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(1, 5, -10), scene);
            camera.setTarget(BABYLON.Vector3.Zero());
            var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            light.intensity = 0.7;
            var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
            sphere.rotation.x = Math.PI / 2
            sphere.position.y = 1;
            var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
            // 在所需模式下创建指针拖动行为
            //var pointerDragBehavior = new BABYLON.PointerDragBehavior({});
            //var pointerDragBehavior = new BABYLON.PointerDragBehavior({dragPlaneNormal: new BABYLON.Vector3(0,1,0)});
            var pointerDragBehavior = new BABYLON.PointerDragBehavior({
                dragAxis: new BABYLON.Vector3(1, 0, 0)
            });
            // 在世界空间中使用拖动平面
            pointerDragBehavior.useObjectOrientationForDragging = false;
            // 监听拖动事件
            pointerDragBehavior.onDragStartObservable.add((event) => {
                console.log("dragStart");
                console.log(event);
            })
            pointerDragBehavior.onDragObservable.add((event) => {
                console.log("drag");
                console.log(event);
            })
            pointerDragBehavior.onDragEndObservable.add((event) => {
                console.log("dragEnd");
                console.log(event);
            })
            // 如果需要手动处理拖动事件,请将 moveAttached 设置为 false
            // pointerDragBehavior.moveAttached = false;
            sphere.addBehavior(pointerDragBehavior);
            return scene;
        };
        window.initFunction = async function () {
            var asyncEngineCreation = async function () {
                try {
                    return createDefaultEngine();
                } catch (e) {
                    console.log(
                        "the available createEngine function failed. Creating the default engine instead"
                    );
                    return createDefaultEngine();
                }
            }
            window.engine = await asyncEngineCreation();
            if (!engine) throw 'engine should not be null.';
            startRenderLoop(engine, canvas);
            window.scene = createScene();
        };
        initFunction().then(() => {
            sceneToRender = scene
        });
        // Resize
        window.addEventListener("resize", function () {
            engine.resize();
        });
    </script>
</body>

</html>

六自由度拖动行为

这用于根据指针的原点(例如相机或 VR 控制器位置)在 3D 空间中拖动网格。

var sixDofDragBehavior = new BABYLON.SixDofDragBehavior();

默认情况下,通过将网格缓慢移动到指针指向的位置来平滑指针抖动。要删除或修改此行为,可以修改以下字段。

// 每帧移动到目标拖动位置的距离。这对于避免抖动很有用。将此设置为 1 无延迟。(默认值:0.2)
sixDofDragBehavior.dragDeltaRatio = 0.2;

默认情况下,将对象拖离/拖向您将被放大以使移动对象更容易远距离。为了避免/修改这种情况,可以使用以下内容。

// 每帧移动到目标拖动位置的距离。这对于避免抖动很有用。将此设置为 1 无延迟。(默认值:0.2)
sixDofDragBehavior.zDragFactor = 0.2;

注意:为避免在使用具有复杂几何形状的模型时对性能造成较大影响,应将对象包裹在边界框网格中

六个方向的示例:

示例链接

示例代码:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Babylon.js sample code</title>
    <!-- Babylon.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://preview.babylonjs.com/ammo.js"></script>
    <script src="https://preview.babylonjs.com/cannon.js"></script>
    <script src="https://preview.babylonjs.com/Oimo.js"></script>
    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
    <script src="https://preview.babylonjs.com/babylon.js"></script>
    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
    <style>
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
            touch-action: none;
        }
    </style>
</head>

<body>
    <canvas id="renderCanvas"></canvas>
    <script>
        var canvas = document.getElementById("renderCanvas");
        var startRenderLoop = function (engine, canvas) {
            engine.runRenderLoop(function () {
                if (sceneToRender && sceneToRender.activeCamera) {
                    sceneToRender.render();
                }
            });
        }
        var engine = null;
        var scene = null;
        var sceneToRender = null;
        var createDefaultEngine = function () {
            return new BABYLON.Engine(canvas, true, {
                preserveDrawingBuffer: true,
                stencil: true,
                disableWebGL2Support: false
            });
        };
        var createScene = function () {
            // 创建基本世界
            var scene = new BABYLON.Scene(engine);
            var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -5), scene);
            camera.setTarget(BABYLON.Vector3.Zero());
            camera.attachControl(canvas, true);
            var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
            ground.position.y = -1
            scene.createDefaultVRExperience({
                floorMeshes: []
            })
            BABYLON.SceneLoader.LoadAssetContainer("https://models.babylonjs.com/", "seagulf.glb", scene, function (
                container) {
                // 将加载的文件添加到场景中
                container.addAllToScene();
                // 缩放和定位加载的模型(从 gltf 加载的第一个网格是根节点)
                container.meshes[0].scaling.scaleInPlace(0.002)
                // 包裹在边界框网格中以避免拾取性能命中
                var gltfMesh = container.meshes[0]
                var boundingBox = BABYLON.BoundingBoxGizmo.MakeNotPickableAndWrapInBoundingBox(gltfMesh)
                // 创建边界框 Gizmo
                var utilLayer = new BABYLON.UtilityLayerRenderer(scene)
                utilLayer.utilityLayerScene.autoClearDepthAndStencil = false;
                var gizmo = new BABYLON.BoundingBoxGizmo(BABYLON.Color3.FromHexString("#0984e3"), utilLayer)
                gizmo.attachedMesh = boundingBox;
                // 在 VR 中创建行为以使用指针进行拖动和缩放
                var sixDofDragBehavior = new BABYLON.SixDofDragBehavior()
                boundingBox.addBehavior(sixDofDragBehavior)
                var multiPointerScaleBehavior = new BABYLON.MultiPointerScaleBehavior()
                boundingBox.addBehavior(multiPointerScaleBehavior)
            });
            return scene;
        };
        window.initFunction = async function () {
            var asyncEngineCreation = async function () {
                try {
                    return createDefaultEngine();
                } catch (e) {
                    console.log(
                        "the available createEngine function failed. Creating the default engine instead"
                    );
                    return createDefaultEngine();
                }
            }
            window.engine = await asyncEngineCreation();
            if (!engine) throw 'engine should not be null.';
            startRenderLoop(engine, canvas);
            window.scene = createScene();
        };
        initFunction().then(() => {
            sceneToRender = scene
        });
        // Resize
        window.addEventListener("resize", function () {
            engine.resize();
        });
    </script>
</body>

</html>

多指针缩放行为

这用于基于 2 个指针(例如手指或 VR 控制器)缩放网格。

var multiPointerScaleBehavior = new BABYLON.MultiPointerScaleBehavior();

注意:为避免在使用具有复杂几何形状的模型时对性能造成较大影响,应将对象包裹在边界框网格中。

多指针缩放行为的示例:

示例链接

示例代码:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Babylon.js sample code</title>
    <!-- Babylon.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://preview.babylonjs.com/ammo.js"></script>
    <script src="https://preview.babylonjs.com/cannon.js"></script>
    <script src="https://preview.babylonjs.com/Oimo.js"></script>
    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
    <script src="https://preview.babylonjs.com/babylon.js"></script>
    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
    <style>
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
            touch-action: none;
        }
    </style>
</head>

<body>
    <canvas id="renderCanvas"></canvas>
    <script>
        var canvas = document.getElementById("renderCanvas");
        var startRenderLoop = function (engine, canvas) {
            engine.runRenderLoop(function () {
                if (sceneToRender && sceneToRender.activeCamera) {
                    sceneToRender.render();
                }
            });
        }
        var engine = null;
        var scene = null;
        var sceneToRender = null;
        var createDefaultEngine = function () {
            return new BABYLON.Engine(canvas, true, {
                preserveDrawingBuffer: true,
                stencil: true,
                disableWebGL2Support: false
            });
        };
        var createScene = function () {
            // 创建基本世界
            var scene = new BABYLON.Scene(engine);
            var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -5), scene);
            camera.setTarget(BABYLON.Vector3.Zero());
            camera.attachControl(canvas, true);
            var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
            ground.position.y = -1
            scene.createDefaultVRExperience({
                floorMeshes: []
            })
            BABYLON.SceneLoader.LoadAssetContainer("https://models.babylonjs.com/", "seagulf.glb", scene, function (
                container) {
                // 将加载的文件添加到场景中
                container.addAllToScene();
                // 缩放和定位加载的模型(从 gltf 加载的第一个网格是根节点)
                container.meshes[0].scaling.scaleInPlace(0.002)
                // 包裹在边界框网格中以避免拾取性能命中
                var gltfMesh = container.meshes[0]
                var boundingBox = BABYLON.BoundingBoxGizmo.MakeNotPickableAndWrapInBoundingBox(gltfMesh)
                // 创建边界框 Gizmo
                var utilLayer = new BABYLON.UtilityLayerRenderer(scene)
                utilLayer.utilityLayerScene.autoClearDepthAndStencil = false;
                var gizmo = new BABYLON.BoundingBoxGizmo(BABYLON.Color3.FromHexString("#0984e3"), utilLayer)
                gizmo.attachedMesh = boundingBox;
                // 在 VR 中创建行为以使用指针进行拖动和缩放
                var sixDofDragBehavior = new BABYLON.SixDofDragBehavior()
                boundingBox.addBehavior(sixDofDragBehavior)
                var multiPointerScaleBehavior = new BABYLON.MultiPointerScaleBehavior()
                boundingBox.addBehavior(multiPointerScaleBehavior)
            });
            return scene;
        };
        window.initFunction = async function () {
            var asyncEngineCreation = async function () {
                try {
                    return createDefaultEngine();
                } catch (e) {
                    console.log(
                        "the available createEngine function failed. Creating the default engine instead"
                    );
                    return createDefaultEngine();
                }
            }
            window.engine = await asyncEngineCreation();
            if (!engine) throw 'engine should not be null.';
            startRenderLoop(engine, canvas);
            window.scene = createScene();
        };
        initFunction().then(() => {
            sceneToRender = scene
        });
        // Resize
        window.addEventListener("resize", function () {
            engine.resize();
        });
    </script>
</body>

</html>

附加到框行为(应用栏)

这用于在网格的边界框顶部附加网格或 UI

var behavior = new BABYLON.AttachToBoxBehavior(appBar);
boundingBox.addBehavior(behavior);

要调整附加网格的位置,请使用以下命令。

behavior.distanceAwayFromFace = 0.15;
behavior.distanceAwayFromBottomOfFace = 0.15;

这可用于将应用栏附加到网格。

图片地址

附加到框行为的示例:

示例链接

示例代码:

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Babylon.js sample code</title>
    <!-- Babylon.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://preview.babylonjs.com/ammo.js"></script>
    <script src="https://preview.babylonjs.com/cannon.js"></script>
    <script src="https://preview.babylonjs.com/Oimo.js"></script>
    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
    <script src="https://preview.babylonjs.com/babylon.js"></script>
    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
    <style>
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
            touch-action: none;
        }
    </style>
</head>

<body>
    <canvas id="renderCanvas"></canvas>
    <script>
        var canvas = document.getElementById("renderCanvas");
        var startRenderLoop = function (engine, canvas) {
            engine.runRenderLoop(function () {
                if (sceneToRender && sceneToRender.activeCamera) {
                    sceneToRender.render();
                }
            });
        }
        var engine = null;
        var scene = null;
        var sceneToRender = null;
        var createDefaultEngine = function () {
            return new BABYLON.Engine(canvas, true, {
                preserveDrawingBuffer: true,
                stencil: true,
                disableWebGL2Support: false
            });
        };
        var createScene = function () {
            // 创建基本世界
            var scene = new BABYLON.Scene(engine);
            var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -5), scene);
            camera.setTarget(BABYLON.Vector3.Zero());
            camera.attachControl(canvas, true);
            var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
            ground.position.y = -1
            scene.createDefaultVRExperience({
                floorMeshes: []
            })
            BABYLON.SceneLoader.LoadAssetContainer("https://models.babylonjs.com/", "seagulf.glb", scene, function (
                container) {
                // 创建 3D UI 管理器
                var manager = new BABYLON.GUI.GUI3DManager(scene);
                // 将加载的文件添加到场景中
                container.addAllToScene();
                // 缩放和定位加载的模型(从 gltf 加载的第一个网格是根节点)
                container.meshes[0].scaling.scaleInPlace(0.002)
                // 包裹在边界框网格中以避免拾取性能命中
                var gltfMesh = container.meshes[0]
                var boundingBox = BABYLON.BoundingBoxGizmo.MakeNotPickableAndWrapInBoundingBox(gltfMesh)
                // 创建边界框 Gizmo
                var utilLayer = new BABYLON.UtilityLayerRenderer(scene)
                utilLayer.utilityLayerScene.autoClearDepthAndStencil = false;
                var gizmo = new BABYLON.BoundingBoxGizmo(BABYLON.Color3.FromHexString("#0984e3"), utilLayer)
                gizmo.attachedMesh = boundingBox;
                // 在 VR 中创建行为以使用指针进行拖动和缩放
                var sixDofDragBehavior = new BABYLON.SixDofDragBehavior()
                boundingBox.addBehavior(sixDofDragBehavior)
                var multiPointerScaleBehavior = new BABYLON.MultiPointerScaleBehavior()
                boundingBox.addBehavior(multiPointerScaleBehavior)
                // 创建应用栏
                var appBar = new BABYLON.TransformNode("");
                appBar.scaling.scaleInPlace(0.2)
                var panel = new BABYLON.GUI.PlanePanel();
                panel.margin = 0;
                panel.rows = 1;
                manager.addControl(panel);
                panel.linkToTransformNode(appBar);
                for (var index = 0; index < 2; index++) {
                    var button = new BABYLON.GUI.HolographicButton("orientation");
                    panel.addControl(button);
                    button.text = "Button #" + panel.children.length;
                    if (index == 0) {
                        button.onPointerClickObservable.add(() => {
                            if (gizmo.attachedMesh) {
                                gizmo.attachedMesh = null;
                                boundingBox.removeBehavior(sixDofDragBehavior)
                                boundingBox.removeBehavior(multiPointerScaleBehavior)
                            } else {
                                gizmo.attachedMesh = boundingBox;
                                boundingBox.addBehavior(sixDofDragBehavior)
                                boundingBox.addBehavior(multiPointerScaleBehavior)
                            }
                        })
                    }
                }
                // 将应用栏附加到边界框
                var behavior = new BABYLON.AttachToBoxBehavior(appBar);
                boundingBox.addBehavior(behavior);
            });
            return scene;
        };
        window.initFunction = async function () {
            var asyncEngineCreation = async function () {
                try {
                    return createDefaultEngine();
                } catch (e) {
                    console.log(
                        "the available createEngine function failed. Creating the default engine instead"
                    );
                    return createDefaultEngine();
                }
            }
            window.engine = await asyncEngineCreation();
            if (!engine) throw 'engine should not be null.';
            startRenderLoop(engine, canvas);
            window.scene = createScene();
        };
        initFunction().then(() => {
            sceneToRender = scene
        });
        // Resize
        window.addEventListener("resize", function () {
            engine.resize();
        });
    </script>
</body>

</html>

跟随行为

这用于使网格跟随相机。

var followBehavior = new BABYLON.FollowBehavior();
followBehavior.attach(mesh);

网格的位置/旋转将在 3 种情况下更新:

要么网格超出视野范围。使用 maxViewVerticalDegreesmaxViewHorizontalDegrees 调整这些界限。
网格离相机太近或太远。使用 defaultDistance, minimumDistancemaximumDistance 来调整这些距离。
要么网格背对相机。用于 orientToCameraDeadzoneDegrees 限定网格可以背向的最大角度。
在 XR 体验中,不考虑用户的完整头部旋转可能很有用。使用该属性 ignoreCameraPitchAndRoll 仅考虑头部的偏航(绕 Y 轴旋转)。在此模式下,您可以使用 pitchOffset, 将网格略微置于水平面之下或之上。

像一样 SixDofDragBehavior,网格的每个变换都被插值以避免抖动。用于 lerpTime 调整插值的长度(越高越慢)。

表面磁性行为

这用于使网格粘到另一个网格上,并沿其法线定向。例如,它可以用于 XR 体验,以使 UI 控件粘在墙上。

该属性 meshes 是我们应该将其视为相交的网格列表。

var surfaceMagnetismBehavior = new BABYLON.SurfaceMagnetismBehavior();
surfaceMagnetismBehavior.attach(mesh);
surfaceMagnetismBehavior.meshes = meshes;

默认情况下,meshes 每次指针移动时它都会相交,并且位置会相应更新(使用插值,如使用 FollowBehavior)。使用该标志 enabled 来控制此行为是否应该发挥作用。

手约束行为

这用于使网格跟随用户的手。它应该始终链接到 WebXRDefaultExperience 以获取手的位置。XR 体验还应该启用 HandTracking 功能,如下所示:

xr.baseExperience.featuresManager.enableFeature(BABYLON.WebXRFeatureName.HAND_TRACKING, "latest", {
    xrInput: xr.input
});

然后您可以实例化行为,将其附加到网格,并将其链接到 XR 体验:

var handConstraintBehavior = new BABYLON.HandConstraintBehavior();
handConstraintBehavior.attach(mesh);
handConstraintBehavior.linkToXRExperience(xr);

您可以更改它应该跟随属性的手 handedness

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MossGrower

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值