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
- 将沿着面向相机的平面进行拖动
默认情况下,拖动平面/轴将根据对象的方向进行修改。要将指定的轴/平面固定在世界上,请设置 useObjectOrientationForDragging
为 false
。
pointerDragBehavior.useObjectOrientationForDragging = false;
默认情况下,拖动平面将在每一帧上更新。要禁用此功能,请设置 updateDragPlane
为 false
。
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);
})
要在不移动附加网格的情况下使用拖动行为,请设置 moveAttached
为 false
。然后可以将上面的拖动事件用于自定义拖动交互。
pointerDragBehavior.moveAttached = false;
要禁用所有拖动行为,请设置enabled为 false。
pointerDragBehavior.enabled = false;
要检查拖动网格的当前状态,currentDraggingPointerID
可以检查 dragging
和 lastDragPosition
// 当前与行为交互的指针的 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
种情况下更新:
要么网格超出视野范围。使用 maxViewVerticalDegrees
和 maxViewHorizontalDegrees
调整这些界限。
网格离相机太近或太远。使用 defaultDistance
, minimumDistance
和 maximumDistance
来调整这些距离。
要么网格背对相机。用于 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
。