ใน โพสต์ก่อนหน้าบน GWT Web Toolkit เราได้กล่าวถึงจุดแข็งและลักษณะของ GWT ซึ่งในการระลึกถึงแนวคิดทั่วไปช่วยให้เราสามารถแปลงซอร์สโค้ด Java เป็น JavaScript และผสมไลบรารี Java และ JavaScript ได้อย่างราบรื่น เราสังเกตว่า JavaScript ที่สร้างโดย GWT ได้รับการปรับให้เหมาะสมอย่างมาก
ในโพสต์ของวันนี้เราอยากจะเจาะลึกลงไปอีกนิดและดูการใช้งาน GWT Toolkit เราจะสาธิตวิธีที่เราสามารถใช้ประโยชน์จาก GWT เพื่อสร้างแอปพลิเคชันที่แปลกประหลาด: ความเป็นจริงยิ่ง (AR) เว็บแอปพลิเคชันที่ทำงานแบบเรียลไทม์ใน JavaScript ในเบราว์เซอร์
โอเพ่นซอร์สซอฟต์แวร์สร้างภาพ 3 มิติ
ในบทความนี้เราจะเน้นไปที่วิธีที่ GWT ช่วยให้เราสามารถโต้ตอบกับ JavaScript API ได้อย่างง่ายดายเช่น WebRTC และ WebGL และช่วยให้เราสามารถใช้งานไลบรารี Java ขนาดใหญ่ NyARToolkit ซึ่งไม่เคยมีไว้เพื่อใช้ในเบราว์เซอร์ เราจะแสดงให้เห็นว่า GWT อนุญาตให้ทีมของฉันและฉันที่ Jooink เพื่อรวบรวมชิ้นส่วนเหล่านี้ทั้งหมดเข้าด้วยกันเพื่อสร้างโครงการสัตว์เลี้ยงของเรา Picshare แอปพลิเคชัน AR ที่ใช้เครื่องหมายซึ่งคุณสามารถลองใช้ในเบราว์เซอร์ของคุณ ตอนนี้ .
โพสต์นี้ไม่ได้เป็นคำแนะนำแบบครอบคลุมเกี่ยวกับวิธีสร้างแอปพลิเคชัน แต่จะแสดงการใช้ GWT เพื่อเอาชนะความท้าทายที่ดูเหมือนจะท่วมท้นได้อย่างง่ายดาย
Picshare ใช้ความเป็นจริงเสริมที่ใช้เครื่องหมาย แอปพลิเคชัน AR ประเภทนี้ค้นหาฉากสำหรับไฟล์ เครื่องหมาย : รูปแบบทางเรขาคณิตที่เฉพาะเจาะจงและจดจำได้ง่าย แบบนี้ . เครื่องหมายให้ข้อมูลเกี่ยวกับตำแหน่งและการวางแนวของวัตถุที่ทำเครื่องหมายไว้ทำให้ซอฟต์แวร์สามารถฉายภาพทิวทัศน์ 3 มิติเพิ่มเติมในภาพได้อย่างสมจริง ขั้นตอนพื้นฐานในกระบวนการนี้คือ:
การใช้ JavaScript API เช่น WebGL และ WebRTC ช่วยให้เกิดการโต้ตอบที่ไม่คาดคิดและผิดปกติระหว่างเบราว์เซอร์และผู้ใช้
ตัวอย่างเช่น WebGL อนุญาตให้ใช้กราฟิกที่เร่งด้วยฮาร์ดแวร์และด้วยความช่วยเหลือของไฟล์ พิมพ์อาร์เรย์ สเปคช่วยให้เอ็นจิ้น JavaScript สามารถรันหมายเลขที่มีประสิทธิภาพเกือบดั้งเดิม ในทำนองเดียวกันกับ WebRTC เบราว์เซอร์สามารถเข้าถึงสตรีมวิดีโอ (และข้อมูลอื่น ๆ ) ได้โดยตรงจากฮาร์ดแวร์คอมพิวเตอร์
WebGL และ WebRTC ต่างก็เป็นไลบรารี JavaScript ที่ต้องสร้างไว้ในเว็บเบราว์เซอร์ เบราว์เซอร์ HTML5 ที่ทันสมัยส่วนใหญ่มาพร้อมกับการสนับสนุนอย่างน้อยบางส่วนสำหรับทั้งสอง API (ดังที่คุณเห็น ที่นี่ และ ที่นี่ ). แต่เราจะควบคุมเครื่องมือเหล่านี้ใน GWT ซึ่งเขียนด้วย Java ได้อย่างไร? เช่น กล่าวไว้ในโพสต์ก่อนหน้านี้ , ชั้นความสามารถในการทำงานร่วมกันของ GWT, JsInterop (เปิดตัวอย่างเป็นทางการใน GWT 2.8) ทำให้เค้กชิ้นนี้
การใช้ JsInterop กับ GWT 2.8 นั้นง่ายพอ ๆ กับการเพิ่ม -generateJsInteropExports
เป็นอาร์กิวเมนต์ของคอมไพเลอร์ คำอธิบายประกอบที่มีอยู่กำหนดไว้ในแพ็คเกจ jsinterop.annotations
รวมอยู่ใน gwt-user.jar
ตัวอย่างเช่นด้วยงานเขียนโค้ดเพียงเล็กน้อยโดยใช้ getUserMedia
ของ WebRTC บน Chrome ด้วย GWT กลายเป็นเรื่องง่ายเหมือนการเขียน:
Navigator.webkitGetUserMedia( configs, stream -> video.setSrc( URL.createObjectURL(stream) ), e -> Window.alert('Error: ' + e) );
ที่ชั้นเรียน Navigator
สามารถกำหนดได้ดังนี้:
@JsType(namespace = JsPackage.GLOBAL, isNative = true, name='navigator') final static class Navigator { public static native void webkitGetUserMedia( Configs configs, SuccessCallback success, ErrorCallback error); }
สิ่งที่น่าสนใจคือคำจำกัดความของอินเทอร์เฟซ SuccessCallback
และ ErrorCallback
ทั้งสองใช้งานโดยนิพจน์แลมบ์ดาด้านบนและกำหนดใน Java โดยใช้ @JsFunction
คำอธิบายประกอบ:
@JsFunction public interface SuccessCallback { public void onMediaSuccess(MediaStream stream); } @JsFunction public interface ErrorCallback { public void onError(DomException error); }
สุดท้ายคำจำกัดความของคลาส URL
เกือบจะเหมือนกันกับ Navigator
และในทำนองเดียวกัน Configs
คลาสสามารถกำหนดได้โดย:
@JsType(namespace = JsPackage.GLOBAL, isNative = true, name='Object') public static class Configs { @JsProperty public native void setVideo(boolean getVideo); }
การนำฟังก์ชันทั้งหมดนี้ไปใช้จริงเกิดขึ้นในเอ็นจิ้น JavaScript ของเบราว์เซอร์
คุณสามารถค้นหาโค้ดด้านบนได้ใน GitHub ที่นี่ .
ในตัวอย่างนี้เพื่อความเรียบง่ายการเลิกใช้งาน navigator.getUserMedia()
API ถูกใช้เนื่องจากเป็น API เดียวที่ทำงานโดยไม่ต้องเติม polyfilling ใน Chrome เวอร์ชันเสถียรปัจจุบัน ในแอปที่ใช้งานจริงเราสามารถใช้ไฟล์ adapter.js เพื่อเข้าถึงสตรีมผ่านทางที่ใหม่กว่า navigator.mediaDevices.getUserMedia()
API เหมือนกันในทุกเบราว์เซอร์ แต่สิ่งนี้อยู่นอกเหนือขอบเขตของการอภิปรายในปัจจุบัน
การใช้ WebGL จาก GWT นั้นไม่แตกต่างกันมากนักเมื่อเทียบกับการใช้ WebRTC แต่มันน่าเบื่อกว่าเล็กน้อยเนื่องจากความซับซ้อนภายในของมาตรฐาน OpenGL
แนวทางของเราตรงนี้สะท้อนให้เห็นถึงแนวทางที่ปฏิบัติตามในส่วนก่อนหน้า ผลลัพธ์ของการห่อสามารถเห็นได้ในการใช้งาน GWT WebGL ที่ใช้ใน Picshare ซึ่งสามารถพบได้ ที่นี่ และตัวอย่างของผลลัพธ์ที่สร้างโดย GWT สามารถพบได้ ที่นี่ .
การเปิดใช้ WebGL ด้วยตัวเองไม่ได้ทำให้เรามีความสามารถด้านกราฟิก 3D ตามที่ Gregg Tavares เขียน :
สิ่งที่หลายคนไม่รู้ก็คือจริงๆแล้ว WebGL เป็น 2D API ไม่ใช่ 3D API
การคำนวณทางคณิตศาสตร์ 3 มิติจะต้องดำเนินการโดยรหัสอื่นและเปลี่ยนเป็นภาพ 2 มิติสำหรับ WebGL มีไลบรารี GWT ที่ดีสำหรับกราฟิก 3D WebGL ที่ชอบคือ พารัลแลกซ์ แต่สำหรับเวอร์ชันแรกของ Picshare เราเดินตามเส้นทาง“ ทำด้วยตัวเอง” มากขึ้นโดยเขียนไลบรารีขนาดเล็กสำหรับการเรนเดอร์ตาข่าย 3 มิติแบบง่ายๆ ไลบรารีช่วยให้เรากำหนดไฟล์ กล้องมุมมอง และจัดการฉากของวัตถุ อย่าลังเลที่จะตรวจสอบ ที่นี่ .
NyARToolkit เป็นพอร์ต Java บริสุทธิ์ของ ARToolKit ไลบรารีซอฟต์แวร์สำหรับสร้างแอปพลิเคชันความเป็นจริงเสริม พอร์ตนี้เขียนโดยนักพัฒนาชาวญี่ปุ่นที่ Nyatla . แม้ว่า ARToolKit ดั้งเดิมและเวอร์ชัน Nyatla จะแตกต่างจากพอร์ตเดิมไปบ้าง แต่ NyARToolkit ก็ยังคงได้รับการดูแลและปรับปรุงอย่างแข็งขัน
AR ที่ใช้เครื่องหมายเป็นสาขาเฉพาะและต้องการความสามารถในการมองเห็นของคอมพิวเตอร์การประมวลผลภาพดิจิทัลและคณิตศาสตร์ดังที่เห็นได้ชัดที่นี่:
ทำซ้ำจาก เอกสาร ARToolKit .
ทำซ้ำจาก เอกสาร ARToolKit .
อัลกอริทึมทั้งหมดที่ใช้โดยชุดเครื่องมือได้รับการจัดทำเป็นเอกสารและเข้าใจเป็นอย่างดี แต่การเขียนใหม่ตั้งแต่เริ่มต้นเป็นกระบวนการที่ยาวและเกิดข้อผิดพลาดดังนั้นจึงควรใช้ชุดเครื่องมือที่มีอยู่และได้รับการพิสูจน์แล้วเช่น ARToolKit น่าเสียดายที่เมื่อกำหนดเป้าหมายไปที่เว็บไม่มีสิ่งเหล่านี้ให้บริการ ชุดเครื่องมือขั้นสูงที่ทรงพลังที่สุดไม่มีการนำไปใช้ใน JavaScript ซึ่งเป็นภาษาที่ใช้สำหรับจัดการเอกสารและข้อมูล HTML เป็นหลัก นี่คือจุดที่ GWT พิสูจน์ให้เห็นถึงความแข็งแกร่งที่ประเมินค่าไม่ได้ทำให้เราสามารถแปลง NyARToolkit เป็น JavaScript และใช้ในเว็บแอปพลิเคชันที่มีความยุ่งยากน้อยมาก
เนื่องจากโปรเจ็กต์ GWT เป็นโปรเจ็กต์ Java โดยพื้นฐานแล้วการใช้ NyARToolkit จึงเป็นเพียงการนำเข้าไฟล์ต้นทางในเส้นทางต้นทางของคุณ อย่างไรก็ตามโปรดทราบว่าเนื่องจากการถ่ายโอนโค้ด GWT ไปยัง JavaScript เสร็จสิ้นในระดับซอร์สโค้ดคุณจึงต้องมีแหล่งที่มาของ NyARToolkit ไม่ใช่แค่ JAR ที่มีคลาสที่คอมไพล์แล้ว
ห้องสมุดที่ใช้โดย Picshare สามารถพบได้ ที่นี่ . ขึ้นอยู่กับแพ็คเกจที่พบภายใน lib/src
และ lib/src.markersystem
จาก NyARToolkit build ที่เก็บถาวร ที่นี่ . เราต้องคัดลอกและนำเข้าแพ็คเกจเหล่านี้ไปยังโครงการ GWT ของเรา
เราควรแยกแพ็กเกจของบุคคลที่สามเหล่านี้ออกจากการนำไปใช้งานของเราเอง แต่ในการดำเนินการกับ“ GWT-ization” ของ NyARToolkit เราต้องจัดเตรียมไฟล์การกำหนดค่า XML ที่แจ้งให้คอมไพเลอร์ GWT ทราบว่าจะค้นหาแหล่งที่มาที่ใด ในแพ็คเกจ jp.nyatla.nyartoolkit
เราเพิ่มไฟล์ NyARToolkit.gwt.xml
com.jooink.gwt.nyartoolkit
ตอนนี้ในแพ็คเกจหลักของเรา GWT_NyARToolKit.gwt.xml
เราสร้างไฟล์คอนฟิกูเรชันหลัก No source code is available for type java.io.InputStream; did you forget to inherit a required module?
และสั่งให้คอมไพเลอร์รวมซอร์สของ Nyatla ในคลาสพา ธ โดยรับช่วงจากไฟล์ XML:
InputStream
ค่อนข้างง่ายจริง โดยส่วนใหญ่แล้วจะต้องใช้เวลาทั้งหมด แต่น่าเสียดายที่เรายังทำไม่เสร็จ หากเราพยายามรวบรวมหรือดำเนินการผ่านไฟล์ โหมด Super Dev ในขั้นตอนนี้เราพบข้อผิดพลาดที่ระบุค่อนข้างน่าประหลาดใจ:
jre
เหตุผลก็คือ NyARToolkit (นั่นคือไลบรารี Java ที่มีไว้สำหรับโปรเจ็กต์ Java) ใช้คลาสของ JRE ที่ GWT’s ไม่รองรับ JRE จำลอง . เรา พูดถึงเรื่องนี้สั้น ๆ ในโพสต์ก่อนหน้านี้
ในกรณีนี้ปัญหาคือ java.io.FileInputStream java.io.InputStream java.io.InputStreamReader java.io.StreamTokenizer java.lang.reflect.Array java.nio.ByteBuffer java.nio.ByteOrder
และคลาส IO ที่เกี่ยวข้อง เมื่อเกิดขึ้นเราไม่จำเป็นต้องใช้คลาสเหล่านี้ส่วนใหญ่ แต่เราจำเป็นต้องจัดเตรียมการนำไปใช้กับคอมไพเลอร์ เราสามารถใช้เวลาเป็นจำนวนมากในการลบข้อมูลอ้างอิงเหล่านี้ออกจากแหล่งที่มาของ NyARToolkit ด้วยตนเอง แต่มันจะบ้ามาก GWT ช่วยให้เรามีทางออกที่ดีขึ้น: จัดเตรียมการใช้งานคลาสที่ไม่สนับสนุนของเราเองผ่านแท็ก XML
ตามที่อธิบายไว้ในไฟล์ เอกสารอย่างเป็นทางการ :
แท็กจะสั่งให้คอมไพลเลอร์ทำการรูทเส้นทางต้นทางอีกครั้ง สิ่งนี้มีประโยชน์สำหรับกรณีที่คุณต้องการใช้ Java API ที่มีอยู่ซ้ำสำหรับโปรเจ็กต์ GWT แต่ซอร์สดั้งเดิมไม่พร้อมใช้งานหรือแปลไม่ได้ สาเหตุทั่วไปคือการเลียนแบบส่วนหนึ่งของ JRE ที่ GWT ไม่ได้ใช้งาน
นั่นคือสิ่งที่เราต้องการ
เราสามารถสร้าง java.lang.reflect.Array
ไดเร็กทอรีในโครงการ GWT ซึ่งเราสามารถนำการใช้งานของเราไปใช้กับคลาสที่ทำให้เรามีปัญหาได้:
FileInputStream
สิ่งเหล่านี้ทั้งหมดยกเว้น package java.io; import java.io.InputStream; import com.google.gwt.user.client.Window; public class FileInputStream extends InputStream { public FileInputStream(String filename) { Window.alert('WARNING, FileInputStream created with filename: ' + filename ); } @Override public int read() { return 0; } }
ไม่ได้ใช้งานจริง ๆ ดังนั้นเราจึงต้องการเพียงการใช้งานที่โง่เขลา ตัวอย่างเช่น Window.alert
ของเรา อ่านได้ดังนี้:
java.lang.reflect.Array
package java.lang.reflect; import jp.nyatla.nyartoolkit.core.labeling.rlelabeling.NyARRleLabelFragmentInfo; import jp.nyatla.nyartoolkit.markersystem.utils.SquareStack; import com.google.gwt.user.client.Window; public class Array { public static Object newInstance(Class c, int n) { if( NyARRleLabelFragmentInfo.class.equals(c)) return new NyARRleLabelFragmentInfo[n]; else if(SquareStack.Item.class.equals(c)) return new SquareStack.Item[n]; else Window.alert('Creating array of size ' + n + ' of ' + c.toString()); return null; } }
คำสั่งในตัวสร้างมีประโยชน์ในระหว่างการพัฒนา แม้ว่าเราจะต้องสามารถรวบรวมคลาสได้ แต่เราต้องการให้แน่ใจว่าเราไม่เคยใช้งานจริงดังนั้นสิ่งนี้จะแจ้งเตือนเราในกรณีที่ใช้คลาสโดยไม่ได้ตั้งใจ
GWT_NyARToolkit.gwt.xml
ถูกใช้จริงโดยรหัสที่เราต้องการดังนั้นจึงจำเป็นต้องมีการใช้งานที่ไม่โง่อย่างสมบูรณ์ นี่คือรหัสของเรา:
Sensor.update()
ทีนี้ถ้าเราวาง // given a drawing context with appropriate width and height // and a where the mediastream is drawn ... // for each video frame // draw the video frame on the canvas ctx.drawImage(video, 0, 0, w, h); // extract image data from the canvas ImageData capt = ctx.getImageData(0, 0, w, h); // convert the image data in a format acceptable by NyARToolkit ImageDataRaster input = new ImageDataRaster(capt); // push the image in to a NyARSensor sensor.update(input); // update the NyARMarkerSystem with the sensor nyar.update(sensor); // the NyARMarkerSystem contains information about the marker patterns and is able to detect them. // After the call to update, all the markers are detected and we can get information for each // marker that was found. if( nyar.isExistMarker( marker_id ) ) { NyARDoubleMatrix44 m = nyar.getMarkerMatrix(marker_id); // m is now the matrix representing the pose (position and orientation) of // the marker in the scene, so we can use it to superimpose an object of // our choice ... } ...
ไฟล์โมดูลเราสามารถรวบรวมและใช้ NyARToolkit ในโครงการของเราได้อย่างปลอดภัย!
ตอนนี้เราอยู่ในตำแหน่งที่มี:
ความท้าทายในตอนนี้คือการผสานรวมเทคโนโลยีเหล่านี้เข้าด้วยกัน
เราจะไม่ลงลึกถึงวิธีการทำสิ่งนี้ แต่แนวคิดพื้นฐานคือการใช้ภาพวิดีโอเป็นพื้นหลังของฉาก (พื้นผิวที่ใช้กับระนาบ 'ไกล' ในภาพด้านบน) และสร้างโครงสร้างข้อมูล 3 มิติ ทำให้เราสามารถฉายภาพนี้ในอวกาศโดยใช้ผลลัพธ์จาก NyARToolkit
โครงสร้างนี้ทำให้เรามีโครงสร้างที่เหมาะสมในการโต้ตอบกับไลบรารีของ NyARToolkit สำหรับการจดจำเครื่องหมายและวาดแบบจำลอง 3 มิติที่ด้านบนของฉากของกล้อง
การทำให้สตรีมกล้องสามารถใช้งานได้นั้นค่อนข้างยุ่งยาก ข้อมูลวิดีโอสามารถดึงไปยังองค์ประกอบเท่านั้น HTML5element นั้นทึบแสงและไม่อนุญาตให้เราดึงข้อมูลรูปภาพโดยตรงดังนั้นเราจึงถูกบังคับให้คัดลอกวิดีโอไปยังตัวกลางแยกข้อมูลรูปภาพแปลงเป็นอาร์เรย์ของพิกเซลและสุดท้ายดันไปที่ NyARToolkit's
|_+_|วิธี. จากนั้น NyARToolkit สามารถทำงานเพื่อระบุเครื่องหมายในภาพและส่งคืนเมทริกซ์การเปลี่ยนแปลงที่สอดคล้องกับตำแหน่งในพื้นที่ 3 มิติของเรา
ด้วยองค์ประกอบเหล่านี้เราสามารถจัดวางวัตถุสังเคราะห์บนเครื่องหมายในรูปแบบ 3 มิติในสตรีมวิดีโอสดได้! ด้วยประสิทธิภาพที่สูงของ GWT เรามีทรัพยากรในการคำนวณมากมายดังนั้นเราจึงสามารถใช้เอฟเฟกต์วิดีโอบางอย่างบนผืนผ้าใบเช่นซีเปียหรือเบลอก่อนที่จะใช้เป็นพื้นหลังสำหรับฉาก WebGL
รหัสย่อต่อไปนี้อธิบายถึงแกนหลักของกระบวนการ:
|_+_|
ด้วยเทคนิคนี้เราสามารถสร้างผลลัพธ์เช่นนี้:
เทมเพลตบูตสแตรปคืออะไร
นี่คือกระบวนการที่เราใช้ในการสร้าง Picshare ที่คุณได้รับเชิญไป พิมพ์ออกมา เครื่องหมายหรือ แสดงบนมือถือของคุณ และเล่นกับ AR ที่ใช้เครื่องหมายในเบราว์เซอร์ของคุณ สนุก!
Picshare เป็นโครงการสัตว์เลี้ยงระยะยาวสำหรับเราที่ Jooink การใช้งานครั้งแรกย้อนหลังไปไม่กี่ปีและถึงแม้จะเร็วพอที่จะน่าประทับใจ ที่ ลิงค์นี้ คุณสามารถดูหนึ่งในการทดลองก่อนหน้านี้ของเราซึ่งรวบรวมในปี 2012 และไม่เคยสัมผัสมาก่อน โปรดทราบว่าในตัวอย่างมีเพียงหนึ่งรายการ อีกสองหน้าต่างเป็นองค์ประกอบที่แสดงผลลัพธ์ของการประมวลผล
GWT มีประสิทธิภาพเพียงพอแม้กระทั่งในปี 2012 ด้วยการเปิดตัว GWT 2.8 เราได้รับชั้นความสามารถในการทำงานร่วมกันที่ได้รับการปรับปรุงให้ดีขึ้นมากด้วย JsInterop ซึ่งช่วยเพิ่มประสิทธิภาพ นอกจากนี้ในการเฉลิมฉลองของหลาย ๆ คนเรายังได้รับการพัฒนาที่ดีขึ้นมากและสภาพแวดล้อมการดีบักโหมด Super Dev ใช่แล้วและรองรับ Java 8
เรารอคอยที่จะ GWT 3.0!