Apple 已經成為動作捕捉行業的新玩家!可以說,其推出的 ARKit 將和移動設備 Kinect 相媲美。人物遮擋功能以及動作預測是 ARKit 框架的核心部分。本部分向你展示如何利用 iPhone 和 iPad 設備開發動作捕捉應用程序。
前提條件
因為我們開發的是 Apple 系統的應用,所以需要使用 Mac 計算機開發應用程序並利用 iOS 設備運行它們。
硬件
在硬件方面,你需要一個兼容 MacOS Catalina 系統的 MacOS 計算機。此外,動作捕捉應用程序需要 Apple A12 仿生處理器(Apple A12 Bionic processors)才能正常運行。以下 Mac 計算機和 iOS 設備都需要具備的開發條件:
對於這個指南,我使用的是一臺 Mac Mini 主機和一個 11 寸 iPad Pro。
軟件
為了運行順利,您需要在您的 Mac 電腦中安裝如下軟件:
Unity3D 2019 mac 2019.1.5f1
MacOS Catalina 10.15 (Beta)
XCode 11 (Beta)
您的 IOS 設備需要更新至 iOS 13 (Beta)系統或者 iPadOS 13(Beta)系統。
正如你所看到的,在編寫這篇文章時,大多數軟件都是測試版(Beta)。請記住,設備可能會變得不穩定或無響應,因此要特別小心,不要丟失有價值的數據。新的文章將伴隨著 ARKit3、iOS13 和 MacOS10.15 的公開發布。
如果你著急,請在 GitHub 上下載完整的源代碼(代碼地址:https://github.com/LightBuzz/Body-Tracking-ARKit )。
繼續閱讀,瞭解如何創建自己的動作捕捉應用程序!
詳細步驟
說的足夠多了…讓我們駛入 ARKit 的魔法世界吧。在你的電腦上,打開 Unity3D 2019.1 並且創建一個新的工程文件。
步驟一:設置主要的場景
Unity3D 將從一個空場景開始。在添加任何視覺對象(visual objects)或編寫任何代碼之前,我們首先需要導入適當的資源包(dependencies)。骨架跟蹤功能是 ARKit 工具包的一部分。因此,我們需要導入 ARKit 和 ARFoundation 依賴包。
現在,創建一個新場景並添加 AR Session 和 AR Session Origin 對象(在 Unity 中創造 AR 場景,首先做的都是這兩件事情)。這些對象控制 iOS 相機的同時也會提供大量的 ARKit 其他體驗功能。
另外,添加一個空的遊戲對象,例如命名它為:Human Body Tracking,並附加一個新的 C#腳本(HumanBodyTracking.cs)。
場景的結構看起來是這樣的:
步驟二:設置骨架
視覺元素已經到位,我們現在可以開始添加一些交互性。打開HumanBodyTracking.cs腳本,引用ARHumanBodyManager 類。ARHuman Body Manager 是分析攝像機數據以檢測人體的主要腳本。代碼如下:
<code>[SerializeField] private ARHumanBodyManager humanBodyManager;/<code>
為了顯示關節,我們將使用一些簡單的 Unity3D 球體材質。每個球體將對應於特定的關節模式。添加一個 C# Dictionary 類,以逐幀(frame-by-frame)更新關節數據。代碼如下:
<code>private Dictionary bodyJoints;/<code>
最後,添加對骨架的用戶界面元素的引用。我們需要球體材質作為關節,線材質作為骨骼。代碼如下:
<code>[SerializeField] private GameObject jointPrefab; [SerializeField] private GameObject lineRendererPrefab; private LineRenderer[] lineRenderers; private Transform[][] lineRendererTransforms;/<code>
你可以在 GitHub 上找到 HumanBodyTracking.cs 這個類完整的 C#代碼。(GitHub 地址:https://github.com/LightBuzz/Body-Tracking-ARKit/blob/master/body-tracking-arkit/Assets/Scripts/HumanBodyTracking.cs )
步驟三:動作捕捉檢測
這是教程中最重要的部分!ARKit 已經使動作捕捉變得非常容易實現。你所需要的就是用 ARHumanBodyManger 對象並且訂閱到humanBidiesChanged 事件。
<code>private void OnEnable() { humanBodyManager.humanBodiesChanged += OnHumanBodiesChanged; } private void OnDisable() { humanBodyManager.humanBodiesChanged -= OnHumanBodiesChanged; }/<code>
humanBidiesChanged 事件就好像是實現動作捕捉功能的咒語。動作捕捉的信息是事件參數的一部分。下面將告訴您如何獲取動作:
<code> private void OnHumanBodiesChanged(ARHumanBodiesChangedEventArgs eventArgs) { foreach (ARHumanBody humanBody in eventArgs.added) { UpdateBody(humanBody); } foreach (ARHumanBody humanBody in eventArgs.updated) { UpdateBody(humanBody); } }/<code>
很簡單,對不對?所以,讓我們完成以上操作,並在先前創建的 Unity 用戶界面中顯示骨架。
注意:筆者在寫這篇文章時,ARKit 僅僅支持單個人物的動作捕捉。
步驟四:展示骨架
以下的代碼會更新相機中關節的位置。在 iOS 相機攝像頭中,球體材質和線材質都會被覆蓋(overlayed)。
<code> private void UpdateBody(ARHumanBody arBody) { if (jointPrefab == null) return; if (arBody == null) return; if (arBody.transform == null) return; InitializeObjects(arBody.transform); NativeArray joints = arBody.joints; foreach (KeyValuePair item in bodyJoints) { UpdateJointTransform(item.Value, joints[(int)item.Key]); } for (int i = 0; i < lineRenderers.Length; i++) { lineRenderers[i].SetPositions(lineRendererTransforms[i]); } } /<code>
Apple 支持 92 種關聯模式(指數)。然而,不是所有的關聯模式都能被追蹤到!大多數是根據它們相鄰關節的位置推斷出來的。為了您的方便,我選擇了 14 種關聯模式,這樣能夠和 Kinect 相機公平比較。下面是如何連接合適的關節並形成人體骨骼的代碼:
<code>private void InitializeObjects(Transform arBodyT) { if (bodyJoints == null) { bodyJoints = new Dictionary { { JointIndices3D.head_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.neck_1_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.left_arm_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.right_arm_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.left_forearm_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.right_forearm_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.left_hand_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.right_hand_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.left_upLeg_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.right_upLeg_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.left_leg_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.right_leg_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.left_foot_joint, Instantiate(jointPrefab, arBodyT).transform }, { JointIndices3D.right_foot_joint, Instantiate(jointPrefab, arBodyT).transform } }; lineRenderers = new LineRenderer[] { Instantiate(lineRendererPrefab).GetComponent(), // head neck Instantiate(lineRendererPrefab).GetComponent(), // upper Instantiate(lineRendererPrefab).GetComponent(), // lower Instantiate(lineRendererPrefab).GetComponent(), // right Instantiate(lineRendererPrefab).GetComponent() // left }; lineRendererTransforms = new Transform[][] { new Transform[] { bodyJoints[JointIndices3D.head_joint], bodyJoints[JointIndices3D.neck_1_joint] }, new Transform[] { bodyJoints[JointIndices3D.right_hand_joint], bodyJoints[JointIndices3D.right_forearm_joint], bodyJoints[JointIndices3D.right_arm_joint], bodyJoints[JointIndices3D.left_arm_joint], bodyJoints[JointIndices3D.left_forearm_joint], bodyJoints[JointIndices3D.left_hand_joint]}, new Transform[] { bodyJoints[JointIndices3D.right_foot_joint], bodyJoints[JointIndices3D.right_leg_joint], bodyJoints[JointIndices3D.right_upLeg_joint], bodyJoints[JointIndices3D.left_upLeg_joint], bodyJoints[JointIndices3D.left_leg_joint], bodyJoints[JointIndices3D.left_foot_joint] }, new Transform[] { bodyJoints[JointIndices3D.right_arm_joint], bodyJoints[JointIndices3D.right_upLeg_joint] }, new Transform[] { bodyJoints[JointIndices3D.left_arm_joint], bodyJoints[JointIndices3D.left_upLeg_joint] } }; for (int i = 0; i < lineRenderers.Length; i++) { lineRenderers[i].positionCount = lineRendererTransforms[i].Length; } } }/<code>
ARKit 會給我們在 3D 空間中,關節的位置以及旋轉度!下面代碼中反映出在 2D 界面中是如何更新座標,位置和球體的旋轉:
<code>private void UpdateJointTransform(Transform jointT, XRHumanBodyJoint bodyJoint) { jointT.localScale = bodyJoint.anchorScale; jointT.localRotation = bodyJoint.anchorPose.rotation; jointT.localPosition = bodyJoint.anchorPose.position; }/<code>
現在!就讓我們建立並運行我們的工程在實際的 iOS 設備中吧!
步驟五:建立並部署應用
最後,我們需要在實際的設備中建立和運行工程。ARKit 是 IOS 和 IpadOS 的一部分,我們不能測試我們的代碼在 MacOS 中(儘管我很想看到這樣一款模擬器。
在 Unity 中,選擇File->Build Settings。點擊 iOS 建立目標並點擊Build鍵。你將需要指定一個位置去存儲所生成的工程,並耐心等待直到 Unity 完成搭建過程。
Unity 將創造一個 XCode 工程(.xcodeproj)。用 XCode 11 Beta 打開這個工程。如果您使用 XCode11 Beta 之前的版本,將會有一個錯誤提示並且工程無法正常運行。
當這個工程被髮布後,需要提供你的 iOS 開發證書,連接你的 iOS 13 設備,並且點擊 Run 鍵。這樣,這個項目將會被部署在設備中。