ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

0 Shares

In unserem letzten ARKit-Tutorial haben wir gelernt, wie man die Größe horizontaler Ebenen misst. Es war ein hilfreicher Einstieg in die Arena der Bestimmung räumlicher Beziehungen zu realen Räumen im Vergleich zu virtuellen Objekten und Erfahrungen.

Dieses Mal werden wir in einen etwas anderen Bereich eintauchen, der einen anderen Aspekt der Messung in Augmented Reality berührt.

Was wirst du lernen?

In diesem Tutorial erfahren Sie, wie Sie den Abstand zwischen zwei beliebigen Punkten in einer horizontalen Ebene messen. Mit ARKit können Sie mit einem iPad oder iPhone alles auf einer ebenen Fläche messen.

Wenn Sie dies noch nicht getan haben, sehen Sie sich dieses vergangene Tutorial an, um zu erfahren, wie Sie die Größe horizontaler Ebenen messen.

Mindestanforderungen

Mac mit MacOS 10.13.2 oder höher. Xcode 9.2 oder höher. Ein Gerät mit iOS 11+ auf einem A9 oder höher Prozessor. Grundsätzlich das iPhone 6S und höher, das iPad Pro (9,7 Zoll, 10,5 Zoll oder 12,9 Zoll; erste und zweite Generation) und das iPad 2017 oder höher. Swift 4.0. Obwohl Swift 3.2 unter Xcode 9.2 funktioniert, empfehle ich dringend, den neuesten Xcode herunterzuladen, um auf dem neuesten Stand zu bleiben. Ein Apple Developer-Konto. Es ist jedoch zu beachten, dass Sie kein kostenpflichtiges Apple Developer-Konto benötigen. Mit Apple können Sie Apps mit einem unbezahlten Apple Developer-Konto auf einem Testgerät bereitstellen. Sie benötigen jedoch ein kostenpflichtiges Entwicklerkonto, um Ihre App in den App Store zu stellen. (Informationen zur Funktionsweise des Programms finden Sie auf der Apple-Website, bevor Sie sich für Ihr kostenloses Apple Developer-Konto registrieren.)

Schritt 1: Laden Sie die Assets herunter, die Sie benötigen

Um das Befolgen dieses Tutorials zu vereinfachen, habe ich einen Ordner mit den erforderlichen 2D-Assets und der für das Projekt erforderlichen Swift-Datei erstellt. Diese Dateien stellen sicher, dass Sie sich in diesem Handbuch nicht verlaufen. Laden Sie daher den komprimierten Ordner mit den Assets herunter und entpacken Sie ihn.

Schritt 2: Richten Sie das AR-Projekt in Xcode ein

Wenn Sie sich nicht sicher sind, wie Sie dies tun sollen, befolgen Sie Schritt 2 in unserem Beitrag zum Steuern einer 3D-Ebene mit hitTest, um Ihr AR-Projekt in Xcode einzurichten. Geben Sie Ihrem Projekt einen anderen Namen, z NextReality_Tutorial5. Führen Sie unbedingt einen kurzen Testlauf durch, bevor Sie mit dem folgenden Tutorial fortfahren.

Schritt 3: Importieren Sie Assets in Ihr Projekt

Klicken Sie im Projektnavigator auf den Ordner “Assets.xcassets”. Wir werden hier unsere 2D-Bilder hinzufügen. Klicken Sie dann mit der rechten Maustaste auf den linken Bereich des Bereichs auf der rechten Seite des Projektnavigators. Wählen Sie “Importieren” und fügen Sie die Datei “overlay_grid.png” aus dem entpackten Ordner “Assets” hinzu.

ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

Klicken Sie anschließend im Projektnavigator erneut mit der rechten Maustaste auf den gelben Ordner für “NextReality_Tutorial5” (oder wie auch immer Sie Ihr Projekt benannt haben). Wählen Sie die Option “Dateien zu ‘NextReality_Tutorial5’ hinzufügen”.

ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

Navigieren Sie zum entpackten Ordner “Assets” und wählen Sie die Datei “Grid.swift”. Stellen Sie sicher, dass Sie “Elemente bei Bedarf kopieren” aktivieren und alles andere unverändert lassen. Klicken Sie dann auf “Hinzufügen”.

ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

“Grid.swift” sollte jetzt zu Ihrem Projekt hinzugefügt werden, und Ihr Projektnavigator sollte ungefähr so ​​aussehen:

ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

Diese Datei hilft beim Rendern eines Rasters für jede horizontale Ebene, die ARKit erkennt.

Schritt 4: Platzieren Sie ein Raster, um erkannte horizontale Ebenen anzuzeigen

In unserem Tutorial zur Erkennung horizontaler Ebenen finden Sie Informationen zu den allgemeinen Ebenenerkennungsfunktionen von ARKit.

Öffnen Sie die Klasse “ViewController.swift”, indem Sie darauf doppelklicken. Wenn Sie dem endgültigen Code für Schritt 4 folgen möchten, öffnen Sie einfach diesen Link, um ihn auf GitHub anzuzeigen.

Ändern Sie in der Datei “ViewController.swift” die Zeile zum Erstellen von Szenen in der viewDidLoad () Methode. Ändern Sie es von diesem:

let scene = SCNScene(named: "art.scnassets/ship.scn")!

Damit wird sichergestellt, dass keine Szene mit dem Standardschiffmodell erstellt wird:

let scene = SCNScene()

Als nächstes finden Sie diese Zeile oben in der Datei:

@IBOutlet var sceneView: ARSCNView!

Fügen Sie unter dieser Linie diese Linie hinzu, um ein Array von “Gittern” für alle erkannten horizontalen Ebenen zu erstellen:

var grids = [Grid]()

Kopieren Sie die folgenden zwei Methoden und fügen Sie sie wie unten aufgeführt am Ende der Datei vor der letzten geschweiften Klammer ein ( }} ) in der Datei. Mit diesen Methoden können wir unser Raster in den von ARKit erkannten horizontalen Ebenen als visuellen Indikator hinzufügen.

// 1.
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    let grid = Grid(anchor: anchor as! ARPlaneAnchor)
    self.grids.append(grid)
    node.addChildNode(grid)
}
// 2.
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    let grid = self.grids.filter { grid in
        return grid.anchor.identifier == anchor.identifier
    }.first

    guard let foundGrid = grid else {
        return
    }

    foundGrid.update(anchor: anchor as! ARPlaneAnchor)
}

Lassen Sie uns kurz durchgehen, was in diesen beiden Methoden passiert:

    Das didAdd () wird aufgerufen, wenn ein neuer Knoten zum hinzugefügt wird ARSCNView. Hier nehmen wir die erkannten ARPlaneAnchor und füge es als unser hinzu Gitter Objekt, das das von uns importierte Rasterbild zu jeder erkannten Ebene hinzufügt. Das didUpdate () wird immer dann aufgerufen, wenn neuer ARPlaneAnchor Knoten werden erkannt oder wenn die Ebene erweitert wird. In diesem Fall möchten wir auch unser Raster aktualisieren und erweitern. Wir machen das hier, indem wir anrufen aktualisieren() auf diesem spezifischen Gitter.

Lassen Sie uns nun Feature-Punkte aktivieren. Unter dieser Zeile in viewDidLoad ()::

sceneView.showsStatistics = true

Hinzufügen:

sceneView.debugOptions = ARSCNDebugOptions.showFeaturePoints

Als nächstes aktivieren wir die Erkennung der horizontalen Ebene. Unter dieser Zeile in viewWillAppear ()::

let configuration = ARWorldTrackingConfiguration()

Hinzufügen:

configuration.planeDetection = .horizontal

Das ist sehr wichtig! Dadurch wird sichergestellt, dass ARKit horizontale, flache geometrische Ebenen in der realen Welt erkennen kann. Mit den Feature-Punkten können wir alle 3D-Punkte anzeigen, die ARKit erkennen kann.

Führen Sie Ihre App auf Ihrem Telefon aus und gehen Sie herum. Konzentrieren Sie sich auf einen gut beleuchteten Bereich auf dem Boden, und Sie sollten in der Lage sein, blaue Gitter zu sehen, wenn eine horizontale Ebene erkannt wird:

ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

Kontrollpunkt: Ihr gesamtes Projekt am Ende dieses Schritts sollte wie der endgültige Schritt 4-Code auf meinem GitHub aussehen.

Schritt 5: Platzieren Sie mit dem hitTest Markierungen auf den erkannten horizontalen Ebenen

Bevor Sie mit diesem Schritt beginnen, empfehlen wir Ihnen dringend, sich unser hitTest-Tutorial anzusehen, um die Grundlagen der Funktionsweise von hitTest zu erläutern. In diesem Schritt platzieren wir Start- und Endmarkierungen zwischen unseren beiden Punkten.

Wenn Sie dem endgültigen Code für Schritt 5 folgen möchten, öffnen Sie einfach den Link, um ihn auf GitHub anzuzeigen.

Fügen Sie zunächst am Ende des eine Gestenerkennung hinzu viewDidLoad () Methode, wie unten gezeigt. Sobald ein Tippen auf dem Bildschirm erfolgt, wird die tippte () Methode wird aufgerufen.

let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
sceneView.addGestureRecognizer(gestureRecognizer)

Fügen Sie nun die hinzu tippte (), wie unten gezeigt, am Ende der Datei, jedoch vor der letzten geschweiften Klammer (}}).

@objc func tapped(gesture: UITapGestureRecognizer) {
    // Get 2D position of touch event on screen
    let touchPosition = gesture.location(in: sceneView)

    // Translate those 2D points to 3D points using hitTest (existing plane)
    let hitTestResults = sceneView.hitTest(touchPosition, types: .existingPlane)

    guard let hitTest = hitTestResults.first else {
        return
    }
}

Derzeit übersetzt dieser Code nur den auf dem Bildschirm getippten 2D-Punkt mithilfe von hitTest in einen 3D-Punkt auf einer erkannten Ebene. Wir werden in einem späteren Schritt darauf zurückkommen, weitere Funktionen hinzuzufügen.

Wir brauchen mehrere Punktpaare, um sie den horizontalen Ebenen hinzuzufügen. Jedes Paar hat einen Start- und einen Endpunkt. Dazu müssen wir anhand der Reihenfolge der Abgriffe verfolgen, welcher Punkt hinzugefügt wird. Das erste Tippen ist für den Startpunkt und das zweite Tippen ist für den Endpunkt. Danach wird es zurückgesetzt, sodass weitere Paare hinzugefügt werden können. Beginnen wir damit.

Deklarieren und initialisieren Sie diese Variable zunächst und verfolgen Sie die Anzahl der Abgriffe direkt nach dem Deklarieren der Variablen für die Gitter Array, das wir im vorherigen Schritt erstellt haben:

var numberOfTaps = 0

Als nächstes erhöhen wir diese Variable jedes Mal, wenn ein Tippen auftritt, oder mit anderen Worten, wenn tippte () wird genannt. Fügen Sie dies am Anfang des tippte () Methode:

numberOfTaps += 1

Jetzt brauchen wir Logik, um zu entscheiden, ob es das erste oder das zweite Tippen war. Basierend darauf fügen wir eine rote oder eine grüne Markierung ein. Fügen Sie dies am Ende des tippte () Methode:

// If first tap, add red marker. If second tap, add green marker and reset to 0
if numberOfTaps == 1 {
    addRedMarker(hitTestResult: hitTest)
}
else {
    // After 2nd tap, reset taps to 0
    numberOfTaps = 0
    addGreenMarker(hitTestResult: hitTest)
}

Im obigen Code haben wir sichergestellt, dass eine rote Markierung hinzugefügt wird, wenn es das erste Tippen war, und eine grüne Markierung, wenn es das zweite Tippen war. Als nächstes setzen wir die Variable zurück numberOfTaps nach dem zweiten Tippen auf 0, damit neue Punktepaare hinzugefügt werden können.

Zuletzt definieren wir die Methoden, mit denen unsere Marker hinzugefügt werden. Fügen Sie den folgenden Code nach dem hinzu tippte () Methode, aber vor der letzten geschweiften Klammer in der Datei:

func addRedMarker(hitTestResult: ARHitTestResult) {
    addMarker(hitTestResult: hitTestResult, color: .red)
}

func addGreenMarker(hitTestResult: ARHitTestResult) {
    addMarker(hitTestResult: hitTestResult, color: .green)
}

func addMarker(hitTestResult: ARHitTestResult, color: UIColor) {
    let geometry = SCNSphere(radius: 0.01)
    geometry.firstMaterial?.diffuse.contents = color

    let markerNode = SCNNode(geometry: geometry)
    markerNode.position = SCNVector3(hitTestResult.worldTransform.columns.3.x, hitTestResult.worldTransform.columns.3.y, hitTestResult.worldTransform.columns.3.z)

    sceneView.scene.rootNode.addChildNode(markerNode)
}

Hier unsere beiden Methoden, addRedMarker () und addGreenMarker ()Rufen Sie die Hilfsmethode auf addMarker () um beide Marker hinzuzufügen. Im addMarker (), wir schaffen eine SCNSphere Instanz mit der übergebenen Farbe und Platzierung basierend auf dem hitTest-Ergebnis, um den Punkt zu identifizieren, an dem wir getippt haben.

Stellen Sie nun die App bereit und führen Sie sie aus. Bewegen Sie Ihr Telefon und konzentrieren Sie sich auf einen gut beleuchteten Bereich am Boden. Wenn Sie die erkannten horizontalen Ebenen sehen, tippen Sie auf eine beliebige Stelle, um Ihre roten und grünen Markierungen zu platzieren. Sie sollten so etwas sehen:

ARKit 101: Messen des Abstands zwischen zwei Punkten auf einer horizontalen Ebene in Augmented Reality

Kontrollpunkt: Ihr gesamtes Projekt am Ende dieses Schritts sollte wie der endgültige Schritt 5-Code auf meinem GitHub aussehen

Schritt 6: Zeichnen Sie eine Linie und berechnen Sie den Abstand zwischen den beiden Punkten

In diesem Schritt berechnen wir auf einfache Weise den Abstand zwischen den beiden Punkten, die wir im letzten Schritt hinzugefügt haben, und verwenden einige SceneKit APIs, um eine Linie zwischen den beiden zu ziehen.

Wenn Sie dem endgültigen Code für Schritt 6 folgen möchten, öffnen Sie einfach den Link, um ihn auf GitHub anzuzeigen.

Ok, jetzt müssen wir in der Lage sein zu verfolgen, wo unsere beiden Punkte hinzugefügt werden. Machen wir Variablen für sie. Fügen Sie den folgenden Code hinzu, nachdem Sie das deklariert haben numberOfTaps Variable aus dem vorherigen Schritt:

var startPoint: SCNVector3!
var endPoint: SCNVector3!

Speichern Sie als Nächstes die Werte der hitTest-Ergebnisse in diesen Variablen. Nach dieser Zeile in der tippte ()::

if numberOfTaps == 1 {

Fügen Sie diese Zeile hinzu:

startPoint = SCNVector3(hitTest.worldTransform.columns.3.x, hitTest.worldTransform.columns.3.y, hitTest.worldTransform.columns.3.z)

Anschließend, nach dieser Zeile in der tippte ()::

// After 2nd tap, reset taps to 0
numberOfTaps = 0

Fügen Sie diese Zeile hinzu:

endPoint = SCNVector3(hitTest.worldTransform.columns.3.x, hitTest.worldTransform.columns.3.y, hitTest.worldTransform.columns.3.z)

Wir speichern einfach nur die Werte des hitTest-Ergebnisses in diesen beiden Variablen für jeden Marker.

Fügen wir nun eine Erweiterung zum hinzu SCNGeometrie Art. Fügen Sie den folgenden Code oben in der Datei direkt nach dieser Zeile ein, die ARKit importiert: ARKit importieren

extension SCNGeometry {
    class func lineFrom(vector vector1: SCNVector3, toVector vector2: SCNVector3) -> SCNGeometry {
        let indices: [Int32] = [0, 1]

        let source = SCNGeometrySource(vertices: [vector1, vector2])
        let element = SCNGeometryElement(indices: indices, primitiveType: .line)

        return SCNGeometry(sources: [source], elements: [element])
    }
}

Hier fügen wir benutzerdefinierte Funktionen hinzu SCNGeometrie damit wir eine Linie von einem Punkt zum anderen ziehen können.

Als nächstes, gleich nachdem wir die grüne Markierung in dieser Zeile hinzugefügt haben:

addGreenMarker(hitTestResult: hitTest)

Fügen Sie diese Codezeile hinzu:

addLineBetween(start: startPoint, end: endPoint)

Diese Methode hilft uns dabei, die Zeile tatsächlich zu unserer hinzuzufügen ARSCNView und zeigen Sie es auf dem Bildschirm. Fügen wir das hinzu addLineBetween () am Ende der Datei, aber vor der letzten geschweiften Klammer:

func addLineBetween(start: SCNVector3, end: SCNVector3) {
    let lineGeometry = SCNGeometry.lineFrom(vector: start, toVector: end)
    let lineNode = SCNNode(geometry: lineGeometry)

    sceneView.scene.rootNode.addChildNode(lineNode)
}

Diese Methode nimmt den Start- und Endpunkt in Form von Vektoren auf (SCNVector3) und fügt die generierte Zeile in Form von a hinzu SCNNode zur Szene. Mit anderen Worten, wir sollten jetzt eine Linie zwischen unseren beiden Punkten sehen!

Als nächstes brauchen wir eine Möglichkeit, den Abstand zwischen zwei Punkten zu berechnen. Gleich nach dem Hinzufügen des Codes für unsere SCNGeometrie Fügen Sie im vorherigen Schritt den folgenden Code hinzu:

extension SCNVector3 {
    static func distanceFrom(vector vector1: SCNVector3, toVector vector2: SCNVector3) -> Float {
        let x0 = vector1.x
        let x1 = vector2.x
        let y0 = vector1.y
        let y1 = vector2.y
        let z0 = vector1.z
        let z1 = vector2.z

        return sqrtf(powf(x1-x0, 2) + powf(y1-y0, 2) + powf(z1-z0, 2))
    }
}

extension Float {
    func metersToInches() -> Float {
        return self * 39.3701
    }
}

Hier fügen wir zwei Erweiterungen hinzu. Das erste ist das Hinzufügen von benutzerdefinierten Funktionen zum SCNVector3 Geben Sie ein, indem Sie die Entfernung zwischen den beiden Punkten mithilfe der Entfernungsformel berechnen können. Die zweite Möglichkeit besteht darin, dem Benutzer benutzerdefinierte Funktionen hinzuzufügen Schweben Geben Sie ein, indem Sie es uns ermöglichen, Meter in Zoll umzurechnen.

Als nächstes, gleich nachdem wir die Logik zum Aufrufen unserer Methode hinzugefügt haben, die im letzten Schritt eine Linie zwischen den beiden Punkten zeichnet:

addLineBetween(start: startPoint, end: endPoint)

Fügen Sie diese Zeile hinzu:

addDistanceText(distance: SCNVector3.distanceFrom(vector: startPoint, toVector: endPoint), at: endPoint)

Zuletzt fügen wir das hinzu addDistanceText () Methode am Ende der Datei, aber vor der letzten geschweiften Klammer:

func addDistanceText(distance: Float, at point: SCNVector3) {
    let textGeometry = SCNText(string: String(format: "%.1f"", distance.metersToInches()), extrusionDepth: 1)
    textGeometry.font = UIFont.systemFont(ofSize: 10)
    textGeometry.firstMaterial?.diffuse.contents = UIColor.black

    let textNode = SCNNode(geometry: textGeometry)
    textNode.position = SCNVector3Make(point.x, point.y, point.z);
    textNode.scale = SCNVector3Make(0.005, 0.005, 0.005)

    sceneView.scene.rootNode.addChildNode(textNode)
}

Diese Methode druckt einfach den Abstand zwischen den beiden Punkten neben dem Endpunkt aus.

Ok, worauf wartest du noch? Stellen Sie Ihre App bereit und führen Sie sie aus! Gehen Sie herum und konzentrieren Sie sich auf einen gut beleuchteten Bereich am Boden. Sobald Sie zwei Punkte auf den erkannten horizontalen Ebenen platziert haben, sollte zwischen den beiden Punkten eine Linie mit dem Abstand direkt neben dem Endpunkt (grüne Markierung) gezogen werden.

Was wir erreicht haben

Gut gemacht! Sie haben erfolgreich gelernt, wie Sie mit ARKit zwischen zwei Punkten in einer horizontalen Ebene messen. Wenn Sie das nächste Mal eine flache Oberfläche messen müssen, verwenden Sie diese von Ihnen erstellte App anstelle eines Maßbandes.

Lassen Sie uns das durchgehen, was Sie aus diesem Tutorial gelernt haben: Platzieren eines Gitters über einer erkannten horizontalen Ebene, Erstellen von Start- und Endmarkierungen für beide Punkte mit dem hitTest und Erstellen einer benutzerdefinierten Erweiterung zum Berechnen des Abstands zwischen den beiden Punkten und Zeichnen einer Linie zwischen diesen Punkten Sie.

Wenn Sie den vollständigen Code für dieses Projekt benötigen, finden Sie ihn in meinem GitHub-Repo. Ich hoffe, Ihnen hat dieses Tutorial auf ARKit gefallen. Wenn Sie Kommentare oder Feedback haben, können Sie diese gerne im Kommentarbereich hinterlassen. Viel Spaß beim Codieren!

Verpassen Sie nicht: So messen Sie den Boden mit ARKit

0 Shares