訪問 session 中的 AR 功能組件
在運行中的 session 裡,可以通過 Assembly 屬性訪問各個功能組件。本文介紹了如何訪問這些組件,以及訪問時需要注意的事項。
開始之前
- 通過 ARSession 簡介 了解 session 的基本概念、組成和工作流程
- 了解如何 創建 session
編輯時或啟動前配置 AR 組件
有些時候,某些組件選項(比如 DesiredFocusMode)必需在組件啟動前配置,如果不想在 session 啟動後再手動配置並啟動組件,一個簡單的方法是在 session 組裝前對所有可能使用的 frame source 組件進行配置。組裝過程會保留這些組件中的一個或多個,並應用其配置。
這時可以使用 FindAnyObjectByType<T>() 或 GetComponent<T>() 等任何 Unity 基本方法找到組件,然後對組件進行配置。
附註
通過這種方法獲取到的 AR 組件是否會在運行時被包含在 session 中是不確定的。因此必需對所有可能的情況進行配置。
例如,下面的代碼展示了在 session 組裝前修改所有 frame source 組件的對焦模式的過程:
void Awake()
{
var allFrameSources = Session.GetComponentsInChildren<FrameSource>();
foreach (var source in allFrameSources)
{
if (source is CameraDeviceFrameSource)
{
((CameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? CameraDeviceFocusMode.Continousauto : CameraDeviceFocusMode.Medium;
}
else if (source is MotionTrackerFrameSource)
{
((MotionTrackerFrameSource)source).DesiredFocusMode = autoFocus ? MotionTrackerCameraDeviceFocusMode.Continousauto : MotionTrackerCameraDeviceFocusMode.Medium;
}
else if (source is ARCoreFrameSource)
{
((ARCoreFrameSource)source).DesiredFocusMode = autoFocus ? ARCoreCameraDeviceFocusMode.Auto : ARCoreCameraDeviceFocusMode.Fixed;
}
else if (source is ARKitFrameSource)
{
((ARKitFrameSource)source).DesiredFocusMode = autoFocus ? ARKitCameraDeviceFocusMode.Auto : ARKitCameraDeviceFocusMode.Fixed;
}
else if (source is AREngineFrameSource)
{
((AREngineFrameSource)source).DesiredFocusMode = autoFocus ? AREngineCameraDeviceFocusMode.Auto : AREngineCameraDeviceFocusMode.Fixed;
}
else if (source is ThreeDofCameraDeviceFrameSource)
{
((ThreeDofCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? ThreeDofCameraDeviceFocusMode.Auto : ThreeDofCameraDeviceFocusMode.Fixed;
}
else if (source is InertialCameraDeviceFrameSource)
{
((InertialCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? InertialCameraDeviceFocusMode.Auto : InertialCameraDeviceFocusMode.Fixed;
}
else if (source is ARFoundationFrameSource)
{
cameraManager.autoFocusRequested = autoFocus;
}
}
}
上述過程也可以在編輯器中完成,同樣需要對所有組件都進行配置:

其中 ARCoreARFoundationFrameSource 和 ARKitARFoundationFrameSource 兩個 frame source 對應的配置在 Main Camera 的組件上。
警告
通過這種方法獲取到的 AR 組件只能用於運行前的配置。
由於組裝過程會對 AR 組件進行篩選,通過場景樹獲取的 AR 組件可能並沒有被包含在 session 中,無法正常工作。
在執行階段使用組裝完成的 AR 元件
session 中執行的 AR 元件是在組裝完成後才確定的。在組裝完成之前,任何 AR 元件都無法使用。組裝完成的 AR 元件可透過 Assembly 屬性存取。
Assembly 僅在 session 的狀態 >= Assembled 時才可使用。具體而言,Assemble() 方法執行完成後,Assembly 屬性才會被賦值,此時才能透過它存取 session 元件。在 session 停止或損毀後,Assembly 屬性會被清空,無法再存取元件。
可在腳本中檢查 session 的 State 來判斷當下是否可以存取 AR 元件:
if (Session.State >= ARSession.SessionState.Ready)
{
// Assembly 可使用
}
else
{
// Assembly 不可使用
}
也可透過訂閱 StateChanged 事件來獲取 session 的狀態變化,從而在合適的時間點存取 AR 元件。一般來說,為了能捕捉到 Ready 狀態,需要在 session 啟動前訂閱 StateChanged 事件。通常在 Awake() 中完成訂閱是安全的:
void Awake()
{
Session.StateChanged += (state) =>
{
if (Session.State == ARSession.SessionState.Ready)
{
// Assembly 可使用,在此之後 Assembly 將持續可存取,直至 session 停止或損毀
}
else if (Session.State < ARSession.SessionState.Ready)
{
// Assembly 不可使用,在此之後 Assembly 將持續不可存取,直至 session 重新啟動
}
else
{
// Assembly 可使用,通常無需特別處理
}
};
}
注意
若透過 FindAnyObjectByType<T>() 或 GetComponent<T>() 等方法取得 AR 元件,該元件必定會被包含在 session 中,也可在執行階段使用。
儲存這些元件的參照是安全的,但在使用這些元件時,必須確保 session 處於執行狀態且這些元件已被正確包含在 session 中,否則可能引發例外或未預期的行為。
session 啟動前及停止後,這些元件是無法運作的。建議即使採用此種用法,仍需關注 session 的 State 及 StateChanged 事件。
訪問 frame source 組件
可以使用 ARAssembly.FrameSource 屬性訪問 frame source 組件。在一個正常運行的 session 中,ARAssembly.FrameSource 有且只有一個。
在使用 session 時,通常需要通過訪問 ARAssembly.FrameSource 才能確定運行時實際使用的 frame source 組件類型,從而訪問該組件特有的屬性和方法。
例如,下面的程式碼展示了如何根據 frame source 的不同使用不同的平面檢測方法:
void PlaceObject(Vector2 touchPosition)
{
if (Session.Assembly.FrameSource is MotionTrackerFrameSource)
{
Ray ray = Session.Assembly.Camera.ScreenPointToRay(touchPosition);
if (Physics.Raycast(ray, out var hitInfo))
{
TouchRoot.transform.position = hitInfo.point;
}
}
else if (Session.Assembly.FrameSource is ARFoundationFrameSource)
{
var raycastManager = Session.Assembly.Origin.Value.GetComponent<UnityEngine.XR.ARFoundation.ARRaycastManager>();
var hits = new List<UnityEngine.XR.ARFoundation.ARRaycastHit>();
if (raycastManager.Raycast(touchPosition, hits, UnityEngine.XR.ARSubsystems.TrackableType.PlaneWithinPolygon))
{
var hitPose = hits[0].pose;
TouchRoot.transform.position = hitPose.position;
}
}
}
訪問 frame filter 元件
可使用 ARAssembly.FrameFilters 屬性存取 frame filter 元件。在正常運作的 session 中,ARAssembly.FrameFilters 清單內任何類型的元件可能同時存在多個。
例如,以下程式碼展示如何取得 session 中的 MegaTrackerFrameFilter 並註冊對應事件:
var megaTracker = session.Assembly.FrameFilters.Where(f => f is MegaTrackerFrameFilter).FirstOrDefault() as MegaTrackerFrameFilter;
if (megaTracker)
{
megaTracker.LocalizationRespond += (response) =>
{
};
}
訪問 camera 組件
可以使用 ARAssembly.Camera 屬性訪問 camera 組件。如果場景中有多個 camera,這時一個找到 AR 使用的攝影機的快捷方式。
例如,下面的程式碼展示了如何取得 session 中的 camera 並對場景中的物體進行射線檢測:
var ray = Session.Assembly.Camera.ScreenPointToRay(screenPoint);
if (Physics.Raycast(ray, out var hitInfo))
{
TouchRoot.transform.position = hitInfo.point;
};
訪問 origin 組件
可以使用 ARAssembly.Origin 屬性訪問 origin 組件。
例如,下面的代碼展示了如何獲取 session 中的 origin 並將一個代表當前攝影機位置和朝向的錐體顯示在場景中:
if (session.Assembly.Origin.OnSome)
{
GameObject frustum = Instantiate(CameraFrustumPrefab, session.Assembly.Camera.transform.position, session.Assembly.Camera.transform.rotation);
frustum.transform.SetParent(session.Assembly.Origin.Value.transform);
}
需要注意的是,這裡需要先判斷 ARAssembly.Origin 是否存在。
附註
ARAssembly.Origin 只在啟用了運動追蹤功能的 session 中存在。
訪問 CameraImageRenderer 元件
可使用 ARAssembly.CameraImageRenderer 屬性存取 CameraImageRenderer 元件。
例如,以下程式碼可取得實體相機影像的 RenderTexture:
RenderTexture renderTexture;
void Awake()
{
Session.StateChanged += (state) =>
{
if (state == ARSession.SessionState.Ready && Session.Assembly.CameraImageRenderer.OnSome)
{
Session.Assembly.CameraImageRenderer.Value.RequestTargetTexture((_, texture) => renderTexture = texture);
}
};
}
需注意此處需先判斷 ARAssembly.CameraImageRenderer 是否存在。
附註
ARAssembly.CameraImageRenderer 僅在由 EasyAR 繪製畫面的工作階段中有效。通常使用 AR Foundation 或頭顯時無效,此時實體相機畫面由 AR Foundation 或頭顯 SDK 繪製。
存取 FrameRecorder 元件
可透過 ARAssembly.FrameRecorder 屬性存取 FrameRecorder 元件。
例如,以下程式碼能啟動錄製,檔案儲存位置取決於配置,預設將儲存在應用內儲存目錄中:
if (session.Assembly.FrameRecorder.OnSome)
{
var frameRecorder = session.Assembly.FrameRecorder.Value;
frameRecorder.enabled = true;
}
需注意的是,此處需先判斷 ARAssembly.FrameRecorder 是否存在。
附註
ARAssembly.FrameRecorder 在少數情況下(例如使用 FramePlayer 時)無法使用。
後續步驟
- 瞭解如何 取得 session 的執行結果,這些結果包含了 AR 元件的執行輸出
- 另外,您還可以透過下面這些範例來瞭解元件的存取:
- Workflow_ARSession 範例 展示了各種元件的存取和使用方法
相關主題
- 幀數據源 描述了 frame source 以及運行時的選取方式
- XR Origin 描述了 AR 場景中 origin 元件的用途
- Camera 描述了 AR 場景中 camera 元件的用途
- 錄製EIF文件 描述了 FrameRecorder 的詳細使用方法