GWT가 브라우저에서 증강 현실을 잠금 해제하는 방법

게시 됨: 2022-03-11

GWT Web Toolkit에 대한 이전 게시물에서 우리는 GWT의 강점과 특성에 대해 논의했습니다. 일반적인 아이디어를 떠올리면 Java 소스 코드를 JavaScript로 변환하고 Java와 JavaScript 라이브러리를 매끄럽게 혼합할 수 있습니다. 우리는 GWT에 의해 생성된 자바스크립트가 극적으로 최적화되었음을 주목했습니다.

오늘의 게시물에서 우리는 조금 더 깊이 들어가 GWT Toolkit이 작동하는 모습을 보고자 합니다. 우리는 GWT를 활용하여 브라우저에서 완전히 JavaScript로 실시간으로 실행되는 증강 현실(AR) 웹 응용 프로그램과 같은 독특한 응용 프로그램을 구축하는 방법을 보여줄 것입니다.

브라우저의 증강 현실? 생각보다 쉽습니다.

이 기사에서는 GWT가 WebRTC 및 WebGL과 같은 많은 JavaScript API와 쉽게 상호 작용할 수 있는 기능을 제공하고 브라우저에서 사용하도록 의도된 적이 없는 대규모 Java 라이브러리인 NyARToolkit을 활용할 수 있도록 하는 방법에 중점을 둘 것입니다. 우리는 GWT를 사용하여 Jooink의 우리 팀과 내가 이 모든 부분을 결합하여 현재 브라우저에서 시도할 수 있는 마커 기반 AR 애플리케이션인 Picshare라는 애완용 프로젝트를 만들 수 있었던 방법을 보여줄 것입니다.

이 게시물은 애플리케이션을 구축하는 방법에 대한 포괄적인 설명이 아니라 GWT를 사용하여 겉보기에 압도적인 문제를 쉽게 극복하는 방법을 보여줍니다.

프로젝트 개요: 현실에서 증강 현실로

WebRTC, WebGL 및 ARToolKit을 사용하여 GWT를 사용하는 브라우저의 마커 기반 증강 현실용 파이프라인.

Picshare 는 마커 기반 증강 현실을 사용합니다. 이 유형의 AR 응용 프로그램은 장면에서 마커 (예: 이와 같이 특정하고 쉽게 인식되는 기하학적 패턴)를 검색합니다. 마커는 표시된 개체의 위치와 방향에 대한 정보를 제공하므로 소프트웨어가 추가 3D 풍경을 이미지에 사실적으로 투영할 수 있습니다. 이 프로세스의 기본 단계는 다음과 같습니다.

  • 카메라 액세스: 기본 데스크톱 응용 프로그램을 처리할 때 운영 체제는 대부분의 장치 하드웨어에 대한 I/O 액세스를 제공합니다. 우리가 웹 애플리케이션을 다룰 때와는 다릅니다. 브라우저는 인터넷에서 다운로드한 JavaScript 코드를 위한 일종의 "샌드박스"로 제작되었으며 원래 웹사이트가 대부분의 장치 하드웨어와 상호 작용할 수 있도록 하기 위한 것이 아닙니다. WebRTC는 HTML5의 미디어 캡처 기능을 사용하여 이 장벽을 허물고 브라우저가 무엇보다도 장치 카메라와 스트림에 액세스할 수 있도록 합니다.
  • 비디오 스트림 분석: 비디오 스트림이 있습니다. 이제 무엇을 할까요? 마커를 감지하기 위해 각 프레임을 분석하고 재구성된 3D 세계에서 마커의 위치를 ​​계산해야 합니다. 이 복잡한 작업은 NyARToolkit의 비즈니스입니다.
  • 비디오 보강: 마지막으로 합성 3D 개체가 추가된 원본 비디오를 표시하려고 합니다. WebGL을 사용하여 웹 페이지에 최종적으로 증강된 장면을 그립니다.

GWT로 HTML5의 API 활용하기

WebGL 및 WebRTC와 같은 JavaScript API를 사용하면 브라우저와 사용자 간의 예기치 않은 비정상적인 상호 작용이 가능합니다.

예를 들어, WebGL은 하드웨어 가속 그래픽을 허용하고, 유형 배열 사양의 도움으로 JavaScript 엔진이 거의 기본 성능으로 숫자 처리를 실행할 수 있도록 합니다. 마찬가지로 WebRTC를 사용하면 브라우저가 컴퓨터 하드웨어에서 직접 비디오(및 기타 데이터) 스트림에 액세스할 수 있습니다.

WebGL과 WebRTC는 모두 웹 브라우저에 내장되어야 하는 JavaScript 라이브러리입니다. 대부분의 최신 HTML5 브라우저는 두 API에 대해 적어도 부분적으로 지원합니다(여기와 여기에서 볼 수 있듯이). 그러나 Java로 작성된 GWT에서 이러한 도구를 어떻게 활용할 수 있습니까? 이전 게시물에서 논의한 바와 같이 GWT의 상호 운용성 계층인 JsInterop(GWT 2.8에서 공식적으로 릴리스됨)은 이것을 케이크 조각으로 만듭니다.

GWT 2.8에서 JsInterop을 사용하는 것은 컴파일러에 인수로 -generateJsInteropExports 를 추가하는 것만큼 쉽습니다. 사용 가능한 주석은 gwt-user.jar 에 번들로 제공되는 jsinterop.annotations 패키지에 정의되어 있습니다.

WebRTC

예를 들어, 최소한의 코딩 작업으로 GWT가 있는 Chrome에서 WebRTC의 getUserMedia 를 사용하면 다음과 같이 간단하게 작성할 수 있습니다.

 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); }

흥미로운 것은 위의 람다 표현식으로 구현되고 @JsFunction 주석을 통해 Java로 정의된 SuccessCallbackErrorCallback 인터페이스의 정의입니다.

 @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가 현재 안정적인 Chrome 릴리스에서 폴리필 없이 작동하는 유일한 API이기 때문에 사용됩니다. 프로덕션 앱에서 adapter.js를 사용하여 모든 브라우저에서 균일하게 새로운 navigator.mediaDevices.getUserMedia() API를 통해 스트림에 액세스할 수 있지만 이는 현재 논의의 범위를 벗어납니다.

웹지엘

GWT에서 WebGL을 사용하는 것은 WebRTC를 사용하는 것과 크게 다르지 않지만 OpenGL 표준의 본질적인 복잡성으로 인해 조금 더 지루합니다.

여기에서 우리의 접근 방식은 이전 섹션에서 따온 접근 방식을 반영합니다. 래핑의 결과는 여기에서 찾을 수 있는 Picshare 에서 사용된 GWT WebGL 구현에서 볼 수 있으며 GWT에서 생성된 결과의 예는 여기에서 찾을 수 있습니다.

WebGL을 활성화하는 것 자체는 실제로 3D 그래픽 기능을 제공하지 않습니다. Gregg Tavares는 다음과 같이 썼습니다.

많은 사람들이 모르는 것은 WebGL이 실제로 3D API가 아니라 2D API라는 것입니다.

3D 산술은 다른 코드로 수행되어야 하며 WebGL용 2D 이미지로 변환되어야 합니다. 3D WebGL 그래픽을 위한 몇 가지 좋은 GWT 라이브러리가 있습니다. 내가 가장 좋아하는 것은 Parallax이지만 Picshare 의 첫 번째 버전에서는 단순한 3D 메시를 렌더링하기 위한 작은 라이브러리를 작성하는 보다 "직접적인" 경로를 따랐습니다. 라이브러리를 사용하면 투시 카메라를 정의하고 개체 장면을 관리할 수 있습니다. 여기에서 확인하세요.

GWT를 사용하여 타사 Java 라이브러리 컴파일

NyARToolkit은 증강 현실 애플리케이션을 구축하기 위한 소프트웨어 라이브러리인 ARToolKit의 순수 Java 포트입니다. 포트는 Nyatla의 일본 개발자가 작성했습니다. 원래 ARToolKit과 Nyatla 버전은 원래 포트와 다소 차이가 있지만 NyARToolkit은 여전히 ​​적극적으로 유지 관리되고 개선됩니다.

마커 기반 AR은 전문 분야이며 다음에서 분명히 알 수 있듯이 컴퓨터 비전, 디지털 이미지 처리 및 수학 능력이 필요합니다.

ARToolKit을 사용한 마커 기반 증강 현실 이미지 분석.

ARToolKit 문서에서 재현.

ARToolKit을 사용한 마커 기반 증강 현실 파이프라인.

ARToolKit 문서에서 재현.

툴킷에서 사용하는 모든 알고리즘은 문서화되고 잘 이해되지만 처음부터 다시 작성하는 것은 길고 오류가 발생하기 쉬운 프로세스이므로 ARToolKit과 같은 기존의 입증된 툴킷을 사용하는 것이 좋습니다. 불행히도 웹을 대상으로 할 때 사용할 수 있는 것이 없습니다. 가장 강력한 고급 툴킷에는 HTML 문서와 데이터를 조작하는 데 주로 사용되는 언어인 JavaScript가 구현되어 있지 않습니다. 여기에서 GWT의 귀중한 강점이 입증되어 NyARToolkit을 JavaScript로 간단히 변환하고 번거로움 없이 웹 애플리케이션에서 사용할 수 있습니다.

GWT로 컴파일

GWT 프로젝트는 본질적으로 Java 프로젝트이므로 NyARToolkit을 사용하는 것은 소스 경로에 있는 소스 파일을 가져오기만 하면 됩니다. 그러나 GWT 코드를 JavaScript로 변환하는 작업은 소스 코드 수준에서 수행되므로 컴파일된 클래스가 있는 JAR뿐만 아니라 NyARToolkit의 소스가 필요합니다.

Picshare 에서 사용하는 라이브러리는 여기에서 찾을 수 있습니다. 여기에 보관된 NyARToolkit 빌드의 lib/srclib/src.markersystem 내부에 있는 패키지에만 의존합니다. 이 패키지를 복사하여 GWT 프로젝트로 가져와야 합니다.

이러한 타사 패키지를 자체 구현과 별도로 유지해야 하지만 NyARToolkit의 "GWT-화"를 진행하려면 GWT 컴파일러에게 소스를 찾을 위치를 알려주는 XML 구성 파일을 제공해야 합니다. NyARToolkit.gwt.xml 패키지에서 jp.nyatla.nyartoolkit 파일을 추가합니다.

 <module> <source path="core" /> <source path="detector" /> <source path="nyidmarker" /> <source path="processor" /> <source path="psarplaycard" /> <source path="markersystem" /> </module>

이제 기본 패키지인 com.jooink.gwt.nyartoolkit 에서 기본 구성 파일 GWT_NyARToolKit.gwt.xml 을 만들고 XML 파일에서 상속하여 클래스 경로에 Nyatla의 소스를 포함하도록 컴파일러에 지시합니다.

 <inherits name='jp.nyatla.nyartoolkit.NyARToolkit'/>

꽤 쉽습니다. 대부분의 경우 이것으로 충분하지만 불행히도 아직 완료하지 못했습니다. 이 단계에서 Super Dev Mode를 통해 컴파일하거나 실행하려고 하면 매우 놀랍게도 다음과 같은 오류가 발생합니다.

 No source code is available for type java.io.InputStream; did you forget to inherit a required module?

그 이유는 NyARToolkit(즉, Java 프로젝트용 Java 라이브러리)이 GWT의 Emulated JRE에서 지원하지 않는 JRE 클래스를 사용하기 때문입니다. 우리는 이전 게시물에서 이에 대해 간략하게 논의했습니다.

이 경우 문제는 InputStream 및 관련 IO 클래스에 있습니다. 상황이 발생하면 이러한 클래스의 대부분을 사용할 필요도 없지만 컴파일러에 일부 구현을 제공해야 합니다. 글쎄, 우리는 NyARToolkit 소스에서 이러한 참조를 수동으로 제거하는 데 엄청난 시간을 투자할 수 있지만 그것은 미친 짓입니다. GWT는 더 나은 솔루션을 제공합니다. <super-source> XML 태그를 통해 지원되지 않는 클래스의 자체 구현을 제공합니다.

<super-source>

공식 문서에 설명된 대로:

<super-source> 태그는 컴파일러가 소스 경로를 다시 루팅하도록 지시합니다. 이것은 GWT 프로젝트에 기존 Java API를 재사용하고 싶지만 원본 소스를 사용할 수 없거나 번역할 수 없는 경우에 유용합니다. 이에 대한 일반적인 이유는 GWT에 의해 구현되지 않은 JRE의 일부를 에뮬레이트하기 위함입니다.

그래서 <super-source> 가 바로 우리에게 필요한 것입니다.

GWT 프로젝트에 jre 디렉토리를 생성할 수 있습니다. 여기서 문제를 일으키는 클래스에 대한 구현을 저장할 수 있습니다.

 java.io.FileInputStream java.io.InputStream java.io.InputStreamReader java.io.StreamTokenizer java.lang.reflect.Array java.nio.ByteBuffer java.nio.ByteOrder

java.lang.reflect.Array 를 제외한 이들 모두는 실제로 사용되지 않으므로 멍청한 구현만 필요합니다. 예를 들어 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 <T> Object newInstance(Class<T> 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 모듈 파일에 <super-source path="jre"/> 를 배치하면 프로젝트에서 NyARToolkit을 안전하게 컴파일하고 사용할 수 있습니다!

GWT와 함께 모든 것을 붙이기

이제 우리는 다음과 같은 위치에 있습니다.

  • WebRTC는 웹캠에서 스트림을 가져와 <video> 태그에 표시할 수 있는 기술입니다.
  • HTML <canvas> 에서 하드웨어 가속 그래픽을 조작할 수 있는 기술인 WebGL .
  • NyARToolkit은 이미지(픽셀 배열로)를 가져오고 마커를 검색할 수 있고 발견되는 경우 3D 공간에서 마커의 위치를 ​​완전히 정의하는 변환 행렬을 제공할 수 있는 Java 라이브러리입니다.

이제 과제는 이러한 모든 기술을 함께 통합하는 것입니다.

카메라에 3D 공간을 투영합니다.

이 작업을 수행하는 방법에 대해 자세히 설명하지 않겠지만 기본 아이디어는 비디오 이미지를 장면의 배경으로 사용하고(위 이미지에서 "먼" 평면에 적용된 텍스처) 3D 데이터 구조를 구축하는 것입니다. NyARToolkit의 결과를 사용하여 이 이미지를 우주에 투영할 수 있습니다.

이 구성은 마커 인식을 위해 NyARToolkit의 라이브러리와 상호 작용하고 카메라 장면 위에 3D 모델을 그리는 올바른 구조를 제공합니다.

카메라 스트림을 사용 가능하게 만드는 것은 약간 까다롭습니다. 비디오 데이터는 <video> 요소에만 그릴 수 있습니다. HTML5 <video> 요소는 불투명하고 이미지 데이터를 직접 추출할 수 없으므로 비디오를 중간 <canvas> 에 복사하고, 이미지 데이터를 추출하고, 픽셀 배열로 변환하고, 마지막으로 NyARToolkit의 Sensor.update() 메서드로 푸시합니다. 그런 다음 NyARToolkit은 이미지에서 마커를 식별하고 3D 공간에서 해당 위치에 해당하는 변환 행렬을 반환하는 작업을 수행할 수 있습니다.

이러한 요소를 사용하면 라이브 비디오 스트림에서 3D로 마커 바로 위에 합성 개체를 배치할 수 있습니다! GWT의 고성능 덕분에 우리는 많은 계산 리소스를 보유하고 있으므로 WebGL 장면의 배경으로 사용하기 전에 캔버스에 세피아 또는 흐림 효과와 같은 일부 비디오 효과를 적용할 수도 있습니다.

다음의 간략한 코드는 프로세스의 핵심을 설명합니다.

 // given a <canvas> drawing context with appropriate width and height // and a <video> 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 ... } ...

이 기술을 사용하면 다음과 같은 결과를 생성할 수 있습니다.

Picshare 브라우저 내 증강 현실 응용 프로그램의 결과.

여러 마커가 있는 Picshare 브라우저 내 증강 현실 응용 프로그램의 결과입니다.

이것은 Picshare 를 만드는 데 사용한 프로세스입니다. 여기에서 마커를 인쇄하거나 모바일에 표시하고 브라우저에서 마커 기반 AR을 사용하도록 초대합니다. 즐기다!

최종 비고

Picshare 는 Jooink의 장기적인 애완동물 프로젝트입니다. 첫 번째 구현은 몇 년 전으로 거슬러 올라갑니다. 그 당시에도 인상적일 정도로 빨랐습니다. 이 링크에서 2012년에 컴파일되고 한 번도 건드리지 않은 이전 실험 중 하나를 볼 수 있습니다. 샘플에는 단 하나의 <video> 가 있습니다. 다른 두 개의 창은 처리 결과를 표시하는 <canvas> 요소입니다.

GWT는 2012년에도 충분히 강력했습니다. GWT 2.8이 출시되면서 JsInterop과의 상호 운용성 레이어가 훨씬 향상되어 성능이 더욱 향상되었습니다. 또한 많은 사람들을 축하하기 위해 훨씬 더 나은 개발 및 디버깅 환경인 Super Dev Mode도 얻었습니다. 아, 그리고 자바 8을 지원합니다.

우리는 GWT 3.0을 기대합니다!