【摘 要】本文論述了通過(guò)使用Kinect體感設(shè)備識(shí)別人體的特定姿勢(shì),并以此作為輸入來(lái)控制視角移動(dòng)進(jìn)行虛擬三維場(chǎng)景漫游的關(guān)鍵技術(shù)。以Unity3D為平臺(tái),通過(guò)使用OpenNI提供的驅(qū)動(dòng)及組件進(jìn)行實(shí)現(xiàn)。
【關(guān)鍵詞】Kinect 姿勢(shì)識(shí)別 OpenNI Unity3D 虛擬漫游
一、前言
很多人操作電腦時(shí)都要通過(guò)鼠標(biāo)和鍵盤(pán)等傳統(tǒng)的交互方式,本文研究的目的是找到一個(gè)通過(guò)識(shí)別人體姿勢(shì)來(lái)控制電腦程序的方法,雖然現(xiàn)在有很多的電視游戲通過(guò)姿勢(shì)識(shí)別作為輸入,但同樣的電腦程序卻不是很多。本文描述了一種通過(guò)姿勢(shì)識(shí)別來(lái)控制三維場(chǎng)景漫游程序的方法。
二、虛擬漫游系統(tǒng)概述
隨著計(jì)算機(jī)技術(shù)的飛速發(fā)展,交互技術(shù)逐漸從二維平面向三維空間轉(zhuǎn)變,虛擬現(xiàn)實(shí)作為一種三維交互手段,在近年來(lái)取得了飛速的發(fā)展。Unity3D是近年來(lái)出現(xiàn)的一款虛擬現(xiàn)實(shí)及三維游戲開(kāi)發(fā)軟件,具有實(shí)時(shí)渲染、跨平臺(tái)、腳本控制等特點(diǎn),現(xiàn)在已經(jīng)廣泛應(yīng)用于各個(gè)領(lǐng)域。本文實(shí)現(xiàn)的系統(tǒng)由Unity3D開(kāi)發(fā),先將建好的3D模型導(dǎo)入到Unity3D中,之后通過(guò)用戶的姿勢(shì)識(shí)別作為輸入來(lái)控制視角的前后左右移動(dòng)和旋轉(zhuǎn),從而實(shí)現(xiàn)虛擬漫游的效果。
Kinect是微軟為Xbox360游戲機(jī)開(kāi)發(fā)的一款體感輸入設(shè)備。通過(guò)這個(gè)外設(shè),可以使用戶不用去觸摸傳統(tǒng)的游戲控制器而通過(guò)自然交互的方式用身體姿勢(shì)和語(yǔ)音來(lái)和游戲或程序進(jìn)行交互。一個(gè)Kinect不只包括一個(gè)RGB攝像頭,還包括紅外攝像頭和深度傳感器,用來(lái)生成場(chǎng)景中的深度數(shù)據(jù),通過(guò)分析這些數(shù)據(jù)可以得到場(chǎng)景中人的信息。本文的虛擬漫游系統(tǒng)利用Kinect得到用戶的姿勢(shì)信息,并通過(guò)判斷姿勢(shì)的類(lèi)型來(lái)控制視角的移動(dòng)方式。
OpenNI(Open Natural Interaction開(kāi)放自然交互)是一個(gè)多語(yǔ)言,跨平臺(tái)的框架,它定義了利用自然交互編寫(xiě)應(yīng)用程序的API。OpenNI通常和NITE中間件組件(對(duì)原始數(shù)據(jù)進(jìn)行分析的組件)一起使用。利用OpenNI+NITE可以讀取設(shè)備產(chǎn)生的場(chǎng)景數(shù)據(jù),并通過(guò)分析得到更高層次的數(shù)據(jù),比如用戶骨架、用戶手心位置等。本文的系統(tǒng)利用OpenNI提供的Unity3D插件包進(jìn)行實(shí)現(xiàn),使Unity3D和Kinect進(jìn)行通信,從而得到所需要的身體數(shù)據(jù)。
三、虛擬漫游系統(tǒng)的實(shí)現(xiàn)
(一)環(huán)境配置
首先安裝OpenNI+NITE程序包,之后安裝PrimeSense提供的體感設(shè)備驅(qū)動(dòng),安裝完成后將Kinect連接至電腦,如果OpenNI的示例程序可以運(yùn)行,就說(shuō)明安裝成功。然后將OpenNI-unity插件包導(dǎo)入到Unity3D中,即可進(jìn)行開(kāi)發(fā)。
(二)搭建場(chǎng)景
由于Unity3D不具備建立復(fù)雜模型的功能,所以復(fù)雜場(chǎng)景需要在3dmax等建模軟件中建模之后導(dǎo)入U(xiǎn)nity3D中。先將模型導(dǎo)出為FBX格式,之后將貼圖和模型放在一個(gè)文件夾中,再將此文件夾一起拖入unity3D的project面板中,即可使導(dǎo)入的模型帶有原來(lái)的貼圖。之后再創(chuàng)建簡(jiǎn)單的地形和樹(shù)木等元素,即可搭建出一個(gè)相對(duì)完整的場(chǎng)景。
(三)編寫(xiě)代碼
編寫(xiě)代碼的目的是通過(guò)識(shí)別用戶的不同姿勢(shì)來(lái)控制攝像機(jī)的移動(dòng)方式。在本系統(tǒng)中包括四個(gè)姿勢(shì)的識(shí)別,即向前,向后,左轉(zhuǎn)和右轉(zhuǎn)。當(dāng)用戶右腳向前保持不動(dòng)時(shí),即識(shí)別為向前的姿勢(shì),同理右腳向后時(shí)即識(shí)別為向后的姿勢(shì),左手臂向前抬起時(shí)為左轉(zhuǎn)的姿勢(shì),右手臂向前抬起則為右轉(zhuǎn)的姿勢(shì)。
每個(gè)姿勢(shì)需要編寫(xiě)兩個(gè)C#腳本。
以左轉(zhuǎn)的姿勢(shì)為例,需要編寫(xiě)NITurnleftPoseDetector和NITurnleftPoseGestureFactory兩個(gè)腳本。其中第一個(gè)是左轉(zhuǎn)的姿勢(shì)檢測(cè)器,繼承自NIGestureTracker,第二個(gè)是左轉(zhuǎn)的姿勢(shì)生成器,繼承自NIGestureFactory。
在NITurnleftPoseGestureFactory中,分別定義四個(gè)變量m_timeToHoldPose、m_maxMoveSpeed、m_timeToSavePoints、m_angleTolerance,分別表示保持姿勢(shì)多長(zhǎng)時(shí)間能被識(shí)別、每個(gè)點(diǎn)能被識(shí)別的最大速度、計(jì)算所有點(diǎn)平均值的時(shí)間、所允許的角度誤差。之后通過(guò)重寫(xiě)父類(lèi)的GetNewTrackerObject()方法來(lái)返回左轉(zhuǎn)姿勢(shì)的姿勢(shì)檢測(cè)器,主要代碼如下:
protected override NIGestureTracker GetNewTrackerObject(){
NITurnleftPoseDetector gestureTracker=new NITurnleftPoseDetector (m_timeToHoldPose,m_maxMoveSpeed,m_angleTolerance,m_timeToSavePoints);
return gestureTracker; }
這樣在腳本中就生成了一個(gè)左轉(zhuǎn)的姿勢(shì)檢測(cè)器,在場(chǎng)景中可以調(diào)用。
在NITurnleftPoseDetector中,需要先定義兩個(gè)NITimedPointSpeedListUtility 類(lèi)型的變量m_pointsLeftHand和m_pointsLeftElbow,分別用來(lái)裝載左手和左肘部位識(shí)別到的點(diǎn)。因?yàn)檫@個(gè)動(dòng)作的識(shí)別需要用到這兩個(gè)部位的數(shù)據(jù)(左手抬起的動(dòng)作只要滿足左手到左肘的向量和向上的向量成90度角,同時(shí)和向左的向量成90度角)。
之后進(jìn)行姿勢(shì)的判斷,主要代碼如下:
protected bool TestTurnleftPose(out int numPoints){
//計(jì)算左手和左肘的平均位置
Vector3 leftHandPos=m_pointsLeftHand.GetAvgPos(m_timeToHoldPose, out numPoints);
Vector3 leftElbowPos=m_pointsLeftElbow.GetAvgPos(m_timeToHoldPose, out numPoints);
//計(jì)算出代表左臂的向量
Vector3 leftDir=leftHandPos-leftElbowPos;
//計(jì)算左臂向量和向上(向左)向量的角度并根據(jù)允許誤差進(jìn)行判斷
float angle2=Vector3.Angle(Vector3.up, leftDir.normalized);
if (Mathf.Abs(angle2 - 90.0f) > m_angleTolerance) return 1;
float angle3=Vector3.Angle(leftDir.normalized,Vector3.left);
if (Mathf.Abs(angle3 - 90.0f) >m_angleTolerance) return 1;
return true;
}
然在每一幀進(jìn)行運(yùn)算,如果滿足保持這個(gè)姿勢(shì)的條件,則發(fā)送一個(gè)產(chǎn)生姿勢(shì)的事件。 這樣就完成了姿勢(shì)檢測(cè)的工作。四個(gè)動(dòng)作的腳本需要分別進(jìn)行編寫(xiě),之后在Unity3D中進(jìn)行整合。
(四)整合場(chǎng)景
在Unity3D中要對(duì)寫(xiě)完的代碼進(jìn)行整合,還要用到OpenNI提供的部分組件。
1.在場(chǎng)景中添加OpenNISettings組件,這是進(jìn)行OpenNI開(kāi)發(fā)所必須要加入的組件,它配置整個(gè)程序的上下文環(huán)境;
2.新建物體并加入NIPlayerManagerCOMSelection腳本,并將Max Allowed Players選項(xiàng)設(shè)為1,它用來(lái)選擇距離攝像頭最近的一名用戶作為玩家進(jìn)行跟蹤;
3.新建物體并加入NISkeletonTracker腳本,并將Joint To Track選項(xiàng)設(shè)為“RightHand”,并設(shè)置其相對(duì)于“Torso”的大致位置,它用來(lái)選擇用戶骨架的一個(gè)部位進(jìn)行跟蹤;
4.新建四個(gè)物體,分別加入之前寫(xiě)的四個(gè)“NI…PoseGestureFactory”腳本,用來(lái)將四個(gè)姿勢(shì)加入到場(chǎng)景中;
5.新建物體命名為“InputController”,并加入NIInput腳本,然后為當(dāng)前物體新建兩個(gè)子物體并分別加入NIGestureManager腳本和NIPointTrackersManager腳本,前者的Gestures集合數(shù)量設(shè)為4,并分別指定為之前加入到場(chǎng)景的四個(gè)姿勢(shì);后者的Trackers集合數(shù)量設(shè)為1,并指定為之前添加的Tracker物體;之后再設(shè)置NIInput腳本的Axes數(shù)量為4,這是用來(lái)設(shè)置輸入的四個(gè)軸向的值,分別檢測(cè)四個(gè)姿勢(shì)的發(fā)生,以第一個(gè)左轉(zhuǎn)為例,名字選項(xiàng)為“turnleft”,Gesture選項(xiàng)為“TurnleftPoseGesture”,Type選項(xiàng)為“Gesture”,Tracker to Use選項(xiàng)為“skeleton tracker for player 0 tracking RightHand”,剩余的三個(gè)依此進(jìn)行設(shè)置即可。
6.上述步驟完成后,在攝像機(jī)上新建c#腳本即可在OnGUI()方法中調(diào)用此輸入來(lái)控制攝像機(jī)的移動(dòng)及旋轉(zhuǎn),以左轉(zhuǎn)姿勢(shì)為例,主要代碼如下:
if (NIInput.GetAxis(\"turnleft\")>=1.0f) {transform.Rotate(0,-0.3f,0); }
所有工作完成后,點(diǎn)擊運(yùn)行按鈕即可實(shí)現(xiàn)使用人體姿勢(shì)來(lái)控制場(chǎng)景的虛擬漫游了。
四、總結(jié)
虛擬現(xiàn)實(shí)技術(shù)的飛速發(fā)展引領(lǐng)著交互方式的不斷創(chuàng)新,以Kinect等體感設(shè)備為硬件的體感交互方式必將在未來(lái)的虛擬現(xiàn)實(shí)領(lǐng)域中占有舉足輕重的地位,基于體感交互的電腦程序也會(huì)越來(lái)越多的出現(xiàn)在我們的生活和工作中。本文介紹的體感交互方法還有一些不足的地方,比如攝像機(jī)的移動(dòng)不夠流暢等,還需要進(jìn)一步的優(yōu)化。相信在以后的虛擬現(xiàn)實(shí)世界中,體感的應(yīng)用將會(huì)更廣泛,更完善。
參考文獻(xiàn):
[1]Menard, Michelle. Game Development with Unity . Delmar Cengage Learning. 2011-1
[2]OpenNI User Guide.
[3]OpenNI Unity Toolkit Html Help. 2011 PrimeSense Ltd.