1. Zanim zaczniesz
To ćwiczenie w Codelabs zawiera przykład tworzenia aplikacji internetowej AR. Korzysta ona z JavaScriptu do renderowania modeli 3D, które wyglądają tak, jakby istniały w rzeczywistym świecie.
Używasz interfejsu WebXR Device API, który łączy w sobie funkcje AR i rzeczywistości wirtualnej (VR). Skupiasz się na rozszerzeniach rzeczywistości rozszerzonej do interfejsu WebXR Device API, aby utworzyć prostą aplikację AR, która działa w interaktywnej sieci.
Co to jest AR?
Termin ten jest zwykle używany do opisywania mieszania grafiki generowanej komputerowo z rzeczywistym światem. W przypadku AR na telefonie oznacza to przekonujące umieszczenie grafiki komputerowej na obrazie z kamery. Aby efekt był realistyczny, gdy telefon porusza się po świecie, urządzenie z AR musi rozumieć świat, przez który się porusza, oraz określać swoją pozycję (położenie i orientację) w przestrzeni trójwymiarowej. Może to obejmować wykrywanie powierzchni i szacowanie oświetlenia otoczenia.
Po wydaniu platformy ARCore Google i platformy ARKit Apple rozpowszechniła się technologia AR, która jest wykorzystywana w aplikacjach, np. do filtrów do selfie czy gier wykorzystujących AR.
Co utworzysz
W tym ćwiczeniu w Codelab utworzysz aplikację internetową, która umieszcza model w rzeczywistym świecie za pomocą rzeczywistości rozszerzonej. Twoja aplikacja będzie:
- Używanie czujników urządzenia docelowego do określania i śledzenia jego położenia i orientacji na mapie
- Renderowanie modelu 3D złożonego z widoku z kamery
- Wykonywanie testów kolizji w celu umieszczania obiektów na wykrytych powierzchniach w rzeczywistym świecie
Czego się nauczysz
- Korzystanie z interfejsu WebXR Device API
- Konfigurowanie podstawowej sceny AR
- Jak znaleźć powierzchnię za pomocą testów trafień AR
- Jak wczytywać i renderować model 3D zsynchronizowany z obrazem z kamery w świecie rzeczywistym
- Jak renderować cienie na podstawie modelu 3D
To ćwiczenia z programowania, które koncentrują się na interfejsach AR API. Nieistotne koncepcje i bloki kodu zostały zamaskowane. Można je po prostu skopiować i wkleić.
Czego potrzebujesz
- Stacja robocza do kodowania i hostowania statycznych treści internetowych
- Urządzenie z Androidem z obsługą ARCore z Androidem 8.0 Oreo
- Google Chrome
- Usługi Google Play dla AR są zainstalowane (Chrome automatycznie wyświetla prośbę o instalację na zgodnych urządzeniach).
- Wybrany serwer WWW
- Kabel USB do połączenia urządzenia AR z stanowiskiem roboczym
- Przykładowy kod
- edytor tekstu,
- podstawowa znajomość HTML, CSS, JavaScriptu i narzędzi deweloperskich w Google Chrome;
Na urządzeniu z rozszerzoną rzeczywistością kliknij Wypróbuj, aby wykonać pierwszy krok tego ćwiczenia. Jeśli wyświetli się strona z komunikatem „Twoja przeglądarka nie obsługuje funkcji AR”, sprawdź, czy na urządzeniu z Androidem są zainstalowane Usługi Google Play dla AR.
2. Konfigurowanie środowiska programistycznego
Pobieranie kodu
- Aby pobrać cały kod tego ćwiczenia na swoją stację roboczą, kliknij ten link:
- Rozpakuj pobrany plik ZIP. Spowoduje to rozpakowanie folderu głównego (
ar-with-webxr-master
), który zawiera katalogi z kilkoma krokami tego laboratorium kodu oraz wszystkie potrzebne zasoby.
Foldery step-03
i step-04
zawierają pożądany stan końcowy z 3 i 4 kroku tego ćwiczenia, a także wynik final
. Są one dostępne w celu ułatwienia Ci pracy.
Wszystkie czynności związane z programowaniem wykonujesz w katalogu work
.
Instalowanie serwera WWW
- Możesz używać własnego serwera WWW. Jeśli nie masz jeszcze skonfigurowanego serwera WWW, w tej sekcji znajdziesz instrukcje jego konfiguracji w Chrome.
Jeśli aplikacja nie jest jeszcze zainstalowana na komputerze, możesz ją zainstalować ze sklepu Chrome Web Store.
- Po zainstalowaniu aplikacji Serwer WWW dla Chrome otwórz
chrome://apps
i kliknij ikonę serwera WWW:
Następnie zobaczysz to okno, które umożliwia skonfigurowanie lokalnego serwera WWW:
- Kliknij Wybierz folder i wybierz folder
ar-with-webxr-master
. Dzięki temu możesz udostępniać swoją 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 wyświetlaj plik index.html.
- Przełącz Serwer WWW na Zatrzymaj, a następnie z powrotem na Uruchomiony.
- Sprawdź, czy pojawia się co najmniej 1 adres URL serwera WWW: http://127.0.0.1:8887 – domyślny adres URL localhost.
Skonfiguruj przekierowanie portów
Skonfiguruj urządzenie AR, aby otwierało ten sam port na stacji roboczej, gdy otworzysz na niej adres localhost:8887.
- Na stacji roboczej dla programistów otwórz chrome://inspect i kliknij Przekierowanie portu…:
- 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
Testowanie połączenia:
- Podłącz urządzenie AR do stacji roboczej za pomocą kabla USB.
- Na urządzeniu AR w Chrome wpisz w pasku adresu http://localhost:8887. Urządzenie AR powinno przekazać to żądanie do serwera internetowego stacji roboczej programisty. Powinien pojawić się katalog plików.
- Na urządzeniu AR kliknij
step-03
, aby załadować 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, prawdopodobnie Twoje urządzenie nie jest zgodne. |
Połączenie z serwerem WWW powinno teraz działać z Twoim urządzeniem AR.
- Kliknij Rozpocznij rzeczywistość rozszerzoną. Może pojawić się prośba o zainstalowanie ARCore.
Gdy po raz pierwszy uruchomisz aplikację AR, zobaczysz prośbę o przyznanie uprawnień do korzystania z aparatu.
→
Gdy wszystko będzie gotowe, zobaczysz scenę z kostkami nałożoną na obraz z kamery. Rozpoznawanie sceny jest coraz dokładniejsze, ponieważ kamera analizuje coraz większą część świata, więc poruszanie się może pomóc w ustabilizowaniu obrazu.
3. Konfigurowanie WebXR
W tym kroku dowiesz się, jak skonfigurować sesję WebXR i podstawową scenę AR. Strona HTML jest dostarczana ze stylami CSS i JavaScriptem, aby umożliwić podstawowe funkcje AR. Przyspiesza to proces konfiguracji, umożliwiając Codelab skupienie się na funkcjach rozszerzonej rzeczywistości.
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.
Aby uruchomić funkcje AR, użytkownik musi wykonać gest, dlatego dostępne są komponenty Material Design do wyświetlania przycisku Rozpocznij AR i wiadomości o nieobsługiwanym przez przeglądarkę komunikacie.
Plik index.html
, który jest już w katalogu work
, powinien wyglądać mniej więcej tak. To podzbiór rzeczywistej zawartoś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 kluczowy kod JavaScript
Punkt początkowy Twojej aplikacji znajduje się w app.js
. Ten plik zawiera schemat, który pomoże Ci skonfigurować środowisko AR.
Twój katalog roboczy zawiera już kod aplikacji (app.js
).
Sprawdzanie obsługi WebXR i AR
Zanim użytkownik będzie mógł używać AR, sprawdź, czy istnieje usługa navigator.xr
i czy są potrzebne funkcje XR. Obiekt navigator.xr
jest punktem wejścia do interfejsu WebXR Device API, więc 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 wywoływana jest funkcja onNoXRDevice()
(w shared/utils.js
), która wyświetla komunikat 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();
}
})();
Prośba o XRSession
Gdy klikniesz Włącz rzeczywistość rozszerzoną, kod wywoła activateXR()
. Spowoduje to uruchomienie AR.
- Znajdź funkcję
activateXR()
wapp.js
. Niektóry kod został pominięty:
activateXR = async () => {
// Initialize a WebXR session using "immersive-ar".
this.xrSession = /* TODO */;
// Omitted for brevity
}
Punkt wejścia do WebXR to XRSystem.requestSession()
. Użyj trybu immersive-ar
, aby wyświetlić wyrenderowane treści w środowisku rzeczywistym.
- Inicjowanie
this.xrSession
w trybie"immersive-ar"
:
activateXR = async () => {
// Initialize a WebXR session using "immersive-ar".
this.xrSession = await navigator.xr.requestSession("immersive-ar");
// ...
}
Inicjowanie XRReferenceSpace
Element XRReferenceSpace
opisuje układ współrzędnych używany dla 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()
za pomocą tego kodu:
this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");
Definiowanie pętli animacji
- Użyj funkcji
XRSession
requestAnimationFrame
, aby rozpocząć pętlę renderowania, podobnie jak w funkcjiwindow.requestAnimationFrame
.
W każdej klatce funkcja onXRFrame
jest wywoływana z sygnaturą czasową i strukturą XRFrame.
- Dokończ implementację usługi
onXRFrame
. Gdy rysowana jest klatka, umieść w kole 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ć pozę widza, użyj
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 powinna zostać wyrenderowana, aby prawidłowo wyświetlić się na bieżącym urządzeniu. Stereoskopowe VR ma 2 widoki (jeden dla każdego oka), a urządzenia AR tylko jeden.
Informacje wpose.views
są najczęściej używane do konfigurowania macierzy widoku i macierzy projekcji wirtualnej kamery. Określa sposób rozmieszczenia sceny w 3D. Po skonfigurowaniu kamery można renderować 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);
}
Testowanie
Uruchom aplikację. Na urządzeniu deweloperskim otwórz stronę work/index.html
. Powinieneś zobaczyć obraz z kamery z unoszącymi się w powietrzu sześcianami, których perspektywa zmienia się wraz z ruchy urządzenia. Im więcej się poruszasz, tym lepsze wyniki uzyskujesz w śledzeniu. Sprawdź, co działa najlepiej w Twoim przypadku i na Twoim urządzeniu.
Jeśli masz problemy z uruchamianiem aplikacji, zapoznaj się z sekcjami Wprowadzenie i Konfigurowanie środowiska programistycznego.
4. Dodawanie siatki kierowania
Po skonfigurowaniu podstawowej sceny AR możesz rozpocząć interakcję ze światem rzeczywistym za pomocą testu kolizji. W tej sekcji zaprogramujesz test uderzenia i użyjesz go do znalezienia powierzchni w świecie rzeczywistym.
Testowanie dopasowania
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 celujesz urządzeniem w rzeczywiste miejsce. Wyobraź sobie, że promień z kamery w Twoim urządzeniu trafia do świata fizycznego przed nim.
Interfejs WebXR Device API informuje, czy promień przecina jakieś obiekty w świecie rzeczywistym, co zależy od możliwości AR i rozumienia świata.
Poproś o XRSession
z dodatkowymi funkcjami
Aby przeprowadzić testy skuteczności, podczas wysyłania żądania XRSession
należy użyć dodatkowych funkcji.
- W
app.js
odszukajnavigator.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. Umieść element
document.body
na widoku kamery AR w ten sposób:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ["hit-test", "dom-overlay"],
domOverlay: { root: document.body }
});
Dodawanie promptu dotyczącego ruchu
ARCore działa najlepiej, gdy dysponujesz dostatecznymi informacjami o środowisku. Osiąga się to dzięki procesowi zwanemu jednoczesną lokalizację i mapowaniem (SLAM), w którym do obliczenia zmiany lokalizacji i charakterystyki środowiska używa się wizualnie różniących się punktów charakterystycznych.
Użyj "dom-overlay"
z poprzedniego kroku, aby wyświetlić prompt dotyczący ruchu nad strumieniem z 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. Jest on wyświetlany, gdy użytkownik jest w AR, i ukrywany, gdy celownik znajdzie powierzchnię, kontrolowaną przez klasy <body>
.
<div id="stabilization"></div>
</body>
</html>
Dodawanie siatki
Użyj siatki, aby wskazać lokalizację, na którą wskazuje widok urządzenia.
- W
app.js
zastąp wywołanieDemoUtils.createCubeScene()
wsetupThreeJs()
pustym wywołaniemThree.Scene()
.
setupThreeJs() {
// ...
// this.scene = DemoUtils.createCubeScene();
this.scene = DemoUtils.createLitScene();
}
- Wypełnij nową scenę obiektem, który reprezentuje punkt kolizji. Udostępniona klasa
Reticle
obsługuje wczytywanie modelu siatki w klasieshared/utils.js
. - Dodaj
Reticle
do sceny wsetupThreeJs()
:
setupThreeJs() {
// ...
// this.scene = DemoUtils.createCubeScene();
this.scene = DemoUtils.createLitScene();
this.reticle = new Reticle();
this.scene.add(this.reticle);
}
Aby przeprowadzić test trafień, użyj nowego XRReferenceSpace
. To metryczka wskazuje nowy układ współrzędnych z perspektywy widza, aby utworzyć promień zgodny z kierunkiem oglądania. Ten układ współrzędnych jest używany w XRSession.requestHitTestSource()
, który może obliczać testy trafień.
- Dodaj do
onSessionStarted()
w plikuapp.js
te informacje:
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 trafienia nie przynosi żadnych wyników, oznacza to, że ARCore nie miał wystarczająco dużo czasu na poznanie środowiska. W takim przypadku poproś użytkownika, aby przesunął urządzenie, używając stabilizacji
<div>
. - Jeśli pojawią się wyniki, przenieś siatkę w wybrane miejsce.
- Jeśli test trafienia nie przynosi żadnych wyników, oznacza to, że ARCore nie miał wystarczająco dużo czasu na poznanie środowiska. W takim przypadku poproś użytkownika, aby przesunął urządzenie, używając 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łówne działanie to kliknięcie ekranu.
- Dodaj detektor zdarzenia
select
na dole oknaonSessionStarted
:
this.xrSession.addEventListener("select", this.onSelect);
W tym przykładzie po kliknięciu ekranu na siatce pojawia się obraz słońca.
- Utwórz implementację
onSelect
w klasieApp
:
onSelect = () => {
if (window.sunflower) {
const clone = window.sunflower.clone();
clone.position.copy(this.reticle.position);
this.scene.add(clone);
}
}
Testowanie aplikacji
Utworzyłeś siatkę celowniczą, którą możesz celować za pomocą urządzenia, korzystając z testów trafień. Po kliknięciu ekranu powinieneś mieć możliwość umieszczenia słoneczniczka w miejscu wskazanym przez celownik.
- Podczas uruchamiania aplikacji powinieneś/powinnaś zobaczyć siatkę naśladującą powierzchnię podłogi. Jeśli nie, spróbuj powoli się rozejrzeć telefonem.
- Gdy zobaczysz siatkę, kliknij ją. Na górze powinna znajdować się słonecznia. 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 tego kroku.
5. Dodawanie cieni
Tworzenie realistycznej sceny wymaga uwzględnienia takich elementów jak odpowiednie oświetlenie i cienie na obiektach cyfrowych, które dodają realizmu i stwarzają wrażenie głębi.
Oświetlenie i cienie są obsługiwane przez three.js
. Możesz określić, które światła mają rzucać cienie, które materiały mają odbierać i renderować te cienie oraz które siatki mogą rzucać cienie. Scena w tej aplikacji zawiera światło rzucające cień i płaską powierzchnię, w której tylko cienie są widoczne.
- Włącz cienie w:
three.js
WebGLRenderer
. Po utworzeniu modułu renderowania ustaw w sekcjishadowMap
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
onSelect
, po dodaniuclone
do sceny, dodaj kod, aby zmienić 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
Podczas umieszczania słoneczników należy pamiętać, że powinny rzucać cień. Jeśli napotkasz jakieś problemy, sprawdź kod final/app.js
, aby zobaczyć działający przykład tego kroku.
6. Dodatkowe materiały
Gratulacje! Dotarłeś(-aś) do końca tego ćwiczenia dotyczącego AR z użyciem WebXR.