Tworzenie aplikacji do rzeczywistości rozszerzonej (AR) przy użyciu interfejsu WebXR Device API

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:

  1. Użycie czujników urządzenia docelowego do określenia i śledzenia jego pozycji oraz orientacji na świecie
  2. Renderowanie modelu 3D utworzonego na obrazie na żywo z kamery
  3. Przeprowadzaj testy trafienia, aby umieszczać obiekty na odkrytych powierzchniach w świecie rzeczywistym

Czego się nauczysz

  • Korzystanie z interfejsu WebXR Device API
  • Konfigurowanie podstawowej sceny 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

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

  1. Kliknij ten link, aby pobrać na swoją stację roboczą cały kod tego ćwiczenia z programowania:

  1. 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

  1. 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.

  1. Po zainstalowaniu aplikacji Serwer WWW dla Chrome przejdź do chrome://apps i kliknij ikonę serwera WWW:

Ikona serwera WWW

Zostanie wyświetlone okno dialogowe, które umożliwia skonfigurowanie lokalnego serwera WWW:

Konfigurowanie serwera WWW Chrome

  1. 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).
  2. W sekcji Opcje (wymaga ponownego uruchomienia) zaznacz pole wyboru Automatycznie pokazuj index.html.
  3. Przełącz Serwer WWW na Zatrzymaj, a następnie ponownie na Uruchomiono.Ponowne uruchamianie serwera WWW Chrome
  4. 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.

  1. Na stacji roboczej programisty otwórz chrome://inspect i kliknij Przekierowanie portów...: chrome://inspect
  2. W oknie Ustawienia przekierowania portów możesz przekierować port 8887 na adres localhost:8887.
  3. Zaznacz pole wyboru Włącz przekierowanie portów:

Skonfiguruj przekierowanie portów

Sprawdzanie konfiguracji

Sprawdź połączenie:

  1. Podłącz urządzenie AR do stacji roboczej kablem USB.
  2. 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.
  3. Na urządzeniu AR kliknij step-03, aby wczytać plik step-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.

Obsługiwany jest ARCore

Funkcja ARCore nie jest obsługiwana

Połączenie z serwerem WWW powinno teraz działać z Twoim urządzeniem AR.

  1. Kliknij Włącz rzeczywistość rozszerzoną. Może pojawić się prośba o zainstalowanie ARCore.

Zainstaluj prompt ARCore

Przy pierwszym uruchomieniu aplikacji AR zobaczysz pytanie o uprawnienia do korzystania z aparatu.

Chrome prosi o uprawnienia do korzystania z aparatuOkno uprawnień

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.

  1. Znajdź funkcję activateXR() w app.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.

  1. 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

  1. Użyj metody requestAnimationFrame interfejsu XRSession, aby rozpocząć pętlę renderowania w podobny sposób jak w przypadku window.requestAnimationFrame.

W każdej klatce funkcja onXRFrame jest wywoływana z sygnaturą czasową i XRFrame.

  1. 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);
  1. 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);
  1. 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 zbioru pose.views są najczęściej używane do konfigurowania matrycy obrazu i macierzy projekcji kamery wirtualnej. Określa sposób rozmieszczenia sceny w 3D. Po skonfigurowaniu kamery można wyrenderować scenę.
  2. 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 interesującymi obiektami. 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.

Wyjaśnienie testu działania

Poproś o XRSession z dodatkowymi funkcjami

Aby można było przeprowadzić testy trafień, przy żądaniu XRSession wymagane są dodatkowe funkcje.

  1. W aplikacji app.js znajdź: navigator.xr.requestSession.
  2. Dodaj elementy "hit-test" i "dom-overlay" jako requiredFeature w ten sposób:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["hit-test", "dom-overlay"]
});
  1. 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.

  1. W app.js zastąp wywołanie DemoUtils.createCubeScene() w elemencie setupThreeJs() pustym elementem Three.Scene().
setupThreeJs() {
  // ...

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
}
  1. Wypełnij nową scenę obiektem reprezentującym punkt kolizji. Podana klasa Reticle obsługuje wczytywanie modelu siatki w shared/utils.js.
  2. Dodaj element Reticle do sceny w filmie setupThreeJs():
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ń.

  1. Dodaj do onSessionStarted() w app.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 });

  // ...
}
  1. 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.
  2. 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.

  1. Dodaj detektor zdarzeń select na dole elementu onSessionStarted:
this.xrSession.addEventListener("select", this.onSelect);

W tym przykładzie kliknięcie ekranu powoduje umieszczenie słonecznika na siatce.

  1. Utwórz implementację interfejsu onSelect w klasie App:
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ę.

  1. Podczas uruchamiania aplikacji powinno być widoczne siatkówka śledząca powierzchnię podłogi. Jeśli nie, spróbuj powoli się rozejrzeć telefonem.
  2. 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.

  1. Włącz cienie w: three.js WebGLRenderer. Po utworzeniu mechanizmu renderowania ustaw w panelu shadowMap 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.

  1. W programie onSelect po dodaniu do sceny elementu clone 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.

Więcej informacji