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

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:

  1. Używanie czujników urządzenia docelowego do określania i śledzenia jego położenia i orientacji na mapie
  2. Renderowanie modelu 3D złożonego z widoku z kamery
  3. 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

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

  1. Aby pobrać cały kod tego ćwiczenia na swoją stację roboczą, kliknij ten link:

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

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

  1. Po zainstalowaniu aplikacji Serwer WWW dla Chrome otwórz chrome://apps i kliknij ikonę serwera WWW:

Ikona serwera WWW

Następnie zobaczysz to okno, które umożliwia skonfigurowanie lokalnego serwera WWW:

Konfigurowanie serwera WWW Chrome

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

  1. Na stacji roboczej dla programistów otwórz chrome://inspect i kliknij Przekierowanie portu…: 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

Testowanie połączenia:

  1. Podłącz urządzenie AR do stacji roboczej za pomocą kabla USB.
  2. 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.
  3. Na urządzeniu AR kliknij step-03, aby załadować 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, prawdopodobnie Twoje urządzenie nie jest zgodne.

Obsługa ARCore

Funkcja ARCore nie jest obsługiwana

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

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

Prośba o zainstalowanie ARCore

Gdy po raz pierwszy uruchomisz aplikację AR, zobaczysz prośbę o przyznanie uprawnień do korzystania z aparatu.

Chrome prosi o uprawnienia do korzystania z aparatuOkno uprawnień

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.

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

  1. 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.localReferenceSpaceonSessionStarted() za pomocą tego kodu:

this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");

Definiowanie pętli animacji

  1. Użyj funkcji XRSession requestAnimationFrame, aby rozpocząć pętlę renderowania, podobnie jak w funkcji window.requestAnimationFrame.

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

  1. 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);
  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ć 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 w pose.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ę.
  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);
}

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 WprowadzenieKonfigurowanie ś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.

Wyjaśnienie dotyczące testu pozycji wskaźnika

Poproś o XRSession z dodatkowymi funkcjami

Aby przeprowadzić testy skuteczności, podczas wysyłania żądania XRSession należy użyć dodatkowych funkcji.

  1. app.js odszukaj 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. 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.

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

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
}
  1. Wypełnij nową scenę obiektem, który reprezentuje punkt kolizji. Udostępniona klasa Reticle obsługuje wczytywanie modelu siatki w klasie shared/utils.js.
  2. Dodaj Reticle do sceny w setupThreeJs():
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ń.

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

  // ...
}
  1. 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.
  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łówne działanie to kliknięcie ekranu.

  1. Dodaj detektor zdarzenia select na dole okna onSessionStarted:
this.xrSession.addEventListener("select", this.onSelect);

W tym przykładzie po kliknięciu ekranu na siatce pojawia się obraz słońca.

  1. Utwórz implementację 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

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.

  1. Podczas uruchamiania aplikacji powinieneś/powinnaś zobaczyć siatkę naśladującą powierzchnię podłogi. Jeśli nie, spróbuj powoli się rozejrzeć telefonem.
  2. 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.

  1. Włącz cienie w: three.js WebGLRenderer. Po utworzeniu modułu renderowania ustaw w sekcji 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. onSelect, po dodaniu clone 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.

Więcej informacji