手部追蹤設定檔
手部追蹤設定檔位於輸入系統設定檔下。 它包含自訂手部表現的設定。
關節預製件
接頭預製件是用簡單的預製件來視覺化的。 掌狀接頭和食指接頭特別重要,擁有各自的預製件,而其他接頭則共用相同的預製件。
預設情況下,手動接頭預製件是簡單的幾何基元。 這些都可以如願更換。 若完全未指定預製件,則會建立空的 GameObject 。
警告
避免在 joint 預製件中使用複雜腳本或昂貴的渲染,因為 joint 物件會在每一幀都被轉換,且可能帶來顯著的效能負擔!
| 預設手部關節表示 | 聯合唱片公司 |
|---|---|
|
|
手工網狀預製件
若手部追蹤裝置提供完整定義的網格資料,則使用手部網格。 預製件中可渲染的網格會被裝置資料取代,因此像立方體這樣的虛擬網格就足夠了。 預製件的材料用於手工網格。
手部網格顯示可能會明顯影響效能,因此只要取消勾選 啟用手部網格視覺化 選項,就可以完全關閉。
手部視覺化設定
手部網格與手部關節視覺化可分別透過 手部網格視覺化模式 與 手部關節視覺化模式 來關閉或開啟。 這些設定是針對應用程式模式的,意即在編輯器 (中開啟部分功能,透過編輯器內模擬看到關節,例如) ,但在玩家建構) 部署到裝置 (時則關閉相同功能。
請注意,通常建議在編輯器 (開啟手部關節視覺化功能,這樣在編輯器內模擬時會顯示手部關節的) 位置;同時在播放器 (中關閉手部關節視覺化和手部網格視覺化,因為這會造成效能) 影響。
腳本編寫
每個手關節 MixedRealityPose的輸入系統可請求位置與旋轉。
或者系統允許存取跟隨關節的 遊戲物件 。 如果其他 GameObject 需要持續追蹤一個接點,這會很有用。
可用接頭列於列舉中 TrackedHandJoint 。
注意事項
當手部追蹤中斷時,關節物件會被摧毀! 確保使用聯合物件的腳本能優雅地處理此 null 情況,以避免錯誤!
存取特定的手型控制器
通常會使用特定的手型控制器,例如在處理輸入事件時。 此時可直接透過介面向裝置 IMixedRealityHand 請求聯合資料。
控制器的輪詢聯合姿勢
如果請求的接點因某些原因無法使用,函式會 TryGetJoint 回傳 false 。 此時所得姿態為 MixedRealityPose.ZeroIdentity。
public void OnSourceDetected(SourceStateEventData eventData)
{
var hand = eventData.Controller as IMixedRealityHand;
if (hand != null)
{
if (hand.TryGetJoint(TrackedHandJoint.IndexTip, out MixedRealityPose jointPose)
{
// ...
}
}
}
手部視覺化器的關節轉換
可向 控制器視覺化器請求聯合物件。
public void OnSourceDetected(SourceStateEventData eventData)
{
var handVisualizer = eventData.Controller.Visualizer as IMixedRealityHandVisualizer;
if (handVisualizer != null)
{
if (handVisualizer.TryGetJointTransform(TrackedHandJoint.IndexTip, out Transform jointTransform)
{
// ...
}
}
}
簡化的聯合資料存取
若未提供特定控制器,則提供工具類別以便方便存取手關節資料。 這些功能會要求目前追蹤的第一個可用手持裝置進行聯合資料。
來自 HandJointUtils 的輪詢聯合姿勢
HandJointUtils 是一個靜態類別,查詢第一個主動的手持裝置。
if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
{
// ...
}
從手部聯合服務的關節轉換
IMixedRealityHandJointService 保留一組持續存在的 GameObjects 來追蹤關節。
var handJointService = CoreServices.GetInputSystemDataProvider<IMixedRealityHandJointService>();
if (handJointService != null)
{
Transform jointTransform = handJointService.RequestJointTransform(TrackedHandJoint.IndexTip, Handedness.Right);
// ...
}
手部追蹤事件
如果不希望直接從控制器查詢資料,輸入系統也會提供事件。
聯合活動
IMixedRealityHandJointHandler 負責關節位置的更新。
public class MyHandJointEventHandler : IMixedRealityHandJointHandler
{
public Handedness myHandedness;
void IMixedRealityHandJointHandler.OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData)
{
if (eventData.Handedness == myHandedness)
{
if (eventData.InputData.TryGetValue(TrackedHandJoint.IndexTip, out MixedRealityPose pose))
{
// ...
}
}
}
}
網狀事件
IMixedRealityHandMeshHandler 處理關節式手網的變更。
請注意,手部網格預設並非啟用。
public class MyHandMeshEventHandler : IMixedRealityHandMeshHandler
{
public Handedness myHandedness;
public Mesh myMesh;
public void OnHandMeshUpdated(InputEventData<HandMeshInfo> eventData)
{
if (eventData.Handedness == myHandedness)
{
myMesh.vertices = eventData.InputData.vertices;
myMesh.normals = eventData.InputData.normals;
myMesh.triangles = eventData.InputData.triangles;
if (eventData.InputData.uvs != null && eventData.InputData.uvs.Length > 0)
{
myMesh.uv = eventData.InputData.uvs;
}
// ...
}
}
}
已知問題
.NET Native
目前已知使用 .NET 後端的 Master 建置有問題。 在 .NET Native 中,IInspectable指標無法使用 Marshal.GetObjectForIUnknown. MRTK 利用此技術取得 SpatialCoordinateSystem 以接收平台的手部與眼睛資料。
我們已在原生的 Mixed Reality Toolkit 倉庫中提供了 DLL 原始碼作為解決方法。 請依照 README 中的指示,將產生的二進位檔複製到 Unity 資產中的 Plugins 資料夾。 之後,MRTK 提供的 WindowsMixedRealityUtilities 腳本會幫你解決這個變通方法。
如果你想建立自己的 DLL 或將此變通方法納入現有 DLL,該變通核心如下:
extern "C" __declspec(dllexport) void __stdcall MarshalIInspectable(IUnknown* nativePtr, IUnknown** inspectable)
{
*inspectable = nativePtr;
}
以及它在你的 C# Unity 程式碼中的使用:
[DllImport("DotNetNativeWorkaround.dll", EntryPoint = "MarshalIInspectable")]
private static extern void GetSpatialCoordinateSystem(IntPtr nativePtr, out SpatialCoordinateSystem coordinateSystem);
private static SpatialCoordinateSystem GetSpatialCoordinateSystem(IntPtr nativePtr)
{
try
{
GetSpatialCoordinateSystem(nativePtr, out SpatialCoordinateSystem coordinateSystem);
return coordinateSystem;
}
catch
{
UnityEngine.Debug.LogError("Call to the DotNetNativeWorkaround plug-in failed. The plug-in is required for correct behavior when using .NET Native compilation");
return Marshal.GetObjectForIUnknown(nativePtr) as SpatialCoordinateSystem;
}
}