ARKit, SceneKit und Wie man die Welt kontrolliert

In Teil 1 dieser Serie haben wir einen Workflow durchlaufen, in dem wir ein 3D-Modell verarbeitet, ein AR-Projekt in Xcode erstellt, eine AR-Sitzung gestartet und unser Modell in unsere erweiterte Szene eingefügt haben.

In diesem Beitrag setzen wir unser Modell mithilfe verschiedener SceneKit-Methoden in die Tat um und beginnen mit der Interaktion mit den Objekten in unserer Welt.

Das Projekt für diesen Beitrag finden Sie unter https://github.com/AbovegroundDan/ARTutorial_Part2

SceneKit-Aktionen

SceneKit bietet eine Reihe von Aktionen, die auf einen Knoten angewendet werden können. Mit diesen Aktionen können Bewegungen, Rotationen, Skalierungen und andere Knoteneigenschaften animiert werden. Sie können gruppiert werden, um gleichzeitig ausgeführt zu werden, nacheinander ausgeführt und wiederholt oder umgekehrt. Die vollständige Liste finden Sie unter https://developer.apple.com/documentation/scenekit/scnaction

Wir werden das aktuelle Projekt weiter bearbeiten und dem Objekt einige Aktionen hinzufügen. Beginnen wir damit, unserer Kugel eine Drehung hinzuzufügen.

Fügen Sie nach der addSphere-Methode in unserer HoverScene die folgende Methode hinzu:

In diesem Code erstellen wir eine Aktion, die eine 180-Grad-Drehung um die Y-Achse beschreibt. Diese Drehung sollte 5 Sekunden dauern. Dann nehmen wir diese Aktion vor und fügen sie dem übergebenen Knoten hinzu. Jetzt müssen wir diese Methode von unserer addSphere-Methode aufrufen. Fügen Sie am Ende der Methode nach der Zeile, in der der untergeordnete Knoten hinzugefügt wird, die folgende Zeile hinzu:

Wenn wir nun diesen Code ausführen, sehen wir, wie sich unsere Kugel in die andere Richtung dreht und dann anhält. Was wir jetzt tun möchten, ist, diese Animation zu wiederholen, damit sie sich weiter dreht.

Ändern wir unseren addAnimation-Code wie folgt:

Hier haben wir eine Aktion "Für immer wiederholen" hinzugefügt, bei der die Rotationsaktion als Eingabe verwendet wird. Dann fügen wir anstelle der Rotationsaktion die Aktion repeatForever zu unserem Knoten hinzu. Führen Sie den Code erneut aus, und wir werden sehen, dass sich unsere Kugel jetzt kontinuierlich dreht.

Fügen wir der Kugel ein bisschen Pizzaz hinzu. Lassen Sie es auch ein wenig auf und ab schweben. Wir werden eine Hover-Up- und eine Hover-Down-Aktion hinzufügen, diese beiden Aktionen nacheinander ausführen und sie dann mit unserer vorhandenen Rotationsaktion gruppieren. So sollte die addAnimation-Methode aussehen:

Jetzt haben wir eine rotierende, schwebende Kugel, die wir überall auf unserer Welt platzieren können.

HitTests und Abstraktionen

Fügen wir der Szene etwas Interaktivität hinzu. Legen wir ein Ziel fest, um die Szene zu starten, indem der Benutzer die Kugeln in der Welt platziert und dann auf tippt, um sie zu aktivieren. Da unser Code etwas komplexer wird, ist es an der Zeit, den Umgang mit unseren Szenenobjekten zu abstrahieren. Erstellen Sie in unserem Projekt eine neue Gruppe mit dem Namen "Objekte". In diesem Ordner erstellen wir eine neue Swift-Datei mit dem Namen SceneObject.swift.

Wir werden eine Basisklasse, SceneObject, erstellen, die von SCNNode abgeleitet ist.

Wir möchten das Laden des Objekts vom Rest des Codes abstrahieren, also erstellen wir eine init () -Methode, die einen Dateinamen aufnimmt. In diesem Initialisierer verschieben wir den Code, den wir zum Laden aus einer Datei haben.

Jetzt können wir eine Sphere-Klasse erstellen, die von SceneObject abgeleitet ist:

Wir haben jetzt eine Sphere-Objektklasse, die sich selbst laden kann. Da wir die Kugeln beim Antippen animieren werden, entfernen wir den Aufruf addAnimation aus der Methode addSphere in unserer HoverScene. Da wir jetzt den gesamten Ladecode in die Sphere-Klasse verschoben haben, können wir Sphere einfach initialisieren und direkt zum Stammknoten der Szene hinzufügen. Unsere stark vereinfachte Methode sieht jetzt so aus:

Viel sauberer!

Jetzt schauen wir uns an, wie wir einen Treffertest durchführen können. Wir haben bereits eine Tap-Gesten-Erkennung in unserem View-Controller, damit wir uns darauf einlassen können. Aber woher wissen wir, ob unsere Taps auf eine Kugel, ein anderes Objekt oder gar nichts treffen?

Zum Glück kann uns unser ARSCNView dabei helfen. Es hat die folgende Methode:

Wir können ihm eine Position in der Ansicht zuweisen, und es gibt uns eine Reihe von Knoten zurück, die sich unter diesem Punkt befinden, unabhängig vom Z-Wert oder der Tiefe.

Da wir nur Sphere-Objekte erfassen möchten, können Sie einen Schnellfilter erstellen, der prüft, ob jeder im hitTest zurückgegebene Knoten eine Sphere ist. Dazu müssen wir für jeden Knoten, den wir überprüfen möchten, den obersten übergeordneten Knoten ermitteln. Kehren wir zu unserer Datei Node + Extensions.swift zurück und fügen Sie die folgende Methode hinzu:

Da alle Objekte in unserer Szene dem Stammknoten der Szene untergeordnet sind, möchten wir anhalten, wenn wir diesen Knoten erreichen, und nicht weiter prüfen. Da es sich um eine rekursive Methode handelt, halten wir an und kehren zurück, wenn wir feststellen, dass der Stammknoten der Elternknoten unseres Knotens ist.

Nachdem dies geschehen ist, kehren wir zu unserem ViewController zurück und ändern unseren Delegierten für die Erkennung von Tippbewegungen. Wir möchten weiterhin neue Kugeln hinzufügen, wenn wir auf eine leere Stelle tippen, aber wenn wir auf eine vorhandene Kugel tippen, möchten wir deren Animation starten.

Wenn wir einen Tipp erhalten, möchten wir den Punkt in unserer Szenenansicht anzeigen, diesen an die hitTest-Methode der Szenenansicht übergeben und sehen, was wir zurückbekommen. Da wir immer nur ein Objekt gleichzeitig bearbeiten möchten, greifen wir nach dem ersten Objekt (wenn Treffer vorliegen) und verwenden dann die Erweiterung topmost (), um das oberste übergeordnete Objekt zu ermitteln und zu überprüfen, ob es sich um eine Kugel handelt. Wenn ja, fügen wir unsere Animation hinzu. Wenn wir bei unserem Test keine Treffer erhalten haben, fügen wir wie zuvor eine neue Kugel vor der Kamera hinzu.

Mach weiter und starte die App erneut. Wir können tippen, um eine Kugel hinzuzufügen, und dann auf eine beliebige Kugel tippen, um sie in Bewegung zu setzen. Wir haben jedoch einen Fehler, den wir eingeführt haben. Wir können weiterhin auf eine Kugel tippen und die Animationen werden jedes Mal zum Objekt hinzugefügt. Sie können es testen und sehen, wie sich die Kugel bei jedem Antippen schneller dreht und schneller auf und ab bewegt.

Da die Animation für die Kugel spezifisch ist, verschieben wir den addAnimation-Code in die Kugel selbst und benennen ihn in "nur animieren" () um. Anstelle von node.addAnimation können wir einfach addAnimation aufrufen. Wir fügen der Sphere-Klasse auch ein Flag hinzu, das wir vor dem Hinzufügen der Animation überprüfen und beim ersten Hinzufügen auf "true" setzen:

Sie müssen lediglich den Code in unserem Gestenrückruf ändern, um diesen neuen Anruf auf der Kugel selbst auszuführen.

Wir sind jetzt mit diesem Teil fertig. Wir haben eine Kugel, die wir in der Welt platzieren können, die eine Interaktion hinzugefügt hat, damit wir die Animation starten und den Code ein wenig aufräumen können.

Extra Gutschrift

Die Art und Weise, wie wir eine Kugel in die Welt setzen, ist ziemlich abrupt. Wir tippen und plötzlich ist es da. Fügen wir dieser Funktion einen kleinen Pizzazz hinzu und animieren die Kugel, wenn wir sie platzieren.

Fügen Sie in unserer addSphere-Methode in HoverScene einen Skalierungseffekt hinzu. Wenn wir die Kugel hinzufügen, animieren wir ihre Skalierung und setzen statt einer linearen Standardskalierung einen Bounce- oder Pop-In-Effekt ein.

Lassen Sie uns unsere addSphere-Methode wie folgt ändern und die easyOutElastic-Timing-Funktion hinzufügen, die uns diese Sprungkraft verleiht:

Wenn wir nun auf eine Kugel tippen, erhalten wir einen ziemlich coolen animierten Effekt.

Extra Gutschrift, Teil Deux

Wir haben viel mit SceneKit gemacht, haben aber nur die Oberfläche von einigen Dingen gestreift, die ARKit kann. Lassen Sie uns der Szene ein wenig Spaß machen, indem Sie die Kugel auf die Kamera „schauen“, bevor wir uns mit den Funktionen von ARKit befassen. Die updateAtTime-Methode des Renderers ist bereits integriert, und wir haben dort auch einen Verweis auf die Kamera. Beginnen wir also damit, der Sphere-Klasse eine Methode hinzuzufügen, damit sie in eine bestimmte Richtung blickt. Das "Auge" der Kugel zeigt bereits auf das negative Z, das die Vorwärtsrichtung des Objekts darstellt. Wir erstellen eine Methode, bei der ein Vektor einen Punkt im Raum markiert, dem unser „Auge“ gegenübersteht.

In diesem Code betrachten wir den Abstand zwischen der Kugel und der Zielposition (Kamera). Wenn es weniger als eine bestimmte Menge ist, animieren wir das Auge zum Ziel. Wenn das Auge auf die Kamera gerichtet war und der Benutzer sich weiter als diese festgelegte Entfernung entfernt, werden wir unsere "Patrouillen" -Animation starten. In diesem Code ist Folgendes zu beachten: Da es keine praktische SCNAction zum Anwenden einer LookAt-Animation gibt, binden wir unseren look (at :) -Aufruf in eine SCNTransaction ein, mit der wir die Bewegung animieren können. Spezielle 3D-Spiele-Engines wie Unity oder Unreal bieten Komfortfunktionen für diese Dinge, aber SceneKit ist noch nicht auf diesem Niveau.

Möglicherweise gibt es auf dem targetPos SCNVector3 einen Fernaufruf, der übergeben wurde, aber diese Methode ist für SCNVector3 nicht vorhanden. Wir werden für diesen Ferngespräch eine neue Nebenstelle hinzufügen.

Ich habe diesen Code in eine neue UtilityExtensions.swift-Datei eingefügt, kann ihn jedoch beliebig einfügen.

Als nächstes müssen wir unsere updateAtTime-Methode ändern, um die Flag-Prüfung zu entfernen und für jeden Frame eine Methode in unserem Szenen-Controller aufzurufen. Unser Szenen-Controller ist dafür verantwortlich, die Nachricht an alle Sphere-Objekte in unserer Szene zu senden.

In unserer HoverScene erstellen wir die makeUpdateCameraPos-Methode, die nur nach Sphere-Objekten filtert, und rufen die patrol-Methode auf.

Ändern wir auch unsere Platzierungsmethode, um die Kugeln etwas weiter weg zu platzieren. Lassen Sie die didTapScreen-Methode unsere Kugel 5 Meter entfernt statt 1 platzieren:

Lassen Sie uns in unserer Sphere-Klasse unsere Schwelle festlegen, um den Blick auf 4,85 Meter zu lenken:

Lassen Sie uns auch unsere Sphere-Animation so ändern, dass sie sich ein wenig umschaut und nicht schwebt.

Das Float.random ist eine weitere Erweiterung, die einfach ist:

Probier das aus und platziere ein paar Kugeln. Sie sollten sich jetzt selbst animieren, ohne sie anzapfen zu müssen. Gehen Sie näher an jeden heran, und Sie sollten sehen, dass sie den Blick auf Sie richten. Gehen Sie weiter weg und sie sollten wieder auf Patrouille gehen. Jetzt haben wir eine Szene direkt aus einer dystopischen Zukunft, mit schwebenden Augen, die jede unserer Bewegungen beobachten.

Bleiben Sie dran für mehr ARKit-Spaß!