Rzeczywistość rozszerzona: być może już to wiesz

Jeśli korzystasz już z interfejsu WebXR Device API, jesteś już prawie gotowy.

Joe Medley
Joe Medley

Interfejs WebXR Device API został wprowadzony jesienią ubiegłego roku w Chrome 79. Jak już wspomnieliśmy, prace nad implementacją interfejsu API w Chrome są w toku. Z przyjemnością informujemy, że część prac jest już ukończona. W Chrome 81 pojawiły się 2 nowe funkcje:

Ten artykuł dotyczy rzeczywistości rozszerzonej. Jeśli korzystasz już z interfejsu WebXR Device API, ucieszysz się, że nie udało się wiele nauczyć. Wprowadzanie sesji WebXR działa prawie tak samo. Uruchomienie pętli klatek przebiega w podobny sposób. Różnice polegają na konfiguracjach, które umożliwiają wyświetlanie treści w odpowiedniej formie w rzeczywistości rozszerzonej. Jeśli nie znasz podstawowych pojęć dotyczących WebXR, przeczytaj moje wcześniejsze posty o interfejsie WebXR Device API lub zapoznaj się z poruszanymi w nim tematami. Musisz wiedzieć, jak poprosić o sesję i wejść do niej oraz jak uruchomić pętlę ramek.

Informacje o testowaniu trafień znajdziesz w artykule Pozycjonowanie obiektów wirtualnych w widokach rzeczywistego. Kod w tym artykule jest oparty na przykładowej sesji wciągającej rzeczywistości rozszerzonej (demo source) z interfejsu WebXR Device API grupy roboczej Immersive Web Working Group.

Zanim zaczniesz analizować kod, przynajmniej raz skorzystaj z przykładu sesji z rozszerzoną rzeczywistością. Potrzebujesz nowoczesnego telefonu z Androidem i przeglądarką Chrome 81 lub nowszą.

Do czego się przydaje?

Rzeczywistość rozszerzona będzie cennym dodatkiem do wielu istniejących i nowych stron internetowych, ponieważ umożliwi wdrażanie przypadków użycia AR bez potrzeby opuszczania przeglądarki. Może ona na przykład pomóc użytkownikom w nauce w witrynach edukacyjnych i umożliwić potencjalnym kupującym wizualizację produktów w ich domach.

Przeanalizuj drugi przypadek użycia. Wyobraź sobie symulację umieszczania rzeczywistej wielkości obiektu wirtualnego w rzeczywistej scenie. Po umieszczeniu obraz pozostaje na wybranej powierzchni, ma rozmiary odpowiadające rzeczywistemu obiektowi na tej powierzchni i pozwala użytkownikowi poruszać się wokół niego oraz zbliżać się do niego lub oddalać. Dzięki temu widzowie mogą lepiej poznać obiekt niż w przypadku obrazu dwuwymiarowego.

Zbywam trochę w przód. Aby to zrobić, potrzebujesz funkcji AR i środka wykrywania powierzchni. W tym artykule omawiamy tę pierwszą opcję. W powiązanym wyżej artykule o interfejsie WebXR Hit Test API znajdziesz więcej informacji na ten temat.

Wysyłanie prośby o rozpoczęcie sesji

Wysyłanie prośby o sesję wygląda bardzo podobnie do tej, z którą się spotykasz. Najpierw sprawdź, czy wybrany typ sesji jest dostępny na bieżącym urządzeniu, wykonując wywołanie xr.isSessionSupported(). Zamiast 'immersive-vr', jak poprzednio, poproś o 'immersive-ar'.

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-ar');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter AR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

W tym przypadku również pojawi się przycisk „Wejdź do AR”. Gdy użytkownik kliknie ten przycisk, wywołaj funkcję xr.requestSession(), przekazując jej argument 'immersive-ar'.

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-ar')
    .then((session) => {
      xrSession = session;
      xrSession.isImmersive = true;
      xrButton.textContent = 'Exit AR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

Właściwość typu convenience

Zauważysz pewnie, że w ostatnim przykładzie kodu podświetlono 2 wiersze. Wygląda na to, że obiekt XRSession ma właściwość o nazwie isImmersive. To jest własność ułatwiająca pracę, którą sam utworzyłem. Nie jest ona częścią specyfikacji. Użyję jej później, aby podjąć decyzję, co wyświetlić widzowi. Dlaczego ta usługa nie jest częścią interfejsu API? Ponieważ aplikacja może potrzebować śledzenia tej właściwości w inny sposób, autorzy specyfikacji postanowili zachować interfejs API w czystej formie.

Rozpoczynanie sesji

Przypomnij sobie, jak wyglądała nazwa onSessionStarted() z mojego wcześniejszego artykułu:

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Muszę dodać kilka rzeczy, aby uwzględnić renderowanie rzeczywistości rozszerzonej. Wyłącz tło. Najpierw określę, czy potrzebuję tła. To pierwsze miejsce, w którym użyję własnej usługi dodatkowej.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  if (session.isImmersive) {
    removeBackground();
  }

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });

}

Pokoje referencyjne

W moich wcześniejszych artykułach tylko pobieżnie omawiałem przestrzenie referencyjne. W opisywanej próbce są stosowane dwie z nich, należy więc poprawić to pominięcie.

Przestrzeń odniesienia opisuje związek między światem wirtualnym a środowiskiem fizycznym użytkownika. Odbywa się to przez:

  • Określanie punktu wyjścia dla układu współrzędnych używanego do wyrażania pozycji w świecie wirtualnym.
  • określanie, czy użytkownik może się poruszać w obrębie tego układu współrzędnych.
  • Czy system współrzędnych ma z góry ustalone granice. (przykłady pokazane tutaj nie korzystają z uprzednio ustalonych granic układów współrzędnych).

W przypadku wszystkich przestrzeni odniesienia współrzędna X oznacza lewo i prawo, współrzędna Y – w górę i w dół, a współrzędna Z – do przodu i do tyłu. Wartości dodatnie odpowiadają odpowiednio prawej, górze i tyłowi.

Współrzędne zwracane przez funkcję XRFrame.getViewerPose() zależą od żądanego typu przestrzeni odniesienia. Więcej informacji na ten temat znajdziesz w sekcji dotyczącej pętli ramek. Teraz musimy wybrać typ pliku referencyjnego odpowiedni dla rzeczywistości rozszerzonej. Ponownie używam właściwości skrótu.

let refSpaceType
function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  if (session.isImmersive) {
    removeBackground();
  }

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Jeśli otworzysz przykład sesji z rozszerzoną rzeczywistością, zauważysz, że początkowo scena jest statyczna i nie ma nic wspólnego z rozszerzoną rzeczywistością. Aby poruszać się po scenie, możesz przeciągać palcem po ekranie. Jeśli klikniesz „ROZPOCZNIJ AR”, tło zniknie i będziesz mieć możliwość poruszania się po scenie, przenosząc urządzenie. Tryby te używają różnych typów przestrzeni odniesienia. Tekst zaznaczony powyżej pokazuje, jak należy wybrać tę opcję. Używa on tych typów odwołań:

local – punkt początkowy znajduje się w miejscu, w którym znajdował się użytkownik w momencie utworzenia sesji. Oznacza to, że nie zawsze jest ono dobrze zdefiniowane, a dokładna pozycja punktu początkowego może się różnić w zależności od platformy. Chociaż nie ma ustalonych wcześniej granic w tym obszarze, treści powinny być przeglądane wyłącznie przez obrót. Jak widać na przykładzie naszej funkcji AR, możliwe jest pewne poruszanie się w przestrzeni.

viewer – najczęściej używany w przypadku treści wyświetlanych w ramach strony. Ten znak odstępu jest dostosowywany do urządzenia wyświetlającego. Gdy zostanie przekazany do getViewerPose, nie zapewnia śledzenia i zawsze zwraca pozę w początku, chyba że aplikacja zmodyfikuje ją za pomocą XRReferenceSpace.getOffsetReferenceSpace(). Przykładowy kod korzysta z tego mechanizmu, aby umożliwić przesuwanie kamery za pomocą dotyku.

Uruchamianie pętli ramek

Koncepcyjnie nic się nie zmienia w stosunku do tego, co zrobiłem podczas sesji VR opisanej w moim wcześniejszym artykule. Przekaż typ przestrzeni referencyjnej do obiektu XRFrame.getViewerPose(). Zwrócona wartość XRViewerPose będzie dotyczyła bieżącego typu przestrzeni referencyjnej. Użycie opcji viewer jako domyślnej pozwala stronie wyświetlać podgląd treści przed poproszeniem użytkownika o zgodę na korzystanie z AR lub VR. To pokazuje ważną kwestię: treści wbudowane korzystają z tego samego pętli ramek co treści w trybie pełnoekranowym, co zmniejsza ilość kodu, który należy utrzymywać.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(refSpaceType);
  if (xrViewerPose) {
    // Render based on the pose.
  }
}

Podsumowanie

Ta seria artykułów obejmuje tylko podstawy wdrażania treści w internecie. Więcej możliwości i przypadków użycia znajdziesz w próbkach interfejsu WebXR Device API przygotowanych przez grupę roboczą ds. wirtualnej rzeczywistości w internecie. Opublikowaliśmy też artykuł z testem skuteczności, w którym opisujemy interfejs API do wykrywania powierzchni i umieszczania wirtualnych przedmiotów w rzeczywistym widoku kamery. Zapoznaj się z tymi artykułami i śledź bloga web.dev, aby w nadchodzącym roku czytać więcej artykułów.

Zdjęcie: David Grandmougin, Unsplash