Unity 中的自訂相機實現 —— 外部幀數據源
透過外部幀數據源(ExternalFrameSource),開發者可以為 EasyAR Sense 擴充自訂的相機實現,從而支援特定的頭顯設備或其他輸入設備。以下內容介紹了外部幀數據源的類型結構及介面定義。
開始之前
外部幀資料來源類型
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
class FrameSource {
<<abstract>>
}
class ExternalFrameSource {
<<abstract>>
}
class ExternalDeviceFrameSource {
<<abstract>>
}
class ExternalDeviceMotionFrameSource:::EasyAR {
<<abstract>>
}
class ExternalDeviceRotationFrameSource:::EasyAR {
<<abstract>>
}
class ExternalImageStreamFrameSource:::EasyAR {
<<abstract>>
}
ExternalFrameSource --|> FrameSource
ExternalDeviceFrameSource --|> ExternalFrameSource
ExternalDeviceMotionFrameSource --|> ExternalDeviceFrameSource
ExternalDeviceRotationFrameSource --|> ExternalDeviceFrameSource
ExternalImageStreamFrameSource --|> ExternalFrameSource
classDef EasyAR fill:#6e6ce6,stroke:#333,color:#fff
上圖展示了外部幀資料來源的類型結構。
根據輸入資料的不同,外部幀資料來源可分為兩大類:
- 影像和裝置運動資料輸入擴展
- 透過繼承 ExternalDeviceMotionFrameSource 實現:裝置及裝置 SDK 提供 6DoF 運動追蹤功能。虛擬攝影機的 transform 及其它控制由裝置 SDK 完成。
- 透過繼承 ExternalDeviceRotationFrameSource 實現:裝置及裝置 SDK 提供 3DoF 旋轉追蹤功能。虛擬攝影機的 transform 及其它控制由裝置 SDK 完成。
- 影像輸入擴展
- 透過繼承 ExternalImageStreamFrameSource 實現:僅提供影像輸入。虛擬攝影機的 transform 及其它控制由 EasyAR 完成。
接入這幾種外部幀資料來源時,可以使用的 AR 功能有所不同:
- 影像和裝置運動資料輸入擴展 ExternalDeviceMotionFrameSource
- Mega
- 運動追蹤(由裝置自身提供)
- 稀疏空間地圖
- 稠密空間地圖
- 影像追蹤(支援運動融合)
- 影像雲識別
- 物體追蹤(支援運動融合)
- 影像和裝置運動資料輸入擴展 ExternalDeviceRotationFrameSource
- Mega
- 影像追蹤(不支援運動融合)
- 影像雲識別
- 物體追蹤(不支援運動融合)
- 影像輸入擴展 ExternalImageStreamFrameSource
- 影像追蹤(不支援運動融合)
- 影像雲識別
- 物體追蹤(不支援運動融合)
外部幀數據源介面定義
建立外部幀資料來源時,必須實作相關介面。下面介紹了這些介面的定義及使用方法。
設備定義
FrameSource.IsHMD:
定義是否為头显
在且仅在头显设备上设为 true。
若設備為头显,診斷資訊將顯示於攝影機前的 3D 板子而非螢幕上。部分 AR 功能在头显设备上運行會有些許差異。FrameSource.Display:
定義顯示系統
提供當前顯示的旋轉等資訊。
可使用 Display.DefaultSystemDisplay 或 Display.DefaultHMDDisplay 取得預設顯示資訊。 通常在头显上可使用 Display.DefaultHMDDisplay。
可用性
- FrameSource.IsAvailable:
可用性(Availability)用於判斷 frame source 是否可以使用。 如果一個 frame source 在當前執行裝置或環境下不可用,該數值應為 false。 如果該數值等於 Optional<bool>.Empty,FrameSource.CheckAvailability() 協程會被呼叫,應在協程結束前更新 FrameSource.IsAvailable。 可用性介面會在 session 組裝時使用,不可用的元件將不會被選擇且它的方法在 session 執行時不會被呼叫。 - FrameSource.CheckAvailability()(可選):
檢查 frame source 是否可用的協程FrameSource.IsAvailable 等於 Optional<bool>.Empty 時會被呼叫。在該協程結束前,session 的組裝過程會被阻塞。
session 原點
ExternalDeviceFrameSource.OriginType:
原點類型- XROrigin:設備 SDK 使用 Unity.XR.CoreUtils.XROrigin 作為原點。
- Custom:設備 SDK 使用自定義的原點。 需指定 ExternalDeviceFrameSource.Origin。
- None:設備 SDK 未定義原點。
這時原點將會自動從場景中選擇或創建,但不會移動。
session 將只支援 SessionOrigin 中心模式。應用開發者必須對於他們如何擺放虛擬物體十分小心,因為所有 target 及 target 下的內容永遠都會在 Unity 座標系中移動,使用者的部分內容(比如物理系統)將無法正常工作。所有放在 Unity 世界座標系下的物體在任何配置下都永遠不可能顯示在正確的位置。
ExternalDeviceFrameSource.Origin:
原點物體
在且僅在 ExternalDeviceFrameSource.OriginType 為 Custom 時定義自己的原點,其它時候不需要重新定義。
虛擬攝像機
- FrameSource.Camera:
虛擬攝像機
攝像機不受 session 控制,攝像機的 transform 和投影矩陣以及圖像背景渲染應由外部代碼控制。
僅在頭顯上該攝像機會被使用,用於將一些診斷文字展示在眼前。
在 ExternalDeviceFrameSource.OriginType 是 XROrigin 時不需要定義,EasyAR 會自動使用 Unity XR 框架中定義的相機。
物理相機
- FrameSource.DeviceCameras:
物理相機參數
提供相機幀數據的物理相機。若相機幀數據由多個相機提供,列表中需包含所有物理相機。
需確保在 FrameSource.CameraFrameStarted 為 true 時可取得正確的物理相機參數。 - FrameSource.CameraFrameStarted:
相機幀是否開始輸入
在物理相機準備好並可輸入數據至 EasyAR 後返回 true,物理相機停止運行後返回 false。當 FrameSource.CameraFrameStarted 為 false 時,EasyAR 不會工作。FrameSource.CameraFrameStarted 為 true 時必須保證 FrameSource.DeviceCameras 數據可存取且不間斷地向 EasyAR 輸入相機幀數據。當 EasyAR 檢查到相機幀連續長時間無輸入後會彈出警告,輔助用戶判斷功能無回應時進行問題解耦。
物理相機參數需與真實裝置相機相同。
- FrameSourceCamera.CameraType:
物理相機類型
一般非前置相機的情況,例如頭顯上,選擇後置相機。 - FrameSourceCamera.CameraOrientation:
物理相機影像在裝置的自然方向上顯示時需順時針旋轉的角度
範圍為 [0, 360)。 - FrameSourceCamera.FrameSize:
影像尺寸 - FrameSourceCamera.FrameRateRange:
幀率範圍
定義 x 為幀率範圍下界 y 為幀率範圍上界。 - DeviceFrameSourceCamera.AxisSystem:
頭部/物理相機 pose 及物理相機外參使用的座標軸系統
所有矩陣必須使用相同的座標軸系統。若使用的數據定義不符合已知系統,需在傳給 EasyAR 前進行座標軸變換。 - DeviceFrameSourceCamera.Extrinsics:
物理相機外參
一般是標定的矩陣。其座標軸應符合 DeviceFrameSourceCamera.AxisSystem 定義。若外參的座標軸定義與實際 pose 的座標軸定義不同,或其不符合 DeviceFrameSourceCamera.AxisSystem 的定義,需在設置此數值前進行座標軸變換。
Session 啟動和停止
- FrameSource.OnSessionStart(ARSession):
處理 session 啟動事件在 session 組裝時選擇了這個 frame source 時有效。 可以用於延遲初始化,在這個方法中進行 AR 獨有的初始化工作。 - FrameSource.OnSessionStop():
處理 session 停止事件在 session 組裝時選擇了這個 frame source 時有效。 可以在這個方法中銷毀 FrameSource.OnSessionStart(ARSession) 以及 session 執行中建立的資源並恢復內部狀態。在 session 銷毀之前這個方法會被保證調用。如果 frame source 在 session 之前銷毀,它將不會被調用,且 session 將進入 Broken 狀態。
輸入幀
ExternalDeviceRotationFrameSource.HandleCameraFrameData(DeviceFrameSourceCamera, double, Image, CameraParameters, Quaternion):
輸入相機幀數據
可以在任何執行緒呼叫,只要裝置 SDK 的 API 都是執行緒安全的即可。
這些數據需要與實體相機感測器曝光時的數據一致。建議輸入 30 或 60 fps 的數據。最小可接受幀率為 2,但部分演算法響應時間會受影響。只要可以獲取,建議輸入彩色數據,這對 Mega 的效果是有幫助的。
為實現最佳效率,可以設計整個數據鏈條讓原始 YUV 數據直接透過共享記憶體透傳,並直接使用數據指標傳入 EasyAR,並注意數據所有權。ExternalDeviceMotionFrameSource.HandleRenderFrameData(double, Pose, MotionTrackingStatus):
輸入渲染幀數據ExternalDeviceRotationFrameSource.HandleRenderFrameData(double, Quaternion):
輸入渲染幀數據
需要確保在裝置數據準備好之後每個渲染幀呼叫,不能跳幀。這些數據需要與驅動同一幀內當前 Unity 虛擬攝影機的數據一致。
- ExternalFrameSource.TryAcquireBuffer(int):
嘗試從記憶體池中獲取記憶體區塊
這個記憶體區塊通常用於儲存相機幀的圖像數據並輸入 EasyAR。 - ExternalFrameSource.ReceivedFrameCount:
EasyAR 獲取到的相機幀計數
EasyAR 會用它來檢查裝置相機幀輸入的健康情況。可以在除錯中使用,如果這個數值停止增長,通常說明裝置停止向 EasyAR 輸入數據。
Unity 訊息
在腳本中使用以下訊息時,需要注意確保基類實現被呼叫:
後續步驟
- 閱讀 外部輸入幀數據 了解相機幀數據和渲染幀數據
- 建立 影像和裝置運動數據輸入延伸模組
- 建立 影像輸入延伸模組