4. Experiment 4: [WebXR mit ReactXR Projekt]

Datum: [16.05.2024] Thema: [WebXR mit ReactXR Projekt]

4.1. Einleitung

WebXR spielt eine immer wichtigere Rolle in der Welt der Augmented Reality (AR), da es Entwicklern ermöglicht, beeindruckende AR-Anwendungen direkt im Webbrowser zu erstellen. Eine solche Anwendung kann eine Vielzahl von Anwendungsfällen haben, von Spielen bis hin zu Bildungs- und Informationsanwendungen.

4.1.1. Motivation

Die Idee, eine AR-Anwendung mit WebXR zu entwickeln, wurde aus der Motivation heraus geboren, eine immersive Erfahrung zu schaffen, die es den Benutzern ermöglicht, Sehenswürdigkeiten auf interaktive und unterhaltsame Weise zu erkunden. Da die Technologie immer zugänglicher wird und das Interesse an AR-Anwendungen wächst, war es ein spannendes Unterfangen, sich mit der Entwicklung einer solchen Anwendung zu beschäftigen. Durch die Nutzung von WebXR konnten wir nicht nur unsere Entwicklerfähigkeiten verbessern, sondern auch innovative Wege erkunden, um AR-Erlebnisse direkt im Webbrowser zu präsentieren.

4.1.2. Aufgabenstellung

Um mit unserer AR-Anwendung mit WebXR zu beginnen, haben wir zunächst kostenlose 3D-Modelle von Sehenswürdigkeiten im Internet gefunden. Diese Modelle haben wir dann mit ReactXR integriert, um eine immersive Galerie von Sehenswürdigkeiten zu erstellen. Um aktuelle Informationen über Sehenswürdigkeiten anzuzeigen, haben wir APIs und verschiedene Datenquellen genutzt, um auf Anfrage relevante Daten zu erhalten. Sobald die AR-Anwendung funktioniert, werden wir eine Installationsanleitung in der README.md bereitstellen, um anderen Benutzern zu ermöglichen, die Anwendung problemlos zu verwenden.

4.2. Grundlagen

Wir verwenden für diesen Versuch ReactXR - React components and hooks for creating VR/AR applications - für das Erstellen eines Augmented Reality Anwendung. Auf der RectXR GitHub wird Schritt für Schritt erklärt, wie eine Anwendung eingerichtet werden muss und dazu werden die Beispielprojekte angezeigt. Für ReactXR verwenden wir die Version 5.7.1.

4.3. Versuchsdurchführung

Dieser Abschnitt beschreibt die Vorbereitung, Durchführung, erzielten Ergebnisse und eventuelle Probleme während des Versuchs. Als erstes, mussten wir herausfinden, wie man im Allgemeinen eine Augmented Reality Anwendung für das Web erstellt. Dafür können wir die WebXR Device API verwenden. Es gibt mehrere Frameworks und Libraries, die WebXR API unterstützt, aber wir haben ReactXR gewählt. Dazu haben wir uns in die RectXR Documentation einlesen müssen. Nachdem wie eine React Anwendung erstellt haben, müssen wir ReactXR importieren. npm install @react-three/xr Nachdem alles importiert wurde, können wir sofort die Szene erstellen und konfigurieren.

    <div className="container">
  <div>
    <ARButton
      ref={arBtnRef}
      onClick={() => {
        setArMode(!arMode);
      }}
    />
  </div>
  <ControlsUI arMode={arMode}/>
  <Canvas shadows>
    <XR referenceSpace="local">
      <Light />
      <pointLight position={[12, 12, 12]} />
      <ModelHitTest />
      <Controllers />
    </XR>
  </Canvas>
</div>

Hier haben wir die ControlsUI für den AR-Modus hinzugefügt, sowie eigene Knöpfe und die Szene (Canvas). Unsere Szene besteht aus Licht, PointLight, ModelHitTest und Controllern. ModelHitTest ist unsere Sammlung von Objekten in der Szene und wird so genannt, weil die HitTest-Funktion implementiert ist. HitTest in AR-Frameworks ermöglicht es den Objekten, der Kamera eines Smartphones zu folgen, und letztendlich kann ein Benutzer die Objekte an einem beliebigen Ort platzieren.

      useHitTest((hitMatrix, hit) => {
  if (!firstHit) {
    //make object invisible from the start
    hitPoint.current!.children.at(0)!.visible = false;
    //make object follow the camera
    hitMatrix.decompose(
      hitPoint.current!.position,
      hitPoint.current!.quaternion,
      hitPoint.current!.scale
    );
  }
});

Ganz am Anfang vor der Platzierung von Objekten verwenden wir die Methode useHitTest mit hitMatrix.decompose. Das ermöglicht es den Objekten, der Kamera zu folgen. Nachdem wir auf unsere Objekte gedrückt haben, verfolgen die Objekte die Kamera nicht mehr.

  <mesh ref={hitPoint} receiveShadow>
  <ModelsArray />
  <Interactive onSelect={onSelect}>
    <PlaceButton />
  </Interactive>
  <Interactive onSelect={onSelectNext}>
    <SwitchButton name="Next" position={[1, 1, 0]} />
  </Interactive>
  <Interactive onSelect={onSelectPrev}>
    <SwitchButton name="Previous" position={[-1, 1, 0]} />
  </Interactive>
</mesh>

Unsere Sammlung von Objekten besteht aus: - ModelsArray - die Sammlung aller Sehenswürdigkeiten, die unsere Anwendung enthält. - PlaceButton - der Knopf, der am Anfang erscheint und uns die Position zeigt, an der wir unsere Objekte platzieren möchten. - 2 Objekte SwitchButton - die Knöpfe, die das Austauschen von Objekten ermöglichen.

Bevor wir betrachten, wie die Knöpfe die Objekte wechseln lassen, müssen wir noch wissen, wie die Objekte in der ModelsArray-Komponente implementiert sind.

function ModelsArray(props: any) {
        const models = ["/assets/EiffelTower-animated.glb", "/assets/pyramid.glb", "/assets/pyramid2.glb", "/assets/fuji.glb"];
        const eiffel = useGLTF(models[0]); // get the scene from file
        const pyramid = useGLTF(models[1]);
        const pyramid2 = useGLTF(models[2]);
        const fuji = useGLTF(models[3]);

        return (
                <Interactive>
                        <primitive object={eiffel.scene} scale={0.5} position={[0.0,0,0]} rotation={[0,0,0]} />
                        <primitive object={pyramid.scene} scale={0.2} position={[0.0,0,0]} rotation={[0,0,0]} />
                        <primitive object={pyramid2.scene} scale={0.2} position={[0.0,0,0]} rotation={[0,0,0]} />
                        <primitive object={fuji.scene} scale={0.2} position={[0.0,0,0]} rotation={[0,0,0]} />
                </Interactive>
        );
}

Diese Funktion enthält die Sammlung „models“, die die Pfade zu den Objekten speichert. Danach laden wir die 3D-Modelle mithilfe der useGLTF-Bibliothek und fügen sie unserer Szene hinzu. Auf diese Weise erhalten wir die Struktur, dass unser Objekt 4 Unterobjekte enthält, die wir später als Array verwenden können. Zuerst haben wir einen anderen Ansatz ausprobiert: Wir haben nur ein Objekt erstellt, das später den Pfad dynamisch ändern würde, aber ReactXR erlaubt uns das nicht, da die Objekte vor dem Anzeigen geladen werden müssen.

    function onSelectNext() {
  let tempPointer = 0;
  hitPoint.current?.children.at(0)!.children.forEach(element => {
    if (tempPointer == pointer) {
      element.visible = true;
    } else {
      element.visible = false;
    }
    tempPointer++;
  });
  if (pointer == hitPoint.current?.children.at(0)!.children.length! - 1) {
    pointer = 0;
  } else {
    pointer++;
  }
}

function onSelectPrev() {
  let tempPointer = 0;
  hitPoint.current?.children.at(0)!.children.forEach(element => {
    if (tempPointer == pointer) {
      element.visible = true;
    } else {
      element.visible = false;
    }
    tempPointer++;
  });
  if (pointer == 0) {
    pointer = hitPoint.current?.children.at(0)!.children.length! - 1;
  } else {
    pointer--;
  }
}

ModelHitTest enthält auch die Methoden onSelectNext und onSelectPrev, die es uns ermöglichen, zwischen den Objekten zu wechseln. Unsere Sammlung von Objekten können wir als Kind der Szene erhalten:

hitPoint.current?.children.at(0)!

Am Anfang wird das Objekt mit der ID 0 angezeigt und alle anderen sind ausgeblendet. Um ein Objekt auszublenden, können wir die Kinder unserer Szene abrufen und alle ausblenden, die wir nicht benötigen.

  hitPoint.current?.children.at(0)!.children.forEach(element => {
  if (tempPointer == pointer) {
    element.visible = true;
  } else {
    element.visible = false;
  }
  tempPointer++;
});

Der folgende Code erstellt den Knopf, der uns die Objekte wechseln lässt. Box() erstellt einen Container, den wir als Teil von SwitchButton verwenden. SwitchButton besteht aus: import { Interactive } from ‚react-three-xr‘;

  • Interactive - die Komponente, die uns mit dem Knopf interagieren lässt.

  • Box - Container, den wir in der Vorherigen Methode erstellt haben.

  • Text - das Text, das auf dem Knopf gezeigt wird.

Mithilfe von Props können wir die Parametern übergeben und unsere Komponente wiederverwenden.

function Box({ color, size, scale, children, ...rest }: any) {
        return (
                <mesh scale={scale} {...rest}>
                <boxGeometry args={size} />
                <meshPhongMaterial color={color} />
                {children}
                </mesh>
        )
}

function SwitchButton(props: any) {
        var name: string = props.name;
        const [hover, setHover] = useState(false)

        return (
                <Interactive onHover={() => setHover(true)} onBlur={() => setHover(false)}>
                <Box scale={hover ? [1.4, 1.4, 1.4] : [1.2, 1.2, 1.2]} size={[0.4, 0.1, 0.1]} {...props}>
                        <Suspense fallback={null}>
                        <Text position={[0, 0, 0.06]} fontSize={0.05} color="#000" anchorX="center" anchorY="middle">
                                {name}
                        </Text>
                        </Suspense>
                </Box>
                </Interactive>
        )
}

4.3.1. Ergebnisse

Die AR-Anwendung funktioniert einwandfrei und man kann sie auf einem Smartphone laufen lassen. Wichtig aber ist der Browser, den man verwendet. Auf Android kann man Chrome oder Samsung Internet verwenden, und auf iOS muss man zusätzlich XRViewer Browser installieren, da Safari WebXR nicht unterstützt.

4.3.2. Fazit

Während der Entwicklung unserer Augmented-Reality-App stellten wir fest, dass der Prozess erstaunlich intuitiv verlief. Die Erfahrung in der Game-Entwicklung erwies sich als äußerst nützlich, da viele Konzepte und Werkzeuge sich zwischen den beiden Disziplinen überschneiden. Die Implementierung von Interaktionen verliefen fließend und organisch und alle 3D Modelle haben wir von Websites heruntergeladen, auf denen sie kostenlos und frei verfügbar sind. Dank der fortschrittlichen Technologie und der benutzerfreundlichen Entwicklertools konnten wir schnell und effizient arbeiten. Der Import von 3D-Objekten aus verschiedenen Quellen erwies sich ebenfalls als unkompliziert, da wir auf eine Vielzahl von Ressourcen zurückgreifen konnten, die frei verfügbar und für unsere Anwendung geeignet waren. Insgesamt war die Entwicklung unserer AR-App eine spannende und erfreuliche Erfahrung, die uns ermöglichte, kreativ zu sein und eine innovative Anwendung zu schaffen.

4.4. Literaturangaben

[1] https://immersiveweb.dev

[2] https://github.com/pmndrs/react-xr