版本 : Kinect SDK 1.7
IDE : Microsoft Visual Studio 2010
XNA版本 : 4.0
在原本的 SDK 裡面提供的有WPF 以及 D2D 顯示骨架資訊。
上述在Tookit裡面可以直接打開專案來使用。
但是今天我們要在XNA裡面畫出骨架資訊。
原由: 應用於很多XNA豐富的元件以及開發環境來做出很多很棒的東西
並且在原本WPF裡面要設計一個動態的東西是不容易的。
首先 : 在原本的WPF 設計裡面。 是用Event-driven 的方式去取得骨架的frame
private void KinectSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
// 以下略
}
利用一個被動式的方法透過,事件(event)去取得frame 資料。
但是今天我們在XNA裡面,裡面的Update() 凾式。
是一直不斷地在running ,意即一直在跑無窮迴圈的意思(直到終止)
這樣我們就可以利用polling 技術去取得 frame 資料。
在XNA環境下使用polling實作起來也會比較容易些...
在原本WPF程式碼裡面的drawLine() 變成在XNA的 draw() 函式
我們先來了解一下流程吧!? (參考請點我)
簡單一點的對照圖就如上。
開始吧!
//////////////////////////////////////////////////////////////////////////////////////////////////
一開始即宣告
首先別忘記加入kinect.dll 喔
開啟XNA 專案之後。宣告要使用的變數
KinectSensor myKinect;
int[] skeletonArray = new int[40];
此處宣告了Kinect 裝置變數以及我們要儲存骨架位置資訊的陣列變數
然而在 LoadContent ()裡面要開始做 讀入資源的動作
myKinect = KinectSensor.KinectSensors[0];
myKinect.SkeletonStream.Enable();
myKinect.Start();
接著就是緊接著重要的部分 亦即作不斷的更新去polling取得frame
protected override void Update(GameTime gameTime)
{
Skeleton[] skeletons;
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
using (SkeletonFrame frameData = myKinect.SkeletonStream.OpenNextFrame(1))
{
// if frame is null , then exit
if (frameData == null)
{
//System.Console.WriteLine("no data");
return;
}
skeletons = new Skeleton[frameData.SkeletonArrayLength];
frameData.CopySkeletonDataTo(skeletons);
foreach (Skeleton skeleton in skeletons)
{
if (skeleton.TrackingState != SkeletonTrackingState.NotTracked)
{
for(int i = 0 ; i < 20 ; i++)
{
ColorImagePoint point1 = myKinect.MapSkeletonPointToColor(skeleton.Joints[(JointType)i].Position, ColorImageFormat.RgbResolution640x480Fps30);
skeletonArray[i * 2] = point1.X;
skeletonArray[i * 2 + 1] = point1.Y;
}
ColorImagePoint point2 = myKinect.MapSkeletonPointToColor(skeleton.Joints[(JointType)2].Position, ColorImageFormat.RgbResolution640x480Fps30);
}
}
}
base.Update(gameTime);
}
在上述程式碼之中 ,首先先宣告了骨架陣列 ,
接著就是使用 SkeletonStream.OpenNextFrame(1) 來"手動"取得frame
簡單來說就是在做 polling 。
整個運作流程就是每Update()一次就去手動取得frame 一次來達到polling的效果。
接著就是儲存骨架資訊的部分了。 //此處不再補充說明 , WPF範例程式有說明。
接下來就是Draw的部分了。
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// draw head to neck
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[6], skeletonArray[7]), new Vector2(skeletonArray[4], skeletonArray[5]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[4], skeletonArray[5]), new Vector2(skeletonArray[2], skeletonArray[3]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[2], skeletonArray[3]), new Vector2(skeletonArray[0], skeletonArray[1]), Color.DarkRed, 4);
// draw nack to left arm
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[4], skeletonArray[5]), new Vector2(skeletonArray[8], skeletonArray[9]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[8], skeletonArray[9]), new Vector2(skeletonArray[10], skeletonArray[11]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[10], skeletonArray[11]), new Vector2(skeletonArray[12], skeletonArray[13]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[12], skeletonArray[13]), new Vector2(skeletonArray[14], skeletonArray[15]), Color.DarkRed, 4);
// draw nack to right arm
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[4], skeletonArray[5]), new Vector2(skeletonArray[16], skeletonArray[17]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[16], skeletonArray[17]), new Vector2(skeletonArray[18], skeletonArray[19]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[18], skeletonArray[19]), new Vector2(skeletonArray[20], skeletonArray[21]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[20], skeletonArray[21]), new Vector2(skeletonArray[22], skeletonArray[23]), Color.DarkRed, 4);
// draw center to left leg
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[0], skeletonArray[1]), new Vector2(skeletonArray[24], skeletonArray[25]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[24], skeletonArray[25]), new Vector2(skeletonArray[26], skeletonArray[27]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[26], skeletonArray[27]), new Vector2(skeletonArray[28], skeletonArray[29]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[28], skeletonArray[29]), new Vector2(skeletonArray[30], skeletonArray[31]), Color.DarkRed, 4);
// draw center to right leg
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[0], skeletonArray[1]), new Vector2(skeletonArray[32], skeletonArray[33]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[32], skeletonArray[33]), new Vector2(skeletonArray[34], skeletonArray[35]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[34], skeletonArray[35]), new Vector2(skeletonArray[36], skeletonArray[37]), Color.DarkRed, 4);
spriteBatch.DrawSingleLine(new Vector2(skeletonArray[36], skeletonArray[37]), new Vector2(skeletonArray[38], skeletonArray[39]), Color.DarkRed, 4);
base.Draw(gameTime);
}
其實在跟WPF程式碼部分沒有特別不同,我們這邊特別用了
第三方寫的class去使用畫筆的部分。
因為在XNA裡面畫基本圖形是比較困難複雜的,必須要考量到3D世界以及攝影機觀點。
去做向量繪圖。 因此簡單的2D繪圖也會相當的困難許多。(API 點我)
結果畫面 :
( 完整程式碼請點我 )
參考資料 :
Kinect 體感程式設計入門
XNA PC / Xbox 360 C# 遊戲程式設計
Tigran's Blog
沒有留言:
張貼留言