[Unity 6] 使用 YOLO11 來開發動作捕捉功能,同步遊戲物件位置至關節座標

2025.04.22 / Unity 引擎
動作捕捉能創造有沉浸感的互動體驗,玩家可以透過網路視訊鏡頭來與作品互動。YOLO11 有提供開箱即用的動作捕捉模型,我們可以藉由將 YOLO 分析出來的關節座標傳送到 Unity 來建構互動裝置。本文將說明如何使用我製作的 MDF-YOLO11 開源模組來快速用網路攝影機來開發動作捕捉功能,可用於體感互動作品的開發。

本文會使用到我開發的兩個開源模組:「python-module-yolo11」開箱即用的 YOLO11 Python 程式、「unity-module-yolo11 (MDF YOLO11)」則是配合第一個模組來用的套件。而因為 python-module-yolo11 是一支獨立的程式關係,讓這個遊戲專案只能用於展示科技,不適合打包成執行檔給玩家使用。

這兩個模組皆開源,任何人都能任意使用,如果能放個超連結到這篇文章的話我會很感謝你~

網路視訊鏡頭

我們的動作捕捉會用 YOLO11 來開發,因此無須購買 Kinect 之類的硬體,只要連接一個網路視訊鏡頭 (Webcam)。

取得 YOLO11 的 Python 模組

首先前往 python-module-yolo11 的 Releases 網頁,下載 1.0.0 版本的 Source Code。

下載後是一個壓縮檔,請將檔案解壓縮到一個空間充足的位置 (至少留個 3GB~,未來還有機會再增長)。

解壓縮後,雙點擊 install.bat 來啟動安裝程式。

安裝程式主要會設定好 Python 的可攜式執行環境,並下載安裝 YOLO 模型、OSC 套件等必要功能,需要穩定的網路來下載。

當畫面最後一直出現如下圖中的提示,代表 YOLO11 模組已安裝完成,而且可以順利執行!如果要關閉,請按下鍵盤 Ctrl + C 後再點擊 y 來關閉。

如果要再次啟動 YOLO11 模組,可以直接雙點擊 start.bat 來啟動,不需要再安裝一次。

取得 YOLO11 的 Unity 模組

接下來請建立一個 Unity 6 的新專案,如果專案已內建 URP,可先點擊 Remove Readme Assets 來移除無關內容。

選擇 Proceed 並等待系統執行完成。

接下來,請從頂部選單的 Window 開啟 Package Manager。

點開左上角的 + 號,選擇 Install package from git URL。

分兩次將以下兩個網址複製貼上並點擊 Install。

1https://github.com/keijiro/OscJack.git?path=Packages/jp.keijiro.osc-jack#2.0.0
1https://github.com/tedliou/unity-module-yolo11.git#1.0.0

最後 Package Manager 將會安裝好 OSC Jack 與 MDF YOLO11。OSC Jack 是一個網路傳輸的功能,MDF YOLO11 會用它來和 python-module-yolo11 模組溝通。

建立示範場景

開啟預設的 Sample Scene,建立一個空物件 GameObject 和方塊 (Cube)、圓球 (Sphere)、圓柱體 (Cylinder) 各一個,並且在 GameObject 上掛上 Body Tracker 腳本 (MDF YOLO11 模組提供的功能)。

Body Tracker 有提供動作捕捉要追蹤的關節設定 (Tracking Joints),預設為追蹤鼻子和左右手腕。

接下來我們要來撰寫程式碼,讓剛才建立的方塊、圓球和圓柱體的座標能同步到鼻子、左手腕、右手腕的關節位置。自行建立一個 CustomManager.cs 腳本。

CustomManager.cs 建立好後,將內容直接替換成以下程式碼,程式碼的說明已使用註解寫在程式碼內,如有問題可以在留言區或到 GitHub 發 Issue/PR。

 1using MDF.YOLO11;
 2using UnityEngine;
 3
 4// 將方塊 (Cube)、圓球 (Sphere)、圓柱體 (Cylinder) 分別移動到
 5// YOLO 偵測到的第一個人的鼻子、左手腕、右手腕的關節位置
 6public class CustomManager : MonoBehaviour
 7{
 8    // 公開變數
 9    // 鼻子 (Cube)、左手腕 (Sphere)、右手腕 (Cylinder)
10    public GameObject nose, leftWrist, rightWrist;
11
12    // 遊戲開始時監聽 BodyTracker 的更新事件
13    // UpdateCubes 被呼叫時代表 YOLO 有順利追蹤到肢體
14    private void Start()
15    {
16        GetComponent<BodyTracker>().ValueChanged += UpdateCubes;
17    }
18
19    // YOLO 追蹤到肢體時會一直呼叫這個
20    // 分別從肢體追蹤的結果中取出座標,並移動物件到指定座標 (關節的座標)
21    // COCOKeypoint.XXXX 是關節的名稱
22    private void UpdateCubes(BodyKeypoint keypoints)
23    {
24        UpdateJointObject(keypoints, COCOKeypoint.Nose, nose);
25        UpdateJointObject(keypoints, COCOKeypoint.LeftWrist, leftWrist);
26        UpdateJointObject(keypoints, COCOKeypoint.RightWrist, rightWrist);
27    }
28
29    // 取出第一個人的指定關節座標,並轉換成世界座標
30    // 讓物件在遊戲畫面上的位置等同於 YOLO 看到的位置
31    private void UpdateJointObject(BodyKeypoint keypoints, COCOKeypoint joint, GameObject targetObj)
32    {
33        var point = keypoints[0][joint];
34
35        // 如果有勾選 Body Tracker 的 Invert X 或 Invert Y
36        // 沒偵測到的關節有可能會是 0 或 1 的初始值
37        // 當座標為初始值時要當作無效座標,將物件隱藏
38        if (IsInvisiable(point))
39        {
40            targetObj.SetActive(false);
41            return;
42        }
43
44        var screenPos = new Vector3(Screen.width * point.x, Screen.height * point.y, Mathf.Abs(Camera.main.transform.position.z));
45        var worldPos = Camera.main.ScreenToWorldPoint(screenPos);
46        targetObj.transform.position = worldPos;
47        targetObj.SetActive(true);
48    }
49
50    // 最好要用 Mathf.Approximately 來比對浮點數的座標
51    // 因浮點數偶爾會有誤差,用 == 可能會出 Bug
52    private bool IsInvisiable(Vector2 point)
53    {
54        return
55            (Mathf.Approximately(point.x, 1) || Mathf.Approximately(point.x, 0)) &&
56            (Mathf.Approximately(point.y, 1) || Mathf.Approximately(point.y, 0));
57    }
58}

最後回到 Unity,將剛才建立的方塊、圓球和圓柱體分別拖曳到 Nose、Left Wrist 與 Right Wrist 欄位,一套簡單的系統即開發完成。

效果預覽

啟動 python-module-yolo11 與執行 Unity 專案,現在遊戲應該已能捕捉到你的動作,並且將三個物件的位置同步到你的鼻子與左右手腕中。

示範專案

本文所使用的 Unity 專案也已上傳至 GitHub,歡迎多加利用:tedliou/unity-tutorial-yolo11

相關文章

Ted Liou

雲科碩士在讀中,專注於 Unity C#、TouchDesigner 技術。
只要願意以超連結標註本文,歡迎轉載或用於教材製作!