You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity MARS插件:实现IProvidesMarsBodyTracking时BodyAdded参数传递疑问

Unity MARS 人体追踪实现疑问

我正尝试使用Unity MARS插件提供的IProvidesMarsBodyTracking API实现人体追踪,以下是继承该接口与MonoBehaviour的脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MARS.Providers;
using System;
using Unity.MARS.Data;

public class BodyTrackManager : MonoBehaviour, IProvidesMarsBodyTracking
{
    public event Action<IMarsBody> BodyAdded;
    public event Action<IMarsBody> BodyUpdated;
    public event Action<IMarsBody> BodyRemoved;

    [SerializeField] GameObject marsBody;

    public void ConnectSubscriber(object obj)
    {
        throw new NotImplementedException();
    }

    public void GetBodies(List<IMarsBody> bodies)
    {
        BodyAdded += BodyTrackManager_BodyAdded;
        Debug.Log("Test");
    }

    private void BodyTrackManager_BodyAdded(IMarsBody obj)
    {
        marsBody.transform.position = obj.BodyPose.bodyPosition;
        marsBody.SetActive(true);
    }

    public void LoadProvider()
    {
        throw new NotImplementedException();
    }

    public void UnloadProvider()
    {
        throw new NotImplementedException();
    }
}

该脚本已挂载到MARS相机,我用一个球体对象作为追踪观测对象,用来查看人体是否被追踪或停止追踪。BodyTrackManager_BodyAdded是注册到BodyAdded事件的自定义方法,但我不清楚应将哪个对象作为该方法的IMarsBody类型参数传入。


问题解析与修正方案

首先明确:IProvidesMarsBodyTracking是提供方接口,它的职责是由Unity MARS底层(或你自定义的追踪逻辑)触发BodyAdded/Updated/Removed事件,你不需要手动传入IMarsBody参数——参数是事件触发者(比如MARS人体追踪底层模块)自动传递的。你的代码目前存在几个关键问题,导致逻辑无法正常工作:

核心问题点

  • 接口方法实现错误:GetBodies的作用是让调用者获取当前所有已追踪人体列表,不是用来注册事件监听的;未实现的ConnectSubscriber、LoadProvider、UnloadProvider必须正确完成逻辑,否则MARS无法识别这个提供方。
  • 事件触发逻辑缺失:作为IProvidesMarsBodyTracking的实现类,你需要自己处理人体检测逻辑,当检测到新人体、状态更新、人体消失时,主动触发对应事件,此时IMarsBody对象是你创建的追踪数据实例。

修正后的脚本示例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MARS.Providers;
using System;
using Unity.MARS.Data;

public class BodyTrackManager : MonoBehaviour, IProvidesMarsBodyTracking
{
    public event Action<IMarsBody> BodyAdded;
    public event Action<IMarsBody> BodyUpdated;
    public event Action<IMarsBody> BodyRemoved;

    [SerializeField] GameObject marsBody;
    // 存储已追踪的人体
    private Dictionary<int, IMarsBody> trackedBodies = new Dictionary<int, IMarsBody>();

    void Awake()
    {
        // 注册事件回调
        BodyAdded += OnBodyAdded;
        BodyUpdated += OnBodyUpdated;
        BodyRemoved += OnBodyRemoved;
    }

    public void ConnectSubscriber(object obj)
    {
        // 关联MARS订阅者与当前提供方
        var subscriber = obj as IMarsBodyTrackingSubscriber;
        subscriber?.SubscribeBodyTracking(this);
    }

    public void GetBodies(List<IMarsBody> bodies)
    {
        // 返回当前所有已追踪人体
        bodies.Clear();
        bodies.AddRange(trackedBodies.Values);
    }

    public void LoadProvider()
    {
        // 初始化追踪逻辑,比如启动摄像头、加载检测模型
        StartCoroutine(SimulateBodyTracking());
    }

    public void UnloadProvider()
    {
        // 停止追踪并释放资源
        StopCoroutine(SimulateBodyTracking());
        trackedBodies.Clear();
    }

    // 模拟人体追踪逻辑(实际项目替换为真实检测代码)
    private IEnumerator SimulateBodyTracking()
    {
        int bodyId = 0;
        while (true)
        {
            // 模拟检测到新人体
            if (trackedBodies.Count == 0)
            {
                var newBody = new MarsBodyMock(bodyId++, transform.position + Vector3.forward);
                trackedBodies.Add(newBody.Id, newBody);
                BodyAdded?.Invoke(newBody);
            }
            // 模拟已追踪人体位置更新
            else
            {
                foreach (var body in trackedBodies.Values)
                {
                    var mockBody = body as MarsBodyMock;
                    mockBody.UpdatePosition(mockBody.BodyPose.bodyPosition + Vector3.right * 0.1f);
                    BodyUpdated?.Invoke(mockBody);
                }
            }
            yield return new WaitForSeconds(0.5f);
        }
    }

    // 事件回调方法
    private void OnBodyAdded(IMarsBody body)
    {
        marsBody.transform.position = body.BodyPose.bodyPosition;
        marsBody.SetActive(true);
        Debug.Log($"检测到新人体,ID: {body.Id}");
    }

    private void OnBodyUpdated(IMarsBody body)
    {
        marsBody.transform.position = body.BodyPose.bodyPosition;
        Debug.Log($"人体位置更新,ID: {body.Id}");
    }

    private void OnBodyRemoved(IMarsBody body)
    {
        marsBody.SetActive(false);
        Debug.Log($"人体消失,ID: {body.Id}");
    }

    // 自定义IMarsBody实现类,用于存储追踪数据
    private class MarsBodyMock : IMarsBody
    {
        public int Id { get; private set; }
        public MarsPose BodyPose { get; private set; }
        public Dictionary<int, MarsPose> JointPoses { get; private set; }

        public MarsBodyMock(int id, Vector3 position)
        {
            Id = id;
            BodyPose = new MarsPose(position, Quaternion.identity);
            JointPoses = new Dictionary<int, MarsPose>();
        }

        public void UpdatePosition(Vector3 newPosition)
        {
            BodyPose = new MarsPose(newPosition, BodyPose.rotation);
        }
    }
}

关键说明

  • IMarsBody参数不需要手动传入:当你的追踪逻辑检测到人体变化时,创建IMarsBody实例(比如示例中的MarsBodyMock),调用BodyAdded?.Invoke(yourMarsBody),事件回调就会自动接收这个参数。
  • 若使用MARS官方内置的人体追踪(比如AR Foundation集成的功能),不需要自己实现IProvidesMarsBodyTracking,直接监听官方提供方的事件即可,只有自定义追踪逻辑时才需要实现该接口。
  • 确保在MARS Session中配置了正确的人体追踪提供方,否则自定义提供方无法被识别。

内容的提问来源于stack exchange,提问作者Omkar P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 19:05:32