|
本帖最后由 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]
|
|