Babylon.js+WebXR(二)WebXR的AR功能特性


WebXR的AR功能特性

關於增強現實(AR)

增強現實(AR)背后的想法很簡單——展示真實世界,但可以在真實世界中添加信息。

這點與虛擬現實(VR)不同,虛擬現實讓你完全沉浸在不同的場景中,與現實世界沒有實際接觸,增強現實讓你與現實世界互動。

快速入門

WebXR和AR

使用Babylon.js構建增強現實(AR)將大量使用WebXR,所以我建議您首先開始使用WebXR入門指南。

大多數對沉浸式VR會話有效的信息也對沉浸式AR會話有效。這里將解釋兩者之間的幾個主要區別。

 支持設備

沉浸式AR會話(目前)在兩種類型的設備上得到支持——手機和Hololens上的firefox reality瀏覽器。

使用android的手機支持chrome(穩定/金絲雀版本)上的沉浸式AR會話。請注意,您將需要安裝AR Core,否則這將是一個非常短暫的體驗。

Hololens 2在使用Firefox Reality for Hololens時支持WebXR和沉浸式AR會話。

要在桌面上檢查場景,可以使用WebXR emulator,它支持AR的一組功能,並允許您在選擇移動模式時進入沉浸式AR會話。

沉浸式AR(immersive AR)中的簡單場景示例

最簡單的沉浸式AR示例如下所示:

 1 var createScene = async function () {
 2   var scene = new BABYLON.Scene(engine);
 3   var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
 4   camera.setTarget(BABYLON.Vector3.Zero());
 5   camera.attachControl(canvas, true);
 6   var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
 7   light.intensity = 0.7;
 8   var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
 9   sphere.position.y = 2;
10   sphere.position.z = 5;
11 
12   const xr = await scene.createDefaultXRExperienceAsync({
13     // ask for an ar-session
14     uiOptions: {
15       sessionMode: "immersive-ar",
16     },
17   });
18 
19   return scene;
20 };

官方Playground的簡單AR示例鏈接:simple immersive AR scene

我們可以注意到,AR示例中沒有創建任何環境。

與沉浸式VR會話相反,AR不需要天空盒或地面。

如果您想在進入AR模式時將已經定義好的地面移除(例如,如果您開發的應用同時支持桌面和AR兩種模式),您可以使用本頁后面描述的背景移除功能。

AR特性

一些AR的功能特性需要在最新的chrome canary版本中啟動相關配置。訪問chrome://flags/瀏覽器配置頁面,並啟用WebXR incubation配置選項。

然后,您需要在您的代碼中讓WebXR啟用這些功能特性。這可以使用default experience helper中的optionalFeature參數完成:

1 const xr = await scene.createDefaultXRExperienceAsync({
2   uiOptions: {
3     sessionMode: "immersive-ar",
4   },
5   optionalFeatures: true, 6 });

上述代碼將啟用我們支持的所有可選功能。您也可以使用數組來定制添加自己需要的功能特性:

1 const xr = await scene.createDefaultXRExperienceAsync({
2   uiOptions: {
3     sessionMode: "immersive-ar",
4   },
5   optionalFeatures: ["hit-test", "anchors"],
6 });

Hit test

Hit-test(命中測試)用於向現實世界發送光線,並接收有關空間相交的信息。您可以在hit test w3c draft中了解它。

想象一條光線從您的手機屏幕向您正在尋找的物體發射。如果設備的AR功能允許,您將知道相交點相對於您的位置和方向。

啟用hit-testing,需要在初始化XR后添加此如下代碼:

1 // featuresManager from the base webxr experience helper
2 const hitTest = featuresManager.enableFeature(BABYLON.WebXRHitTest, "latest");

在typescript中,您還可以獲取正確設置的類型:

1 // featuresManager from the base webxr experience helper
2 const hitTest = featuresManager.enableFeature(BABYLON.WebXRHitTest, 'latest') as BABYLON.WebXRHitTest;

啟用hit-testing后的默認行為,即在每一幀上從顯示器中心向前發送一條hit-test ray。

如下接口描述了您可以傳遞的可選參數:

 1 export interface IWebXRHitTestOptions {
 2   /**
 3    * Do not create a permanent hit test. Will usually be used when only
 4    * transient inputs are needed.
 5    */
 6   disablePermanentHitTest?: boolean;
 7   /**
 8    * Enable transient (for example touch-based) hit test inspections
 9    */
10   enableTransientHitTest?: boolean;
11   /**
12    * Offset ray for the permanent hit test
13    */
14   offsetRay?: Vector3;
15   /**
16    * Offset ray for the transient hit test
17    */
18   transientOffsetRay?: Vector3;
19   /**
20    * Instead of using viewer space for hit tests, use the reference space defined in the session manager
21    */
22   useReferenceSpace?: boolean;
23 }

 disablePermanentHitTest選項將禁用持續hit-testing,而enableTransientHitTest選項將在觸摸屏幕時啟用hit-testing。offsets幾個參數代表偏移,定義光線發射起點的偏移量(相對於設備視圖的中心)。

啟用hit-testing功能后,您可以注冊OnHitTestResultoServable函數以獲取hit-testing的更新數據:

 1 // a dot to show in the found position
 2 const dot = BABYLON.SphereBuilder.CreateSphere(
 3   "dot",
 4   {
 5     diameter: 0.05,
 6   },
 7   scene,
 8 );
 9 dot.isVisible = false;
10 hitTest.onHitTestResultObservable.add((results) => {
11   if (results.length) {
12     dot.isVisible = true;
13     results[0].transformationMatrix.decompose(dot.scaling, dot.rotationQuaternion, dot.position);
14   } else {
15     dot.isVisible = false;
16   }
17 });

上述代碼實現了功能:在hit-test有效時顯示圓點,如果無效時,則將隱藏圓點。圓點通過使用系統提供的信息,被投影到現實世界中。

基於Babylon.js的WebXR hit-test的一個簡單示例:WebXR Hit-Test Using Babylon.js

用你的AR設備(可能是你的android智能手機)打開它,點擊設備中的一個紋理平面(比如你的地板或門)。如果/當系統正確掃描平面時,標記將顯示在正確位置。

瞄點(Anchors)

瞄點是空間中的跟蹤點,當您掃描環境時,系統將不斷更新這些點。點的轉換將由底層系統不斷更新。

您可以在WebXR anchors module w3c proposal中閱讀更多關於瞄點的信息。

使用以下命令啟用瞄點系統:

1 // featuresManager from the base webxr experience helper
2 const anchorSystem = featuresManager.enableFeature(BABYLON.WebXRAnchorSystem, "latest");

或對於typescript:

1 // featuresManager from the base webxr experience helper
2 const anchorSystem = featuresManager.enableFeature(BABYLON.WebXRAnchorSystem, 'latest') as BABYLON.WebXRAnchorSystem;

一些選項可以傳遞給錨點系統:

 1 export interface IWebXRAnchorSystemOptions {
 2   /**
 3    * a node that will be used to convert local to world coordinates
 4    */
 5   worldParentNode?: TransformNode;
 6 
 7   /**
 8    * If set to true a reference of the created anchors will be kept until the next session starts
 9    * If not defined, anchors will be removed from the array when the feature is detached or the session ended.
10    */
11   doNotRemoveAnchorsOnSessionEnded?: boolean;
12 }

退出XR會話時會默認刪除錨點(請注意,只刪除錨點,連接到錨點的數據不會被刪除),這是推薦的行為,因為在會話之間無法相互引用錨點。

如果要防止這種情況發生,請在初始化錨定系統時設置DonotRemoveAnchorSessionEnded

const anchorSystem = featuresManager.enableFeature(BABYLON.WebXRAnchorSystem, "latest", { doNotRemoveAnchorsOnSessionEnded: true });

當您要在hit test位置添加錨點時會發現,瞄點系統和hit-test特性匹配的非常完美。使用addAnchorPointUsingHitTestResultAsync函數完成這個任務:

1 const arTestResult = getMeTheResultINeed();
2 const anchorPromise = anchorSystem.addAnchorPointUsingHitTestResultAsync(lastHitTest);

要在場景中的任何位置和旋轉中添加錨點,請使用AddAnchorPositionAndRotationAsync函數:

1 const { position, rotationQuaternion } = anyRandomMesh;
2 const anchorPromise = anchorSystem.addAnchorAtPositionAndRotationAsync(position, rotationQuaternion);

注意到,anchorPromise將在完成時返回一個內部的XRAnchor對象,它將為您提供瀏覽器返回的內容。

為了使用babylon錨點,我們使用瞄點模塊中定義的observables:

 1 anchorSystem.onAnchorAddedObservable.add((anchor) => {
 2   // ... do what you want with the anchor after it was added
 3 });
 4 
 5 anchorSystem.onAnchorRemovedObservable.add((anchor) => {
 6   // ... do what you want with the anchor after it was removed
 7 });
 8 
 9 anchorSystem.onAnchorUpdatedObservable.add((anchor) => {
10   // ... do what you want with the anchor after it was updated
11 });

瞄點類型為IWebXRAnchor:

 1 export interface IWebXRAnchor {
 2   /**
 3    * A babylon-assigned ID for this anchor
 4    */
 5   id: number;
 6   /**
 7    * Transformation matrix to apply to an object attached to this anchor
 8    */
 9   transformationMatrix: Matrix;
10   /**
11    * The native anchor object
12    */
13   xrAnchor: XRAnchor;
14 
15   /**
16    * if defined, this object will be constantly updated by the anchor's position and rotation
17    */
18   attachedNode?: TransformNode;
19 }

要將錨點附着到一個節點上(例如,節點為始終位於場景中某位置的模型對象),請使用attachedNode變量。當瞄點更新時,其附加的模型對象的變換也會更新:

1 const mesh = anchorSystem.onAnchorAddedObservable.add((anchor) => {
2   //...
3   anchor.attachedNode = mesh;
4 });

mesh模型對象現在將由系統跟蹤,並將放置在指定的位置。

您可能會問自己,為什么要使用帶有hit-test結果的瞄點系統,當hit-test結果由系統根據設備定義的一個位置返回。

在hit-test的位置放置mesh模型對象將非常有效。

不同的是,系統可能會更新關於這個位置的信息——可能它發現平面處於不同的變換,也可能它更新了它在空間中的位置。

使用瞄點系統將保持變換更新,即使系統更新了其空間知識。

平面檢測

 您的設備(通常)能夠檢測現實世界中的平面幾何圖形。要了解更多有關平面檢測的信息,請訪問平面檢測說明

Babylon有一個實驗性的平面探測模塊,與底層系統一起工作。要啟用它,請執行以下操作:

1 // featuresManager from the base webxr experience helper
2 const planeDetector = featuresManager.enableFeature(BABYLON.WebXRPlaneDetector, "latest");

與任何模塊一樣,您可以使用選項對象(屬於以下類型)對其進行配置:

 1 export interface IWebXRPlaneDetectorOptions {
 2   /**
 3    * The node to use to transform the local results to world coordinates
 4    */
 5   worldParentNode?: TransformNode;
 6 
 7   /**
 8    * If set to true a reference of the created planes will be kept until the next session starts
 9    * If not defined, planes will be removed from the array when the feature is detached or the session ended.
10    */
11   doNotRemovePlanesOnSessionEnded?: boolean;
12 }

與瞄點系統類似,平面不會在會話之間停留。如果要保留本地的XRPlane對象,請將doNotRemovePlanesOnSessionEnded設置為true,Babylon將不會刪除它們。

平面探測器是自動工作的,並提供三個observables供您使用:

 1 planeDetector.onPlaneAddedObservable.add((plane) => {
 2   // ... do what you want with the plane after it was added
 3 });
 4 
 5 planeDetector.onPlaneRemovedObservable.add((plane) => {
 6   // ... do what you want with the plane after it was removed
 7 });
 8 
 9 planeDetector.onPlaneUpdatedObservable.add((plane) => {
10   // ... do what you want with the plane after it was updated
11 });

平面對象的類型為IWebXRPlane:

 1 export interface IWebXRPlane {
 2   /**
 3    * a babylon-assigned ID for this polygon
 4    */
 5   id: number;
 6   /**
 7    * an array of vector3 points in babylon space. right/left hand system is taken into account.
 8    */
 9   polygonDefinition: Array<Vector3>;
10   /**
11    * A transformation matrix to apply on the mesh that will be built using the polygonDefinition
12    * Local vs. World are decided if worldParentNode was provided or not in the options when constructing the module
13    */
14   transformationMatrix: Matrix;
15   /**
16    * the native xr-plane object
17    */
18   xrPlane: XRPlane;
19 }

要根據平面信息創建Babylon多邊形,請執行以下操作:

 1 const plane = // a reference to an added plane
 2   // add the starting point, so the polygon will close
 3   plane.polygonDefinition.push(plane.polygonDefinition[0]);
 4 // create a polygon mesh builder for the polygons returned from the system
 5 var polygon_triangulation = new BABYLON.PolygonMeshBuilder(
 6   "name",
 7   plane.polygonDefinition.map((p) => new BABYLON.Vector2(p.x, p.z)),
 8   scene,
 9 );
10 // build the plane with specific thickness
11 var polygon = polygon_triangulation.build(false, 0.01);

平面的一個簡單用例是使用多邊形表示平面,在場景中中進行展示。在WebXR平面檢測演示中可以找到一個示例

背景移除

在AR模式下,應避免使用像天空框和地面這樣的環境網格對象(除非您的目標是保留它們)。

如果您正在創建一個場景,該場景既能在常規設備模式下,又能在AR模式下工作,則您將希望能夠在進入AR模式時禁用某些網格對象,並在離開AR模式時重新啟用它們。

此模塊正是這樣做的。它接收網格對象列表,並在需要時禁用/啟用網格對象。

當使用babylon環境助手(babylon environment helper)時,模塊可以自動為您完成工作。在這種情況下,如果啟用該功能,skybox和ground將自動刪除。

要啟用它,請使用:

1 const xrBackgroundRemover = featuresManager.enableFeature(BABYLON.WebXRBackgroundRemover);

要自定義模塊的工作方式,請使用以下配置對象:

 1 export interface IWebXRBackgroundRemoverOptions {
 2   /**
 3    * Further background meshes to disable when entering AR
 4    */
 5   backgroundMeshes?: AbstractMesh[];
 6   /**
 7    * flags to configure the removal of the environment helper.
 8    * If not set, the entire background will be removed. If set, flags should be set as well.
 9    */
10   environmentHelperRemovalFlags?: {
11     /**
12      * Should the skybox be removed (default false)
13      */
14     skyBox?: boolean,
15     /**
16      * Should the ground be removed (default false)
17      */
18     ground?: boolean,
19   };
20   /**
21    * don't disable the environment helper
22    */
23   ignoreEnvironmentHelper?: boolean;
24 }

例如,如果希望模塊僅移除skybox而不移除地面,則在使用環境輔助對象時,請通過以下方式啟用該功能:

1 const xrBackgroundRemover = featuresManager.enableFeature(BABYLON.WebXRBackgroundRemover, "latest", {
2   environmentHelperRemovalFlags: {
3     skyBox: true,
4     ground: false,
5   },
6 });

DOM覆蓋

在AR模式下,可能需要顯示DOM元素。

啟用DOM覆蓋時,功能元素是唯一必需的選項,可以是DOM元素或字符串(使用傳遞到document.querySelector時返回的第一個元素)。

enableFeature的最后一個參數可能對您很重要,可以將此功能設置為可選。

 1 const featuresManager = xr.baseExperience.featuresManager;
 2 const domOverlayFeature = featuresManager.enableFeature(BABYLON.WebXRDomOverlay, "latest", { element: ".dom-overlay-container" }, undefined, false);
 3 
 4 xr.baseExperience.onStateChangedObservable.add((webXRState) => {
 5   switch (webXRState) {
 6     case BABYLON.WebXRState.ENTERING_XR:
 7     case BABYLON.WebXRState.IN_XR:
 8       // domOverlayType will be null when not supported.
 9       console.log("overlay type:", domOverlayFeature.domOverlayType);
10       break;
11   }
12 });

當進入AR模式后,可以檢查DOM覆蓋類型的特征;如果瀏覽器中支持該功能,domOverlayType將為非空。

最新的選項可以在WebXR DOM overlay功能的源代碼中找到。

示例

AR測量      AR對象


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM