亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

HTML5開(kāi)發(fā)Kinect體感游戲的實(shí)例應(yīng)用

 更新時(shí)間:2017年09月18日 16:42:31   作者:萬(wàn)波  
這篇文章主要介紹了HTML5開(kāi)發(fā)Kinect體感游戲的實(shí)例應(yīng)用的相關(guān)資料,希望通過(guò)本文能夠幫助到大家,需要的朋友可以參考下

HTML5開(kāi)發(fā)Kinect體感游戲的實(shí)例應(yīng)用

一、簡(jiǎn)介

我們要做的是怎樣一款游戲?

  在前不久成都TGC2016展會(huì)上,我們開(kāi)發(fā)了一款《火影忍者手游》的體感游戲,主要模擬手游章節(jié)《九尾襲來(lái) 》,用戶化身四代,與九尾進(jìn)行對(duì)決,吸引了大量玩家參與。 表面上看,這款游戲與其它體感體驗(yàn)無(wú)異,實(shí)際上,它一直運(yùn)行于瀏覽器Chrome下,也就是說(shuō),我們只需要掌握前端相應(yīng)技術(shù),就可以開(kāi)發(fā)基于Kinect的網(wǎng)頁(yè)體感游戲。

二、實(shí)現(xiàn)原理

實(shí)現(xiàn)思路是什么?

  使用H5開(kāi)發(fā)基于Kinect的體感游戲,其實(shí)工作原理很簡(jiǎn)單,由Kinect采集到玩家及環(huán)境數(shù)據(jù),比如人體骨骼,使用某種方式,使瀏覽器可以訪問(wèn)這些數(shù)據(jù)。

1、采集數(shù)據(jù)

  Kinect有三個(gè)鏡頭,中間鏡頭類似普通攝像頭,獲取彩色圖像。左右兩邊鏡頭則是通過(guò)紅外線獲取深度數(shù)據(jù)。我們使用微軟提供的SDK去讀取以下類型數(shù)據(jù):

  • 色彩數(shù)據(jù):彩色圖像;
  • 深度數(shù)據(jù):顏色嘗試信息;
  • 人體骨骼數(shù)據(jù):基于以上數(shù)據(jù)經(jīng)計(jì)算,獲取到人體骨骼數(shù)據(jù)。

2、使瀏覽器可訪問(wèn)到Kinect數(shù)據(jù)

我嘗試和了解過(guò)的框架,基本上是以socket讓瀏覽器進(jìn)程與服務(wù)器進(jìn)行通信 ,進(jìn)行數(shù)據(jù)傳輸:

  • Kinect-HTML5 用C#搭建服務(wù)端,色彩數(shù)據(jù)、嘗試數(shù)據(jù)、骨骼數(shù)據(jù)均有提供;
  • ZigFu 支持H5、U3D、Flash進(jìn)行開(kāi)發(fā),API較為完整,貌似收費(fèi);
  • DepthJS  以瀏覽器插件形式提供數(shù)據(jù)訪問(wèn);
  • Node-Kinect2 以Nodejs搭建服務(wù)器端,提供數(shù)據(jù)比較完整,實(shí)例較多。

我最終選用Node-Kinect2,雖然沒(méi)有文檔,但是實(shí)例較多,使用前端工程師熟悉的Nodejs,另外作者反饋比較快。

  • Kinect: 捕獲玩家數(shù)據(jù),比如深度圖像、彩色圖像等;
  • Node-Kinect2: 從Kinect獲取相應(yīng)數(shù)據(jù),并進(jìn)行二次加工;
  • 瀏覽器: 監(jiān)聽(tīng)node應(yīng)用指定接口,獲取玩家數(shù)據(jù)并完成游戲開(kāi)發(fā)。

 三、準(zhǔn)備工作

先得買個(gè)Kinect啊

1、系統(tǒng)要求:
這是硬性要求,我曾在不符合要求的環(huán)境下浪費(fèi)太多時(shí)間。

  • USB3.0
  • 支持DX11的顯卡
  • win8及以上系統(tǒng)
  • 支持Web Sockets的瀏覽器
  • 當(dāng)然Kinect v2傳感器是少不了的

2、環(huán)境搭建流程:

npm install kinect2

四、實(shí)例演示

說(shuō)什么都不如給我一個(gè)例子!

如下圖所示,我們演示如何獲取人體骨骼,并標(biāo)識(shí)脊椎中段及手勢(shì):

1、服務(wù)器端

創(chuàng)建web服務(wù)器,并將骨骼數(shù)據(jù)發(fā)送到瀏覽器端,代碼如下:

var Kinect2 = require('../../lib/kinect2'),
  express = require('express'),
  app = express(),
  server = require('http').createServer(app),
  io = require('socket.io').listen(server);
 
var kinect = new Kinect2();
// 打開(kāi)kinect
if(kinect.open()) {
  // 監(jiān)聽(tīng)8000端口
  server.listen(8000);
  // 指定請(qǐng)求指向根目錄
  app.get('/', function(req, res) {
    res.sendFile(__dirname + '/public/index.html');
  });
  // 將骨骼數(shù)據(jù)發(fā)送給瀏覽器端
  kinect.on('bodyFrame', function(bodyFrame){
    io.sockets.emit('bodyFrame', bodyFrame);
  });
  // 開(kāi)始讀取骨骼數(shù)據(jù)
  kinect.openBodyReader();
}

2、瀏覽器端

瀏覽器端獲取骨骼數(shù)據(jù),并用canvas描繪出來(lái),關(guān)鍵代碼如下:

var socket = io.connect('/');
var ctx = canvas.getContext('2d');
socket.on('bodyFrame', function(bodyFrame){
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  var index = 0;
  // 遍歷所有骨骼數(shù)據(jù)
  bodyFrame.bodies.forEach(function(body){
    if(body.tracked) {
      for(var jointType in body.joints) {
        var joint = body.joints[jointType];
        ctx.fillStyle = colors[index];
        // 如果骨骼節(jié)點(diǎn)為脊椎中點(diǎn)
        if(jointType == 1) {
          ctx.fillStyle = colors[2];
        }
        ctx.fillRect(joint.depthX * 512, joint.depthY * 424, 10, 10);
      }
      // 識(shí)別左右手手勢(shì)
      updateHandState(body.leftHandState, body.joints[7]);
      updateHandState(body.rightHandState, body.joints[11]);
      index++;
    }
  });
});

很簡(jiǎn)單的幾行代碼,我們便完成了玩家骨骼捕獲,有一定 javascript基礎(chǔ)的同學(xué)應(yīng)該很容易能看明白,但不明白的是我們能獲取哪些數(shù)據(jù)?如何獲???骨骼節(jié)點(diǎn)名稱分別是什么?而node-kienct2并沒(méi)有文檔告訴我們這些。

 五、開(kāi)發(fā)文檔

Node-Kinect2并沒(méi)有提供文檔,我將我測(cè)試總結(jié)的文檔整理如下:

1、服務(wù)器端能提供的數(shù)據(jù)類型;

kinect.on('bodyFrame', function(bodyFrame){}); //還有哪些數(shù)據(jù)類型呢?

bodyFrame 骨骼數(shù)據(jù)
infraredFrame 紅外數(shù)據(jù)
longExposureInfraredFrame 類似infraredFrame,貌似精度更高,優(yōu)化后的數(shù)據(jù)
rawDepthFrame 未經(jīng)處理的景深數(shù)據(jù)
depthFrame 景深數(shù)據(jù)
colorFrame 彩色圖像
multiSourceFrame 所有數(shù)據(jù)
audio 音頻數(shù)據(jù),未測(cè)試

 2、骨骼節(jié)點(diǎn)類型

body.joints[11] // joints包括哪些呢?

節(jié)點(diǎn)類型 JointType 節(jié)點(diǎn)名稱
0 spineBase 脊椎基部
1 spineMid  脊椎中部
2 neck 頸部
3 head 頭部
4 shoulderLeft 左肩
5 elbowLeft 左肘
6 wristLeft 左腕
7 handLeft 左手掌
8 shoulderRight 右肩
9 elbowRight 右肘
10 wristRight 右腕
11 handRight 右手掌
12 hipLeft 左屁
13 kneeLeft 左膝
14 ankleLeft 左踝
15 footLeft 左腳
16 hipRight 右屁
17 kneeRight 右膝
18 ankleRight 右踝
19 footRight 右腳
20 spineShoulder 頸下脊椎
21 handTipLeft 左手指(食中無(wú)小)
22 thumbLeft 左拇指
23 handTipRight 右手指
24 thumbRight 右拇指

 

3、手勢(shì),據(jù)測(cè)識(shí)別并不是太準(zhǔn)確,在精度要求不高的情況下使用

0 unknown 不能識(shí)別
1 notTracked 未能檢測(cè)到
2 open 手掌
3 closed 握拳
4 lasso 剪刀手,并合并中食指

 4、骨骼數(shù)據(jù)

body [object] {
 bodyIndex [number]:索引,允許6人
 joints [array]:骨骼節(jié)點(diǎn),包含坐標(biāo)信息,顏色信息
 leftHandState [number]:左手手勢(shì)
 rightHandState [number]:右手手勢(shì)
 tracked [boolean]:是否捕獲到
 trackingId
} 

5、kinect對(duì)象

on 監(jiān)聽(tīng)數(shù)據(jù)
open 打開(kāi)Kinect
close 關(guān)閉
openBodyReader 讀取骨骼數(shù)據(jù)
open**Reader 類似如上方法,讀取其它類型數(shù)據(jù)

 六、實(shí)戰(zhàn)總結(jié)

火影體感游戲經(jīng)驗(yàn)總結(jié)

接下來(lái),我總結(jié)一下TGC2016《火影忍者手游》的體感游戲開(kāi)發(fā)中碰到的一些問(wèn)題。

1、講解之前,我們首先需要了解下游戲流程。

1.1、通過(guò)手勢(shì)觸發(fā)開(kāi)始游戲

1.2、玩家化身四代,左右跑動(dòng)躲避九尾攻擊

1.3、擺出手勢(shì)“奧義”,觸發(fā)四代大招

1.4、用戶掃描二維碼獲取自己現(xiàn)場(chǎng)照片

2、服務(wù)器端

游戲需要玩家骨骼數(shù)據(jù)(移動(dòng)、手勢(shì)),彩色圖像數(shù)據(jù)(某一手勢(shì)下觸發(fā)拍照),所以我們需要向客戶端發(fā)送這兩部分?jǐn)?shù)據(jù)。值得注意的是,彩色圖像數(shù)據(jù)體積過(guò)大,需要進(jìn)行壓縮。

var emitColorFrame = false;
io.sockets.on('connection', function (socket){
  socket.on('startColorFrame', function(data){
    emitColorFrame = true;
  });
});
kinect.on('multiSourceFrame', function(frame){
 
  // 發(fā)送玩家骨骼數(shù)據(jù)
  io.sockets.emit('bodyFrame', frame.body);
 
  // 玩家拍照
  if(emitColorFrame) {
    var compression = 1;
    var origWidth = 1920;
    var origHeight = 1080;
    var origLength = 4 * origWidth * origHeight;
    var compressedWidth = origWidth / compression;
    var compressedHeight = origHeight / compression;
    var resizedLength = 4 * compressedWidth * compressedHeight;
    var resizedBuffer = new Buffer(resizedLength);
    // ...
    // 照片數(shù)據(jù)過(guò)大,需要壓縮提高傳輸性能
    zlib.deflate(resizedBuffer, function(err, result){
      if(!err) {
        var buffer = result.toString('base64');
        io.sockets.emit('colorFrame', buffer);
      }
    });    
    emitColorFrame = false;
  }
});
kinect.openMultiSourceReader({
  frameTypes: Kinect2.FrameType.body | Kinect2.FrameType.color
});

3、客戶端

客戶端業(yè)務(wù)邏輯較復(fù)雜,我們提取關(guān)鍵步驟進(jìn)行講解。

3.1、用戶拍照時(shí),由于處理的數(shù)據(jù)比較大,為防止頁(yè)面出現(xiàn)卡頓,我們需要使用web worker

(function(){
  importScripts('pako.inflate.min.js');
 
  var imageData;
  function init() {
    addEventListener('message', function (event) {
      switch (event.data.message) {
        case "setImageData":
          imageData = event.data.imageData;
          break;
        case "processImageData":
          processImageData(event.data.imageBuffer);
          break;
      }
    });
  }
  function processImageData(compressedData) {
    var imageBuffer = pako.inflate(atob(compressedData));
    var pixelArray = imageData.data;
    var newPixelData = new Uint8Array(imageBuffer);
    var imageDataSize = imageData.data.length;
    for (var i = 0; i < imageDataSize; i++) {
      imageData.data[i] = newPixelData[i];
    }
    for(var x = 0; x < 1920; x++) {
      for(var y = 0; y < 1080; y++) {
        var idx = (x + y * 1920) * 4;
        var r = imageData.data[idx + 0];
        var g = imageData.data[idx + 1];
        var b = imageData.data[idx + 2];
      }
    }
    self.postMessage({ "message": "imageReady", "imageData": imageData });
  }
  init();
})(); 

3.2、接投影儀后,如果渲染面積比較大,會(huì)出現(xiàn)白屏,需要關(guān)閉瀏覽器硬件加速。

3.3、現(xiàn)場(chǎng)光線較暗,其它玩家干擾,在追蹤玩家運(yùn)動(dòng)軌跡的過(guò)程中,可能會(huì)出現(xiàn)抖動(dòng)的情況,我們需要去除干擾數(shù)據(jù)。(當(dāng)突然出現(xiàn)很大位移時(shí),需要將數(shù)據(jù)移除)

var tracks = this.tracks;
var len = tracks.length;
 
// 數(shù)據(jù)過(guò)濾
if(tracks[len-1] !== window.undefined) {
  if(Math.abs(n - tracks[len-1]) > 0.2) {
    return;
  }
}
this.tracks.push(n);

3.4、當(dāng)玩家站立,只是左右少量晃動(dòng)時(shí),我們認(rèn)為玩家是站立狀態(tài)。

// 保留5個(gè)數(shù)據(jù)
if(this.tracks.length > 5) {
  this.tracks.shift();
} else {
  return;
}
 
// 位移總量
var dis = 0;
for(var i = 1; i < this.tracks.length; i++) {
  dis += this.tracks[i] - this.tracks[i-1];
}
if(Math.abs(dis) < 0.01) {
  this.stand();
} else {
  if(this.tracks[4] > this.tracks[3]) {
    this.turnRight();
  } else {
    this.turnLeft();
  }
  this.run();
}

七、展望

1、使用HTML5開(kāi)發(fā)Kinect體感游戲,降低了技術(shù)門檻,前端工程師可以輕松的開(kāi)發(fā)體感游戲;
2、大量的框架可以應(yīng)用,比如用JQuery、CreateJS、Three.js(三種不同渲染方式);
3、無(wú)限想象空間,試想下體感游戲結(jié)合webAR,結(jié)合webAudio、結(jié)合移動(dòng)設(shè)備,太可以挖掘的東西了……想想都激動(dòng)不是么!

如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

最新評(píng)論