บทเรียน Javascript กับของเล่นใหม่ Leap Motion สำหรับ Detect มือและนิ้วของเราผ่านอุปกรณ์แสกนแล้วทำการ Rigged กระดูกมือเราให้ใช้งานร่วมกับ โปรแกรมได้
ก่อนอื่นที่จะทำอะไรกับบทความนี้ได้นั้น คุณต้องมีเจ้าเครื่อง Leap Motion มาก่อน สามารถสั่งซื้อผ่านอินเทอร์เน็ตได้ ในราคา 79.99$ (http://store-us.leapmotion.com/) ไม่แพงสำหรับการเรียนรู้อะไรใหม่ๆ
ได้ของแล้วก็ทำการติดตั้งซะ
เมื่อได้ของมาแล้วก็ให้ไปดาวน์โหลดตัว Driver และ SDK ซะเลยสำหรับนักพัฒนา
ทำการติดตั้งแล้วก็เปิด Virtualize ทดสอบมันซะหน่อย
ทีนี้ก็มาพัฒนาโปรแกรมร่วมกับมันซะหน่อย อันที่จริง มันมีเกมมาให้เยอะแยะเลยนะให้เราเล่น แต่เราจะมองข้ามไป ไปพัฒนากันจริงๆ จังๆ ซึ่งรูปแบบการพัฒนามีให้เลือกอยู่มากมาย ผมจึงเลือกมาแค่ 2 แพลตฟอร์มคือ C# (Unity) กับ Javascript
เรามาเริ่ม Essential Lesson ด้วย Javascript ก่อน ตัว SDK มันก็มีให้แกะแหละครับ แต่การรับรู้ของคนเรามีไม่เท่ากันดังนั้นก็เลย ย่อยมาให้
รูปแบบ Leap Motion ตัวนี้ก็คือการ Detect จับว่ามือเรานั้นเป็นข้างไหน และมีสถานะ กำมือ หรือ แบมืออยู่
เขียน HTML ขึ้นมาก่อนเลยครับ ไฟล์ index.html
<!DOCTYPE html> <!-- DAYDEV CO., LTD. CASE STUDY--> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Leap Motion JS Hand Detect</title> <!-- SDK--> <!-- SDK--> </head> <body> <h1>Console</h1> <div id="main"> <div id="handData"></div> <div style="clear:both;"></div> </div> </body> </html>
ตัว Leap Motion จะมี SDK แบบ Online ให้เราเรียกใช้ครับ แทรก คำสั่งนี้ลงใน <!–SDK–> ได้เลย
<script src="http://js.leapmotion.com/leap-0.6.3.min.js"></script>
ให้เราทำการเขียน ฟังก์ชัน Javascript ขึ้นมาใหม่บน <head> ดังนี้ครับ
// Store frame for motion functions var previousFrame = null; var paused = false; var pauseOnGesture = false; // Setup Leap loop with frame callback function var controllerOptions = {enableGestures: true};
เป็นการตรวจสอบการ Detect Gesture ของการเคลื่อนไหวผ่าน Censor ของ Leap Motion ครับ ตามด้วย
Leap.loop(controllerOptions, function(frame) { if (paused) { return; // Skip this update } // Display Hand object data var handOutput = document.getElementById("handData"); var handString = ""; if (frame.hands.length > 0) { for (var i = 0; i < frame.hands.length; i++) { var hand = frame.hands[i]; handString += "<div style='width:400px; float:left; padding:5px'>"; handString += "ID มือ: " + hand.id + "<br />"; handString += "ข้างที่ใช้: " + hand.type + "<br />"; handString += "ทิศทาง: " + vectorToString(hand.direction, 2) + "<br />"; handString += "กำมือ: " + hand.grabStrength + "<br />"; // IDs of pointables associated with this hand if (hand.pointables.length > 0) { var fingerIds = []; for (var j = 0; j < hand.pointables.length; j++) { var pointable = hand.pointables[j]; fingerIds.push(pointable.id); } if (fingerIds.length > 0) { handString += "ID มือ และ นิ้ว: " + fingerIds.join(", ") + "<br />"; } } handString += "</div>"; } } else { handString += "No hands detect"; } handOutput.innerHTML = handString; previousFrame = frame; }) function vectorToString(vector, digits) { if (typeof digits === "undefined") { digits = 1; } return "(" + vector[0].toFixed(digits) + ", " + vector[1].toFixed(digits) + ", " + vector[2].toFixed(digits) + ")"; }
โดย Parameter ที่จำเป็นจะอยู่ส่วนนี้ครับ
var hand = frame.hands[i]; handString += "<div style='width:400px; float:left; padding:5px'>"; handString += "ID มือ: " + hand.id + "<br />"; handString += "ข้างที่ใช้: " + hand.type + "<br />"; handString += "ทิศทาง: " + vectorToString(hand.direction, 2) + "<br />"; handString += "กำมือ: " + hand.grabStrength + "<br />";
เราจะมี hand.id ไว้จับว่ามือที่ปรากฏบน censor ณ ขณะนั้นคือมือของใคร เช่น นาย A มี ID คือ 123 แล้วยกอีกมือมาเป็น 124 แต่จู่ๆ มีนาย B เดินมายกอีกข้างสักข้างมันจะนับเป็น 125 ซึ่งจะไม่มีการเรียก Detect แต่เมื่อนาย A ยกมือ 124 ลง มันจะมองว่า ระบบมีมือ 2 ข้างคือ 123 และ 125 นั่นก็คือมือคนละข้างของ A และ B
ตามด้วย hand.type จะมีการ Rigged กระดูกมือเราเสร็จสรรพ และบอกได้เลยว่าเป็นมือ ข้าง ซ้าย หรือ ขวา โดย return ค่าเป็น left, right ครับ
hand.grabStrength เป็นสถานะของการ แบมือ และ กำมือ ถ้าแบมือจะมีค่าเป็น 0 ไปเรื่อย แต่ถ้ามีสถานะกำมือเมื่อไหร มันจะกลายเป็น 1 ไว้เทียบค่าแบบ Parameter ร่วมกับ Boolean ได้
ใส่ code ลงไปเลย จะเห็นว่า ภาพรวมของ code เป็นดังนี้
<!DOCTYPE html> <!-- DAYDEV CO., LTD. CASE STUDY--> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Leap Motion JS Hand Detect</title> <script src="http://js.leapmotion.com/leap-0.6.3.min.js"></script> <script> // Store frame for motion functions var previousFrame = null; var paused = false; var pauseOnGesture = false; // Setup Leap loop with frame callback function var controllerOptions = {enableGestures: true}; Leap.loop(controllerOptions, function(frame) { if (paused) { return; // Skip this update } // Display Hand object data var handOutput = document.getElementById("handData"); var handString = ""; if (frame.hands.length > 0) { for (var i = 0; i < frame.hands.length; i++) { var hand = frame.hands[i]; handString += "<div style='width:400px; float:left; padding:5px'>"; handString += "ID มือ: " + hand.id + "<br />"; handString += "ข้างที่ใช้: " + hand.type + "<br />"; handString += "ทิศทาง: " + vectorToString(hand.direction, 2) + "<br />"; handString += "กำมือ: " + hand.grabStrength + "<br />"; // IDs of pointables associated with this hand if (hand.pointables.length > 0) { var fingerIds = []; for (var j = 0; j < hand.pointables.length; j++) { var pointable = hand.pointables[j]; fingerIds.push(pointable.id); } if (fingerIds.length > 0) { handString += "ID มือ และ นิ้ว: " + fingerIds.join(", ") + "<br />"; } } handString += "</div>"; } } else { handString += "No hands detect"; } handOutput.innerHTML = handString; previousFrame = frame; }) function vectorToString(vector, digits) { if (typeof digits === "undefined") { digits = 1; } return "(" + vector[0].toFixed(digits) + ", " + vector[1].toFixed(digits) + ", " + vector[2].toFixed(digits) + ")"; } </script> </head> <body> <h1>Console</h1> <div id="main"> <div id="handData"></div> <div style="clear:both;"></div> </div> </body> </html>
มาทดสอบกันหน่อย ผมสร้าง http://localhost/LEAP ขึ้นมาทดสอบ
ถ้าเอามือไปวาง 2 มือ มันก็จะปรากฏค่าออกมาเป็น 2 colums ให้เรารู้ว่า มือแต่ละข้างคือมือไหน ตามด้วย ID มือและนิ้ว มือ ID 168 ถ้านิ้วโป้ง 1680, นิ้วชี้ 1681 เป็นต้น
พอดี รีวิวคนเดียวเลย จับหน้าจอแบบ 2 มือไม่ได้แต่เอาเป็นว่ามันแสดงผลได้ครับ
ยังไง ต่อไปคงจะใช้ต่อยอดกับ Unity (C#) กับเกมที่ต้องใช้มือควบคุมครับ ส่วน Leap Motion เหมาะกับงานประเภทไหน ก็คงบอกตรงๆ ว่า เหมาะกับงาน Event พวก Show Case หรือเกมแนว Mo Cap ครับ