1. Zanim zaczniesz
To ćwiczenie w Codelabs pokazuje przykład tworzenia aplikacji internetowej AR. Wykorzystuje JavaScript do renderowania modeli 3D, które sprawiają wrażenie, że istnieją w prawdziwym świecie.
Używasz interfejsu WebXR Device API, który łączy funkcje AR i VR (VR). Skupiasz się na rozszerzeniach AR w interfejsie WebXR Device API, aby utworzyć prostą aplikację AR działającą w internecie.
Co to jest AR?
AR to termin używany zwykle do opisania mieszania grafiki wygenerowanej komputerowo ze światem rzeczywistym. W przypadku AR na telefonie oznacza to przekonujące umieszczenie grafiki komputerowej na obrazie z kamery. Aby ten efekt był realistyczny, gdy telefon porusza się po świecie, urządzenie z obsługą AR musi zrozumieć świat, przez który się porusza, i określić jego położenie (pozycję i orientację) w przestrzeni 3D. Może to obejmować wykrywanie powierzchni i szacowanie oświetlenia otoczenia.
AR jest powszechnie stosowana w aplikacjach po opublikowaniu ARCore od Google i ARKit firmy Apple, niezależnie od tego, czy chodzi o filtry do selfie czy gry oparte na AR.
Co utworzysz
W ramach tych ćwiczeń w programie utworzysz aplikację internetową, która umieszcza model w świecie rzeczywistym przy użyciu rzeczywistości rozszerzonej. Twoja aplikacja będzie:
- Użycie czujników urządzenia docelowego do określenia i śledzenia jego pozycji oraz orientacji na świecie
- Renderowanie modelu 3D utworzonego na obrazie na żywo z kamery
- Przeprowadzaj testy trafienia, aby umieszczać obiekty na odkrytych powierzchniach w świecie rzeczywistym
Czego się nauczysz
- Korzystanie z interfejsu WebXR Device API
- Jak skonfigurować podstawową scenę AR
- Jak znaleźć powierzchnię za pomocą testów działań AR
- Jak wczytać i wyrenderować model 3D zsynchronizowany z obrazem z kamery w świecie rzeczywistym
- Jak renderować cienie na podstawie modelu 3D
To ćwiczenia w programie skupiają się na interfejsach API AR. Nieistotne koncepcje i bloki kodu zostały zamaskowane i są widoczne w odpowiednim kodzie repozytorium.
Czego potrzebujesz
- Stacja robocza do kodowania i hostowania statycznych treści z internetu
- Urządzenie z Androidem z obsługą ARCore i Androidem 8.0 Oreo
- Google Chrome
- zainstalowane Usługi Google Play dla AR (Chrome automatycznie prosi o zainstalowanie tej usługi na zgodnych urządzeniach);
- Wybrany serwer WWW
- Kabel USB do podłączenia urządzenia AR do stacji roboczej
- Przykładowy kod
- Edytor tekstu
- Podstawowa znajomość języków HTML, CSS i JavaScript oraz narzędzi dla programistów Google Chrome
Na urządzeniu AR kliknij Wypróbuj, aby wypróbować pierwszy krok tego ćwiczenia z programowania. Jeśli wyświetli się strona z komunikatem „Twoja przeglądarka nie obsługuje funkcji AR”, sprawdź, czy na Twoim urządzeniu z Androidem są zainstalowane Usługi Google Play dla AR.
2. Konfigurowanie środowiska programistycznego
Pobieranie kodu
- Kliknij ten link, aby pobrać na swoją stację roboczą cały kod tego ćwiczenia z programowania:
- Rozpakuj pobrany plik ZIP. Spowoduje to rozpakowanie folderu głównego (
ar-with-webxr-master
), który zawiera katalogi obejmujące kilka etapów tego ćwiczenia w Codelabs oraz wszystkie potrzebne zasoby.
Foldery step-03
i step-04
zawierają pożądany stan końcowy 3 i 4 kroku tego ćwiczenia w programie, a także wynik final
. Są to informacje w celach informacyjnych.
Wszystkie zadania związane z kodowaniem wykonujesz w katalogu work
.
Zainstaluj serwer WWW
- Możesz używać własnego serwera WWW. Jeśli nie masz jeszcze skonfigurowanego serwera WWW, w tej sekcji znajdziesz szczegółowe informacje na ten temat.
Jeśli nie masz jeszcze zainstalowanej tej aplikacji na swojej stacji roboczej, możesz ją zainstalować z Chrome Web Store.
- Po zainstalowaniu aplikacji Serwer WWW dla Chrome przejdź do
chrome://apps
i kliknij ikonę Serwer WWW:
Zostanie wyświetlone okno dialogowe, które umożliwia skonfigurowanie lokalnego serwera WWW:
- Kliknij Wybierz folder i wskaż folder
ar-with-webxr-master
. Dzięki temu możesz udostępniać wykonywaną pracę pod adresem URL wyróżnionym w oknie serwera WWW (w sekcji Adresy URL serwera WWW). - W sekcji Opcje (wymaga ponownego uruchomienia) zaznacz pole wyboru Automatycznie pokazuj index.html.
- Przełącz Serwer WWW na Zatrzymaj, a następnie ponownie na Uruchomiono.
- Sprawdź, czy wyświetlany jest co najmniej jeden URL serwera WWW: http://127.0.0.1:8887 – domyślny adres URL lokalnego hosta.
Skonfiguruj przekierowanie portów
Skonfiguruj urządzenie AR tak, aby miało dostęp do tego samego portu na stacji roboczej podczas odwiedzania na nim lokalnego hosta:8887.
- Na stacji roboczej programisty otwórz chrome://inspect i kliknij Przekierowanie portów...:
- W oknie Ustawienia przekierowania portów możesz przekierować port 8887 na adres localhost:8887.
- Zaznacz pole wyboru Włącz przekierowanie portów:
Sprawdzanie konfiguracji
Sprawdź połączenie:
- Podłącz urządzenie AR do stacji roboczej kablem USB.
- W Chrome na urządzeniu AR wpisz http://localhost:8887 na pasku adresu. Urządzenie AR powinno przekierować to żądanie do serwera WWW stacji roboczej programistycznej. Powinien wyświetlić się katalog z plikami.
- Na urządzeniu AR kliknij
step-03
, aby wczytać plikstep-03/index.html
w przeglądarce.
Powinna wyświetlić się strona zawierająca przycisk Włącz rzeczywistość rozszerzoną. | Jeśli jednak zobaczysz stronę błędu Nieobsługiwana przeglądarka, Twoje urządzenie prawdopodobnie nie jest zgodne. |
Połączenie z serwerem WWW powinno teraz działać z Twoim urządzeniem AR.
- Kliknij Włącz rzeczywistość rozszerzoną. Może pojawić się prośba o zainstalowanie ARCore.
Przy pierwszym uruchomieniu aplikacji AR zobaczysz pytanie o uprawnienia do korzystania z aparatu.
→
Gdy wszystko będzie gotowe, na obraz z kamery powinna pojawić się scena z sześcianami. Rozpoznawanie scenerii poprawia się w miarę jak większy fragment świata jest analizowany przez kamerę, więc poruszanie się po okolicy może pomóc w stabilizacji.
3. Konfigurowanie WebXR
Z tego kroku dowiesz się, jak skonfigurować sesję WebXR i podstawową scenę AR. Strona HTML zawiera style CSS i JavaScript, które umożliwiają obsługę podstawowych funkcji AR. Przyspiesza to proces konfiguracji, dzięki czemu ćwiczenia z programowania mogą skupić się na funkcjach AR.
Strona HTML
Za pomocą istniejących technologii internetowych przekształcasz środowisko AR w tradycyjną stronę internetową. W tym przypadku używasz pełnoekranowego obszaru roboczego renderowania, więc plik HTML nie musi być zbyt złożony.
Funkcje AR wymagają gestu użytkownika, dlatego do wyświetlania przycisku Uruchom AR i komunikatu w nieobsługiwanej przeglądarce są potrzebne komponenty Material Design.
Plik index.html
, który jest już w katalogu work
, powinien wyglądać mniej więcej tak. Jest to podzbiór faktycznej treści. Nie kopiuj tego kodu do pliku.
<!-- Don't copy this code into your file! -->
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Building an augmented reality application with the WebXR Device API</title>
<link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<!-- three.js -->
<script src="https://unpkg.com/three@0.123.0/build/three.js"></script>
<script src="https://unpkg.com/three@0.123.0/examples/js/loaders/GLTFLoader.js"></script>
<script src="../shared/utils.js"></script>
<script src="app.js"></script>
</head>
<body>
<!-- Information about AR removed for brevity. -->
<!-- Starting an immersive WebXR session requires user interaction. Start the WebXR experience with a simple button. -->
<a onclick="activateXR()" class="mdc-button mdc-button--raised mdc-button--accent">
Start augmented reality
</a>
</body>
</html>
Otwórz kod JavaScript klucza
Początek Twojej aplikacji to app.js
. Ten plik zawiera schemat, który pomoże Ci skonfigurować środowisko AR.
Katalog służbowy zawiera już kod aplikacji (app.js
).
Sprawdź obsługę WebXR i AR
Zanim użytkownik będzie mógł używać AR, sprawdź, czy istnieje usługa navigator.xr
i czy są niezbędne funkcje XR. Obiekt navigator.xr
jest punktem wejścia dla interfejsu WebXR Device API, dlatego powinien istnieć, jeśli urządzenie jest zgodne. Sprawdź też, czy obsługiwany jest tryb sesji "immersive-ar"
.
Jeśli wszystko jest w porządku, kliknięcie przycisku Włącz rzeczywistość rozszerzoną spowoduje próbę utworzenia sesji XR. W przeciwnym razie funkcja onNoXRDevice()
jest wywoływana (w shared/utils.js
), co powoduje wyświetlenie komunikatu o braku obsługi AR.
Ten kod występuje już w usłudze app.js
, więc nie trzeba wprowadzać żadnych zmian.
(async function() {
if (navigator.xr && await navigator.xr.isSessionSupported("immersive-ar")) {
document.getElementById("enter-ar").addEventListener("click", activateXR)
} else {
onNoXRDevice();
}
})();
Poproś o: XRSession
Gdy klikniesz Włącz rzeczywistość rozszerzoną, kod wywoła activateXR()
. Spowoduje to uruchomienie AR.
- Znajdź funkcję
activateXR()
wapp.js
. Część kodu została pominięta:
activateXR = async () => {
// Initialize a WebXR session using "immersive-ar".
this.xrSession = /* TODO */;
// Omitted for brevity
}
Punkt wejścia do WebXR prowadzi przez XRSystem.requestSession()
. Aby umożliwić wyświetlanie renderowanych treści w rzeczywistym środowisku, użyj trybu immersive-ar
.
- Zainicjuj
this.xrSession
przy użyciu trybu"immersive-ar"
:
activateXR = async () => {
// Initialize a WebXR session using "immersive-ar".
this.xrSession = await navigator.xr.requestSession("immersive-ar");
// ...
}
Inicjowanie XRReferenceSpace
XRReferenceSpace
opisuje układ współrzędnych obiektów w świecie wirtualnym. Tryb 'local'
najlepiej sprawdza się w przypadku AR, w którym przestrzeń referencyjna ma początek w pobliżu widza i jest stabilne podczas śledzenia.
Zainicjuj this.localReferenceSpace
w onSessionStarted()
przy użyciu tego kodu:
this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");
Definiowanie pętli animacji
- Użyj metody
requestAnimationFrame
interfejsuXRSession
, aby rozpocząć pętlę renderowania w podobny sposób jak w przypadkuwindow.requestAnimationFrame
.
W każdej klatce funkcja onXRFrame
jest wywoływana z sygnaturą czasową i XRFrame.
- Dokończ implementację interfejsu
onXRFrame
. Po narysowaniu klatki umieść w kolejce następne żądanie, dodając:
// Queue up the next draw request.
this.xrSession.requestAnimationFrame(this.onXRFrame);
- Dodaj kod, aby skonfigurować środowisko graficzne. Dodaj na dole
onXRFrame
:
// Bind the graphics framebuffer to the baseLayer's framebuffer.
const framebuffer = this.xrSession.renderState.baseLayer.framebuffer;
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
this.renderer.setFramebuffer(framebuffer);
- Aby określić pozycję widza, użyj funkcji
XRFrame.getViewerPose()
.XRViewerPose
zawiera informacje o położeniu i orientacji urządzenia w przestrzeni. Zawiera też tablicęXRView
, która opisuje każdy punkt widzenia, z którego scena ma zostać wyrenderowana, aby była prawidłowo wyświetlana na bieżącym urządzeniu. Stereoskopowa rzeczywistość wirtualna zapewnia 2 widoki (po jednym na każde oko), a urządzenia AR – tylko jeden.
Informacje ze zbiorupose.views
są najczęściej używane do konfigurowania matrycy obrazu i matrycy obrazu w kamerze wirtualnej. Określa sposób rozmieszczenia sceny w 3D. Po skonfigurowaniu kamery można wyrenderować scenę. - Dodaj na dole
onXRFrame
:
// Retrieve the pose of the device.
// XRFrame.getViewerPose can return null while the session attempts to establish tracking.
const pose = frame.getViewerPose(this.localReferenceSpace);
if (pose) {
// In mobile AR, we only have one view.
const view = pose.views[0];
const viewport = this.xrSession.renderState.baseLayer.getViewport(view);
this.renderer.setSize(viewport.width, viewport.height);
// Use the view's transform matrix and projection matrix to configure the THREE.camera.
this.camera.matrix.fromArray(view.transform.matrix);
this.camera.projectionMatrix.fromArray(view.projectionMatrix);
this.camera.updateMatrixWorld(true);
// Render the scene with THREE.WebGLRenderer.
this.renderer.render(this.scene, this.camera);
}
Przetestuj
Uruchom aplikację. na urządzeniu, którego używasz do programowania, otwórz stronę work/index.html
. Obraz z kamery powinien zawierać unoszące się w przestrzeni sześciany, których perspektywa zmienia się, gdy poruszasz urządzeniem. Śledzenie zmienia się wraz z większą liczbą ruchu, więc sprawdź, co sprawdza się w przypadku Ciebie i Twojego urządzenia.
Jeśli masz problemy z uruchomieniem aplikacji, zapoznaj się z sekcjami Wprowadzenie i Skonfiguruj środowisko programistyczne.
4. Dodaj siatkę kierowania
Gdy masz już skonfigurowaną podstawową scenę AR, możesz rozpocząć wchodzenie w interakcję ze światem rzeczywistym, korzystając z testu trafień. W tej sekcji zaprogramujesz test trafienia i wykorzystasz go, aby znaleźć pewną powierzchnię w prawdziwym świecie.
Informacje o teście działań
Test trafień to zwykle sposób rzutu prostego z punktu w przestrzeni kosmicznej w określonym kierunku i ustalenia, czy przecina ona z jakimikolwiek obiektami interesującymi. W tym przykładzie wycelujesz urządzenie w miejsce w świecie rzeczywistym. Wyobraź sobie, że promień z kamery w Twoim urządzeniu trafia do świata fizycznego przed nim.
Interfejs WebXR Device API informuje, czy ten promień krzyżuje się z innymi obiektami w świecie rzeczywistym, co jest określane na podstawie podstawowych możliwości AR i znajomości świata.
Poproś o XRSession
z dodatkowymi funkcjami
Aby można było przeprowadzić testy trafień, przy żądaniu XRSession
wymagane są dodatkowe funkcje.
- W aplikacji
app.js
znajdź:navigator.xr.requestSession
. - Dodaj elementy
"hit-test"
i"dom-overlay"
jakorequiredFeature
w ten sposób:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ["hit-test", "dom-overlay"]
});
- Skonfiguruj nakładkę DOM. Nałóż element
document.body
na widok kamery AR w ten sposób:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ["hit-test", "dom-overlay"],
domOverlay: { root: document.body }
});
Dodaj prompt ruchu
ARCore działa najlepiej, gdy dysponujesz dostatecznymi informacjami o środowisku. Jest to możliwe dzięki procesowi nazywanemu równoczesną lokalizacją i mapowaniem (SLAM), w którym do obliczania zmian cech lokalizacji i środowiska używane są różnie różniące się wizualnie punkty cech.
Użyj funkcji "dom-overlay"
z poprzedniego kroku, aby wyświetlić powiadomienie o ruchu na górze strumienia kamery.
Dodaj: <div>
do: index.html
o identyfikatorze stabilization
. <div>
wyświetla użytkownikom animację przedstawiającą stan stabilizacji i zachęca ich do poruszania się po urządzeniu w celu ulepszenia procesu SLAM. Wyświetlana, gdy użytkownik jest w trybie AR, i ukryta, gdy reflektor znajdzie powierzchnię, którą sterują <body>
klasy.
<div id="stabilization"></div>
</body>
</html>
Dodaj siatkę
Użyj celownika, aby wskazać lokalizację, na którą wskazuje urządzenie.
- W
app.js
zastąp wywołanieDemoUtils.createCubeScene()
w elemenciesetupThreeJs()
pustym elementemThree.Scene()
.
setupThreeJs() {
// ...
// this.scene = DemoUtils.createCubeScene();
this.scene = DemoUtils.createLitScene();
}
- Wypełnij nową scenę obiektem reprezentującym punkt kolizji. Podana klasa
Reticle
obsługuje wczytywanie modelu siatki wshared/utils.js
. - Dodaj element
Reticle
do sceny w filmiesetupThreeJs()
:
setupThreeJs() {
// ...
// this.scene = DemoUtils.createCubeScene();
this.scene = DemoUtils.createLitScene();
this.reticle = new Reticle();
this.scene.add(this.reticle);
}
Aby przeprowadzić test działań, używasz nowego adresu typu XRReferenceSpace
. Ta przestrzeń odniesienia wskazuje nowy układ współrzędnych z perspektywy widza, by utworzyć promień wyrównany z kierunkiem oglądania. Ten układ współrzędnych jest używany w zadaniu XRSession.requestHitTestSource()
, który może obliczać testy trafień.
- Dodaj do
onSessionStarted()
wapp.js
te elementy:
async onSessionStarted() {
// ...
// Setup an XRReferenceSpace using the "local" coordinate system.
this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");
// Add these lines:
// Create another XRReferenceSpace that has the viewer as the origin.
this.viewerSpace = await this.xrSession.requestReferenceSpace("viewer");
// Perform hit testing using the viewer as origin.
this.hitTestSource = await this.xrSession.requestHitTestSource({ space: this.viewerSpace });
// ...
}
- Używając metody
hitTestSource
, przetestuj działanie każdej klatki:- Jeśli test trafień nie przyniesie żadnych wyników, oznacza to, że zespół ARCore nie miał wystarczająco dużo czasu, aby poznać środowisko. W takim przypadku poproś użytkownika o przeniesienie urządzenia za pomocą stabilizacji
<div>
. - Jeśli pojawią się wyniki, przenieś siatkę w wybrane miejsce.
- Jeśli test trafień nie przyniesie żadnych wyników, oznacza to, że zespół ARCore nie miał wystarczająco dużo czasu, aby poznać środowisko. W takim przypadku poproś użytkownika o przeniesienie urządzenia za pomocą stabilizacji
- Zmodyfikuj
onXRFrame
, aby przesunąć siatkę:
onXRFrame = (time, frame) => {
// ... some code omitted ...
this.camera.updateMatrixWorld(true);
// Add the following:
const hitTestResults = frame.getHitTestResults(this.hitTestSource);
if (!this.stabilized && hitTestResults.length > 0) {
this.stabilized = true;
document.body.classList.add("stabilized");
}
if (hitTestResults.length > 0) {
const hitPose = hitTestResults[0].getPose(this.localReferenceSpace);
// update the reticle position
this.reticle.visible = true;
this.reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
this.reticle.updateMatrixWorld(true);
}
// More code omitted.
}
Dodaj zachowanie po dotknięciu ekranu
XRSession
może wysyłać zdarzenia na podstawie interakcji użytkownika za pomocą zdarzenia select
, które reprezentuje działanie główne. W WebXR na urządzeniach mobilnych głównym działaniem jest kliknięcie ekranu.
- Dodaj detektor zdarzeń
select
na dole elementuonSessionStarted
:
this.xrSession.addEventListener("select", this.onSelect);
W tym przykładzie kliknięcie ekranu powoduje umieszczenie słonecznika na siatce.
- Utwórz implementację interfejsu
onSelect
w klasieApp
:
onSelect = () => {
if (window.sunflower) {
const clone = window.sunflower.clone();
clone.position.copy(this.reticle.position);
this.scene.add(clone);
}
}
Testowanie aplikacji
Udało Ci się stworzyć siatkę strzelniczą, którą możesz wycelować w swoje urządzenie, korzystając z testów trafień. Dotykając ekranu, możesz umieścić słonecznik w miejscu wskazanym przez siatkę.
- Podczas uruchamiania aplikacji powinno być widoczne siatkówka śledząca powierzchnię podłogi. Jeśli nie, spróbuj powoli się rozejrzeć telefonem.
- Gdy zobaczysz siatkę, kliknij ją. Na niej powinien znajdować się słonecznik. Konieczne może być trochę ruchu, żeby platforma AR była w stanie lepiej wykrywać powierzchnie w świecie rzeczywistym. Słabe oświetlenie i powierzchnie bez elementów obniżają jakość rozpoznawania sceny i zwiększają ryzyko wykrycia trafienia. Jeśli napotkasz jakieś problemy, sprawdź kod
step-04/app.js
, aby zobaczyć działający przykład.
5. Dodaj cienie
Aby stworzyć realistyczną scenę, należy zastosować odpowiednie oświetlenie i cienie na obiektach cyfrowych, które dodadzą scenie realizmu i zanurzenia się w sytuacji.
Za oświetlenie i cienie odpowiada aplikacja three.js
. Możesz określić, które światła mają rzucać cienie, które materiały powinny opuszczać i renderować te cienie, a które siatki mogą rzucać cienie. Scena w tej aplikacji zawiera światło rzucające cień i płaską powierzchnię, w której cienie są widoczne tylko.
- Włącz cienie w:
three.js
WebGLRenderer
. Po utworzeniu mechanizmu renderowania ustaw w panelushadowMap
te wartości:
setupThreeJs() {
...
this.renderer = new THREE.WebGLRenderer(...);
...
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
...
}
Przykładowa scena utworzona w DemoUtils.createLitScene()
zawiera obiekt o nazwie shadowMesh
– płaską, poziomą powierzchnię, która renderuje tylko cienie. Ta powierzchnia ma początkowo pozycję Y wynoszącą 10 000 jednostek. Po umieszczeniu słonecznika przesuń shadowMesh
na taką samą wysokość, jak powierzchnia świata rzeczywistego, tak aby cień kwiatu pojawił się na powierzchni rzeczywistej gruntu.
- W programie
onSelect
po dodaniu do sceny elementuclone
dodaj kod zmieniający położenie płaszczyzny cienia:
onSelect = () => {
if (window.sunflower) {
const clone = window.sunflower.clone();
clone.position.copy(this.reticle.position);
this.scene.add(clone);
const shadowMesh = this.scene.children.find(c => c.name === "shadowMesh");
shadowMesh.position.y = clone.position.y;
}
}
Przetestuj
Gdy umieścisz słonecznik, powinien być widoczny rzucający cień. Jeśli napotkasz jakieś problemy, sprawdź kod final/app.js
, aby zobaczyć działający przykład.
6. Dodatkowe materiały
Gratulacje! To już koniec tego ćwiczenia z programowania w AR przy użyciu WebXR.