Babylon.js+WebXR(一)WebXR介绍
作者:互联网
WebXR
前言
W3C出了一套包括但不限于WebVR/WebAR的规范。这个W3C组织名叫Immersive Web,即沉浸式网络,非常确切的概括了WebXR想要实现的效果。组织的目标是通过API将高性能虚拟现实(VR)和增强现实(AR)(统称为XR)引入开放式Web,以便与Web中的传感器和XR设备进行交互。
当前状态
WebXR W3C提案目前处于草案阶段。 然而,它已经在 Chrome 中实现了(查看 caniuse.com 可了解其他浏览器的WebXR实现情况)。 从Chrome的79版本开始,WebVR已被弃用,默认情况下启用WebXR。 早期的Chrome浏览器版本在配置选项里有WebXR选项,可选择打开。 其目标之一是弃用WebVR和其他AR实现,并提供单一的VR和AR API。
由于WebXR API还在不断变化和更新中,所以babylon.js很难跟上其功能和特性的变化。最新的chrome浏览器金丝雀版本(canary)是目前XR功能最完整的浏览器,而且谷歌也在不断持续的更新WebXR新功能。 这是我们引入功能管理器(Features Manager)的主要原因,它允许Babylon.js通过内部版本控制功能去实现WebXR最新版本的官方功能,而不会破坏向后兼容性。
请注意,大多数时候当我们说WebXR时,我们实际上是指VR沉浸式模式(VR immersive mode)下的WebXR。 这是目前WebXR最常用的模式。
设备和浏览器支持
PC
所有微软的混合现实设备使用的windows系统的Chrome 79版本浏览器都官方支持WebXR。 非官方的,WebXR 与 oculus SDK(Rift、Rift S 和 Quest with Link)配合良好。 在撰写本文时,对Oculus的官方支持仍未公布。
手机和Quest
Google Daydream设备使用Chrome浏览器可支持WebXR。
Android 的 Chrome 浏览器(Stable 和 Canary版本)上的 WebXR AR 功能可以在 chrome://flags 打开相应的功能配置标志后启用,包括平面检测、命中测试和锚点等 AR 功能。 请注意,AR功能的架构在不断变化,因此预计不同版本的结果会有所不同。
Oculus Quest设备在最新的oculus浏览器中支持 WebXR(在 VR 模式下)。 Babylon.js的规范实现在quest设备中运行良好。
目前没有正式的 iOS/iPhone 支持计划。 Mozilla 已经构建了一个在IOS系统能够运行的WebXR浏览器(WebXR iOS Viewer),这是一个(非常)受限的面向 AR 的浏览器。
Polyfill
对于支持 WebVR 但不支持 WebXR 的旧浏览器,您可以使用 WebXR Polyfill,它是使用WebXR API接口去实现了WebVR的功能 。 某些功能将无法运行(或将直接返回而不进行任何操作),但基本功能运行OK。
Babylon.js不打算将 polyfill 集成到框架本身或Playground中。 我们鼓励开发人员向那些不使用支持 WebXR 的浏览器的用户提供 polyfill。
要在 Playground 中使用 polyfill,请将以下内容添加到您的 Playground中(在 'createScene'函数之前):
1 const xrPolyfillPromise = new Promise((resolve) => { 2 if (navigator.xr) { 3 return resolve(); 4 } 5 define("polyfill", ["https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js"], (polyfill) => { 6 new polyfill(); 7 resolve(); 8 }); 9 });
然后,确保在初始化 WebXR 之前等待该函数执行完成:
const xrPolyfillPromise = new Promise((resolve) => { if (navigator.xr) { return resolve(); } define("polyfill", ["https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js"], (polyfill) => { new polyfill(); resolve(); }); }); var createScene = async function () { // wait for the polyfill to kick in await xrPolyfillPromise; console.log(navigator.xr); // should be there! console.log(await BABYLON.WebXRSessionManager.IsSessionSupportedAsync("immersive-vr")); // should be true // create your scene var scene = new BABYLON.Scene(engine); var camera = new BABYLON.DeviceOrientationCamera("DevOr_camera", new BABYLON.Vector3(-30, -30, -30), scene); camera.setTarget(BABYLON.Vector3.Zero()); camera.attachControl(canvas, true); var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 0, 0), scene); scale = 100; // initialize XR var xr = await scene.createDefaultXRExperienceAsync(); return scene; };
如果在使用 polyfill 时遇到低分辨率,需要将画布大小调整为更高的分辨率。 这是WebVR的限制(需要调整画布大小),我们集成的WebXR没有这个限制 。
WebXR模拟器
如果您正在开发并且不想经常在真实设备上进行测试,请使用 mozilla 的 WebXR 模拟器,它适用于 chrome 和 firefox浏览器。 我们支持它并在开发过程中实际使用了它。 强烈推荐!
快速入门
最简单的入门方法是使用支持 WebXR 的浏览器并将一行代码添加到您的场景中:
const xr = scene.createDefaultXRExperienceAsync();
这将在 VR 沉浸式模式下(VR immersive mode)启用 WebXR,包括会话初始化、输入源、相机、隐形传态和场景交互。 全部使用我们的 WebXR 默认体验助手(WebXR Default Experience Helper)。
请注意, xr 变量是一个 Promise。 使用 async/await 模式会更简单、更直观。 定义地板网格(floor meshes)也很有意义,这样我们就可以定义我们的地面并在上面移动。 这是 XR 中的一个球体:
var createScene = async function () { var scene = new BABYLON.Scene(engine); var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene); camera.setTarget(BABYLON.Vector3.Zero()); camera.attachControl(canvas, true); 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.position.y = 1; const env = scene.createDefaultEnvironment(); // here we add XR support const xr = await scene.createDefaultXRExperienceAsync({ floorMeshes: [env.ground], }); return scene; };
这样就可以了,是不是很简单?
请务必阅读有关WebXR Experience Helper的更多信息以获取更多提示和技巧,并查看我们的演示和示例。
从WebVR迁移到WebXR
WebVR 已被弃用,并且将很快在大多数浏览器中结束其生命周期。 强烈建议将所有 WebVR 实现移植到 WebXR。
从VR Experience helper迁移
如果您使用了我们的 VR 体验助手(WebVR experience helper),请移除 VR 初始化程序并添加 XR 体验助手(WebXR experience helper)。 所以代码由:
var scene = new BABYLON.Scene(engine); var vrHelper = scene.createDefaultVRExperience();
转变成:
var scene = new BABYLON.Scene(engine); var xrHelper = scene.createDefaultXRExperienceAsync();
默认情况下,WebXR助手具有完整的控制器支持,包括与场景网格、指针事件等的交互。 阅读有关WebXR体验助手的更多信息。
迁移控制器支持
由于 WebXR 控制器不再被视为游戏手柄,因此架构略有不同。
添加的最重要的功能是对控制器的完整指针事件支持。 控制器支持所有指针事件,因此您可以使用指针交互(Pointer interactions),就像在场景中控制鼠标交互一样。
同样需要注意的是,现在可以查询控制器具有哪些功能及其相关的操作。
以下是 VR 控制器最常用的功能,以及如何让它们在 XR 中工作:
1 // On new controller attached: 2 3 // WebVR: 4 webvrCamera.onControllersAttached = (vrController) => { 5 // fun with the new controller, which is a gamepad! 6 }; 7 8 // WebXR: 9 const webXRInput = xr.input; // if using the experience helper, otherwise, an instance of WebXRInput 10 input.onControllerAddedObservable.add((xrController /* WebXRInputSource instance */) => { 11 // more fun with the new controller, since we are in XR! 12 inputSource.onMotionControllerInitObservable.add((motionController) => { 13 // get the motionController, which is similar to but NOT a gamepad: 14 }); 15 // xr supports all types of inputs, so some won't have a motion controller 16 if (!xrController.gamepad) { 17 // using touch, hands, gaze, something else? 18 } 19 }); 20 21 // From this point we assume we have two variables: vrController and xrController. 22 // We also assume motionController is present! 23 24 // main button 25 26 // WebVR: 27 controller.onMainButtonStateChangedObservable.add((newState /* ExtendedGamepadButton */) => { 28 // is the button pressed? 29 if (newState.pressed) { 30 // Do something 31 } 32 }); 33 34 // WebXR: 35 // get the main component (decided by the controller's vendor!) 36 const mainComponent = xrController.motionController.getMainComponent(); 37 // or get the trigger component, if present: 38 const mainTrigger = xrController.motionController.getComponent(WebXRControllerComponent.TRIGGER); 39 mainComponent.onButtonStateChanged.add((component /* WebXRControllerComponent */) => { 40 // check for changes: 41 // pressed changed? 42 if (component.changes.pressed) { 43 // is it pressed? 44 if (component.changes.pressed.current === true) { 45 // pressed 46 } 47 // or a different way: 48 if (component.pressed) { 49 // component is pressed. 50 } 51 } 52 }); 53 54 // thumbpad / touchpad 55 56 // in WebVR - you had to check what controller is being used, but in general this would work: 57 vrController.onPadValuesChangedObservable.add(function (stateObject) { 58 console.log(stateObject); // {x: 0.1, y: -0.3} 59 }); 60 61 // in webXR you can check if it is present and work accordingly: 62 const thumbstick = xrController.motionController.getComponent(WebXRControllerComponent.THUMBSTICK); 63 if (thumbstick) { 64 // Huzza! we have a thumbstick: 65 thumbstick.onButtonStateChanged; // will trigger when the thumbstick is PRESSED or touched! 66 67 thumbstick.onAxisValueChanged; // will trigger when axes of the thumbstick changed 68 } 69 70 // touchpad 71 72 // in WebVR we had "pad" concept which was for both thumbstick and touchpad 73 controller.onPadValuesChangedObservable.add(function (stateObject) { 74 console.log(stateObject); // {x: 0.1, y: -0.3} 75 }); 76 77 // in WebXR, it is much much better: 78 const touchpad = xrController.motionController.getComponent(WebXRControllerComponent.TOUCHPAD); 79 if (touchpad) { 80 // Finally, a controller with a touchpad 81 touchpad.onButtonStateChanged; // will trigger when the touchpad is touched or pressed 82 83 touchpad.onAxisValueChanged; // will trigger when axes of the touchpad changed 84 }
阅读有关XR 控制器系统的更多信息。
兼容性支持
我们始终鼓励向后兼容,我们建议直接使用 WebXR 并停止使用 WebVR 体验助手(WebVR experience helper)。
当然:
最新的 WebVR 体验助手在其初始化选项中有一个新标志 - useXR。 这将检查是否支持WebXR,如果支持,则会在WebXR中启动VR会话。
一个工作示例参见WebVR demo。
源代码如下:
1 var createScene = function () { 2 // Create scene 3 var scene = new BABYLON.Scene(engine); 4 5 // Create simple sphere 6 var sphere = BABYLON.Mesh.CreateIcoSphere( 7 "sphere", 8 { 9 radius: 0.2, 10 flat: true, 11 subdivisions: 1, 12 }, 13 scene, 14 ); 15 sphere.position.y = 3; 16 sphere.material = new BABYLON.StandardMaterial("sphere material", scene); 17 18 // Lights and camera 19 var light = new BABYLON.DirectionalLight("light", new BABYLON.Vector3(0, -0.5, 1.0), scene); 20 light.position = new BABYLON.Vector3(0, 5, -2); 21 var camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 4, 3, new BABYLON.Vector3(0, 3, 0), scene); 22 camera.attachControl(canvas, true); 23 scene.activeCamera.beta += 0.8; 24 25 // Default Environment 26 var environment = scene.createDefaultEnvironment({ 27 enableGroundShadow: true, 28 groundYBias: 2.8, 29 }); 30 environment.setMainColor(BABYLON.Color3.FromHexString("#74b9ff")); 31 32 // Shadows 33 var shadowGenerator = new BABYLON.ShadowGenerator(1024, light); 34 shadowGenerator.useBlurExponentialShadowMap = true; 35 shadowGenerator.blurKernel = 32; 36 shadowGenerator.addShadowCaster(sphere, true); 37 38 // Enable VR, use XR when possible 39 var vrHelper = scene.createDefaultVRExperience({ 40 createDeviceOrientationCamera: false, 41 useXR: true, // This will enable XR if supported 42 floorMeshes: [environment.ground], 43 }); 44 45 // Runs every frame to rotate the sphere 46 scene.onBeforeRenderObservable.add(() => { 47 sphere.rotation.y += 0.0001 * scene.getEngine().getDeltaTime(); 48 sphere.rotation.x += 0.0001 * scene.getEngine().getDeltaTime(); 49 }); 50 51 // GUI 52 var plane = BABYLON.Mesh.CreatePlane("plane", 1); 53 plane.position = new BABYLON.Vector3(0.4, 4, 0.4); 54 var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(plane); 55 var panel = new BABYLON.GUI.StackPanel(); 56 advancedTexture.addControl(panel); 57 var header = new BABYLON.GUI.TextBlock(); 58 header.text = "Color GUI"; 59 header.height = "100px"; 60 header.color = "white"; 61 header.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER; 62 header.fontSize = "120"; 63 panel.addControl(header); 64 var picker = new BABYLON.GUI.ColorPicker(); 65 picker.value = sphere.material.diffuseColor; 66 picker.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER; 67 picker.height = "350px"; 68 picker.width = "350px"; 69 // This will work in XR, since we are using native pointer events! 70 picker.onValueChangedObservable.add(function (value) { 71 sphere.material.diffuseColor.copyFrom(value); 72 }); 73 panel.addControl(picker); 74 75 vrHelper.onAfterEnteringVRObservable.add(() => { 76 // This callback will still work! Would be better to use the XR native observables. 77 }); 78 79 return scene; 80 };
颜色选择器(The color picker)使用指针架构(The pointer architecture)来工作,用户点击(point)不同颜色区域,可以选择不用的颜色。 如果存在 XR,则将使用 XR。 否则,它将使用 WebVR 作为后备。
请注意,WebVR的某些功能将无法正常工作或根本无法工作。 例如,相机凝视(camera gaze)功能根本不起作用。 控制器可以工作,但由于交互架构不同,您很可能需要调整一些观察者(observers)才能使其工作,特别是专门针对VR的控制器回调。
我们建议在不支持WebXR的浏览器中,使用WebXR polyfill代替WebVR 体验助手(WebVR experience helper)进行WebVR开发。
PS:
1)本文翻译自babylon.js官方WebXR文档,翻译用于自学和巩固知识,也希望能给有需要的人一点帮助;
2)阅读本文,需要具备一定的Web JavaScript,babylon.js,以及WebVR开发基础。
翻译若有不当之处,请指正。
标签:WebVR,Babylon,scene,WebXR,var,new,js,BABYLON 来源: https://www.cnblogs.com/muliublog/p/14982660.html