| 
 | 
 
 本帖最后由 ycyipman 于 2016-2-16 15:03 编辑  
 
一、使用方式: 
彩色帧获取需要两个脚本,BodySourceManager和BodySourceView,使用时新建一个空物体,并为其添加BodySourceManager,在新建一个plane或者cube,添加BodySourceView作为输出展示载体。BodySourceView需要一个公共变量,将BodySourceManager所在的空物体拖入即可。 
二、脚本执行过程: 
BodySourceManager脚本: 
脚本执行逻辑与其他三种帧数据处理逻辑相同,此处只贴代码,不再做解释。 
[mw_shl_code=csharp,true]    private KinectSensor _Sensor;                               //传感器对象 
    private BodyFrameReader _Reader;                            //骨骼帧阅读器 
    private Body[] _Data = null;                                //骨骼数据存储器,用于返回给BodySourceView使用,数组中每一个元素都是Body对象 
 
    public Body[] GetData() 
    { 
        return _Data; 
    } 
     
 
    void Start ()  
    { 
        _Sensor = KinectSensor.GetDefault(); 
 
        if (_Sensor != null) 
        { 
            //打开骨骼阅读器 
            _Reader = _Sensor.BodyFrameSource.OpenReader(); 
             
            if (!_Sensor.IsOpen) 
            { 
                _Sensor.Open(); 
            } 
        }    
    } 
     
    void Update ()  
    { 
        if (_Reader != null) 
        { 
            //得到最近一帧的骨骼帧 
            var frame = _Reader.AcquireLatestFrame(); 
            if (frame != null) 
            { 
                if (_Data == null) 
                { 
                    //创建存储器对象,长度为BodyCount返回值 
                    _Data = new Body[_Sensor.BodyFrameSource.BodyCount]; 
                } 
                 
                //每一帧刷新数据 
                frame.GetAndRefreshBodyData(_Data); 
                 
                frame.Dispose(); 
                frame = null; 
            } 
        }     
    } 
     
    void OnApplicationQuit() 
    { 
        if (_Reader != null) 
        { 
            _Reader.Dispose(); 
            _Reader = null; 
        } 
         
        if (_Sensor != null) 
        { 
            if (_Sensor.IsOpen) 
            { 
                _Sensor.Close(); 
            } 
             
            _Sensor = null; 
        } 
}[/mw_shl_code] 
 
BodySourceView脚本定义了整个人体的骨骼网络图,其中键为子节点,值为母节点 
[mw_shl_code=csharp,true]    private Dictionary<Kinect.JointType, Kinect.JointType> _BoneMap = new Dictionary<Kinect.JointType, Kinect.JointType>() 
    { 
        { Kinect.JointType.FootLeft, Kinect.JointType.AnkleLeft }, 
        { Kinect.JointType.AnkleLeft, Kinect.JointType.KneeLeft }, 
        { Kinect.JointType.KneeLeft, Kinect.JointType.HipLeft }, 
        { Kinect.JointType.HipLeft, Kinect.JointType.SpineBase }, 
 
        { Kinect.JointType.FootRight, Kinect.JointType.AnkleRight }, 
        { Kinect.JointType.AnkleRight, Kinect.JointType.KneeRight }, 
        { Kinect.JointType.KneeRight, Kinect.JointType.HipRight }, 
        { Kinect.JointType.HipRight, Kinect.JointType.SpineBase }, 
 
        { Kinect.JointType.HandTipLeft, Kinect.JointType.HandLeft }, 
        { Kinect.JointType.ThumbLeft, Kinect.JointType.HandLeft }, 
        { Kinect.JointType.HandLeft, Kinect.JointType.WristLeft }, 
        { Kinect.JointType.WristLeft, Kinect.JointType.ElbowLeft }, 
        { Kinect.JointType.ElbowLeft, Kinect.JointType.ShoulderLeft }, 
        { Kinect.JointType.ShoulderLeft, Kinect.JointType.SpineShoulder }, 
 
        { Kinect.JointType.HandTipRight, Kinect.JointType.HandRight }, 
        { Kinect.JointType.ThumbRight, Kinect.JointType.HandRight }, 
        { Kinect.JointType.HandRight, Kinect.JointType.WristRight }, 
        { Kinect.JointType.WristRight, Kinect.JointType.ElbowRight }, 
        { Kinect.JointType.ElbowRight, Kinect.JointType.ShoulderRight }, 
        { Kinect.JointType.ShoulderRight, Kinect.JointType.SpineShoulder }, 
 
        { Kinect.JointType.SpineBase, Kinect.JointType.SpineMid }, 
        { Kinect.JointType.SpineMid, Kinect.JointType.SpineShoulder }, 
        { Kinect.JointType.SpineShoulder, Kinect.JointType.Neck }, 
        { Kinect.JointType.Neck, Kinect.JointType.Head }, 
};[/mw_shl_code] 
 
对于获取到的骨骼数据,由于存在几个人的骨骼被同时获取的可能性,因此还需要定义一个键值对,键代表每一个人的ID,值为该ID对应的创建好的骨骼GameObject(注:ID值并没有从0开始,依次增大1的顺序规律,同一个人在离开Kinect视野范围之后再回来时,ID值也会发生变化) 
[mw_shl_code=csharp,true]private Dictionary<ulong, GameObject> _Bodies = new Dictionary<ulong, GameObject>();//根据body对象创建的body GameObject的字典集合,键是追踪的ID值,值为创建的body GameObject 
[/mw_shl_code] 
Update函数通过调用BodySourceManager脚本中的GetData函数得到骨骼数据,再将GetData数组中的每一个body对象赋予一个ID值,当玩家没有离开Kinect视野范围时,该ID值与body对象一一对应,当玩家离开Kinect视野范围时,根据ID删除对应的body对象 
[mw_shl_code=csharp,true]    void Update() 
    { 
        if (BodySourceManager == null) 
        { 
            return; 
        } 
 
        //获得BodySourceManager组件 
        _BodyManager = BodySourceManager.GetComponent<BodySourceManager>(); 
        if (_BodyManager == null) 
        { 
            return; 
        } 
 
        //得到BodySourceManager的最终数据,为Body对象数组 
        Kinect.Body[] data = _BodyManager.GetData(); 
        if (data == null) 
        { 
            return; 
        } 
 
        //trackedIds存放跟踪到的ID的集合 
        List<ulong> trackedIds = new List<ulong>(); 
        foreach (var body in data) 
        { 
            if (body == null) 
            { 
                continue; 
            } 
 
            if (body.IsTracked) 
            { 
                trackedIds.Add(body.TrackingId); 
            } 
        } 
 
        List<ulong> knownIds = new List<ulong>(_Bodies.Keys); 
 
        // First delete untracked bodies 
        //删除未追踪到的body GameObject 
        foreach (ulong trackingId in knownIds) 
        { 
            if (!trackedIds.Contains(trackingId)) 
            { 
                Destroy(_Bodies[trackingId]); 
                _Bodies.Remove(trackingId); 
            } 
        } 
 
        //追踪到的body对象绘制body GameObject 
        foreach (var body in data) 
        { 
            if (body == null) 
            { 
                continue; 
            } 
 
            if (body.IsTracked) 
            { 
                if (!_Bodies.ContainsKey(body.TrackingId)) 
                { 
                    _Bodies[body.TrackingId] = CreateBodyObject(body.TrackingId); 
                } 
 
                RefreshBodyObject(body, _Bodies[body.TrackingId]); 
            } 
        } 
} 
[/mw_shl_code] 
CreateBodyObject函数用于在追踪到body对象时实时创建相应的body GameObject,包括代表关节的cube和连接cube的线 
[mw_shl_code=csharp,true]    /// <summary> 
    /// 根据ID创建Body对象 
    /// </summary> 
    /// <param name="id">追踪到的ID值</param> 
    /// <returns>Body对象</returns> 
    private GameObject CreateBodyObject(ulong id) 
    { 
        //依据ID给追踪到的body对象起名 
        GameObject body = new GameObject("Body:" + id); 
 
        for (Kinect.JointType jt = Kinect.JointType.SpineBase; jt <= Kinect.JointType.ThumbRight; jt++) 
        { 
            //每个关节处创建一个cube表示 
            GameObject jointObj = GameObject.CreatePrimitive(PrimitiveType.Cube); 
 
            //关节与关节连线 
            LineRenderer lr = jointObj.AddComponent<LineRenderer>(); 
            lr.SetVertexCount(2); 
            lr.material = BoneMaterial; 
            lr.SetWidth(0.05f, 0.05f); 
 
            //大小设置,名字设置,变为body的子物体 
            jointObj.transform.localScale = new Vector3(0.3f, 0.3f, 0.3f); 
            jointObj.name = jt.ToString(); 
            jointObj.transform.parent = body.transform; 
        } 
 
        return body; 
} 
[/mw_shl_code] 
GetColorForState函数定义了线条的颜色,正常追踪为绿色,未追踪到为红色,默认黑色 
[mw_shl_code=csharp,true]    /// <summary> 
    /// 设置线条颜色 
    /// </summary> 
    /// <param name="state">追踪状态</param> 
    /// <returns>颜色</returns> 
    private static Color GetColorForState(Kinect.TrackingState state) 
    { 
        switch (state) 
        { 
            case Kinect.TrackingState.Tracked: 
                return Color.green; 
 
            case Kinect.TrackingState.Inferred: 
                return Color.red; 
 
            default: 
                return Color.black; 
        } 
} 
[/mw_shl_code] 
RefreshBodyObject函数根据读取到的body对象动态绘制body GameObject,并且根据不同的追踪状态绘制不同颜色的线条 
[mw_shl_code=csharp,true]    /// <summary> 
    /// 更新骨骼游戏物体BodyObject 
    /// </summary> 
    /// <param name="body">Kinect读取到的body对象</param> 
    /// <param name="bodyObject">绘制出的body GameObject</param> 
    private void RefreshBodyObject(Kinect.Body body, GameObject bodyObject) 
    { 
        //遍历每一个关节jt,SpineBase序号为0,ThumbRight序号最大 
        for (Kinect.JointType jt = Kinect.JointType.SpineBase; jt <= Kinect.JointType.ThumbRight; jt++) 
        { 
            //sourceJoint为连接线条的起点关节 
            Kinect.Joint sourceJoint = body.Joints[jt]; 
            //targetJoint为连接线条的末点关节 
            Kinect.Joint? targetJoint = null; 
 
            //将每次循环到的关节jt的母节点赋值给targetJoint 
            if (_BoneMap.ContainsKey(jt)) 
            { 
                targetJoint = body.Joints[_BoneMap[jt]]; 
            } 
 
            //根据sourceJoint的坐标*10后给遍历到的关节jt设置坐标 
            Transform jointObj = bodyObject.transform.FindChild(jt.ToString()); 
            jointObj.localPosition = GetVector3FromJoint(sourceJoint); 
 
            //获取线条渲染组件 
            LineRenderer lr = jointObj.GetComponent<LineRenderer>(); 
            if (targetJoint.HasValue) 
            { 
                //线条起点 
                lr.SetPosition(0, jointObj.localPosition); 
                //线条末点(与起点一样,坐标*10) 
                lr.SetPosition(1, GetVector3FromJoint(targetJoint.Value)); 
                //根据追踪状态设置颜色 
                lr.SetColors(GetColorForState(sourceJoint.TrackingState), GetColorForState(targetJoint.Value.TrackingState)); 
            } 
            else 
            { 
                lr.enabled = false; 
            } 
        } 
} 
 
    /// <summary> 
    /// 坐标*10,用于绘制连接线条 
    /// </summary> 
    /// <param name="joint">关节对象</param> 
    /// <returns>*10后的坐标</returns> 
    private static Vector3 GetVector3FromJoint(Kinect.Joint joint) 
    { 
        return new Vector3(joint.Position.X * 10, joint.Position.Y * 10, joint.Position.Z * 10); 
    }[/mw_shl_code] 
 |   
 
 
 
 |