我无法在 Swift 中解决 "Use of undeclared type 'SphereNode'"

I can't solve "Use of undeclared type 'SphereNode'" in Swift

我正在尝试使用 Swift 的 ARKit 制作一个简单的测量应用程序。

我运行一个demo工程,找个好例子。

但是我无法使用'SphereNode'。

使用 Swift 创建第一个应用程序的过程具有挑战性。

我希望你能理解,因为英语不是我的母语。

我的完整来源如下。

谢谢。

P.S。我的系统版本是'OSX ver. 10.14',最新的'xCode ver. 10.0'是2018.09.27

//
//  ViewController.swift
//  Reference : https://virtualrealitypop.com/ios-11-tutorial-how-to-measure-objects-with-arkit-743d2ec78afc.
//

import UIKit

//Import ARKit and SceneKit frameworks
import ARKit
import SceneKit
//Conform our ViewController to ARSCNViewDelegate protocol.
class ViewController: UIViewController, ARSCNViewDelegate {
    var nodes: [SphereNode] = []

    //Create a lazy sceneView variable to store ARSCNView instance
    lazy var sceneView: ARSCNView = {
        let view = ARSCNView(frame: CGRect.zero)
        view.delegate = self
        return view
    }()
    //Create a label to display status information.
    lazy var infoLabel: UILabel = {
        let label = UILabel(frame: CGRect.zero)
        label.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.title1)
        label.textAlignment = .center
        label.backgroundColor = .white
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //Add sceneView to our host view
        view.addSubview(sceneView)
        //Add the label to host view
        view.addSubview(infoLabel)
        //
        let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapRecognizer.numberOfTapsRequired = 1
        sceneView.addGestureRecognizer(tapRecognizer)
    }

    @objc func handleTap(sender: UITapGestureRecognizer) {
        //2
        let tapLocation = sender.location(in: sceneView)
        //3
        let hitTestResults = sceneView.hitTest(tapLocation, types: .featurePoint)
        if let result = hitTestResults.first {
            //4
            let position = SCNVector3.positionFrom(matrix: result.worldTransform)
            //5
            let sphere = SphereNode(position: position)
            //6
            sceneView.scene.rootNode.addChildNode(sphere)
            let lastNode = nodes.last
            nodes.append(sphere)
            if lastNode != nil {
                //7
                let distance = lastNode!.position.distance(to: sphere.position)
                infoLabel.text = String(format: "Distance: %.2f meters", distance)
            }
        }
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        //Resize sceneView
        sceneView.frame = view.bounds
        //Update the label position
        infoLabel.frame = CGRect(x: 0, y: 16, width: view.bounds.width, height: 64)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        //Start ARKit session
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    }

    func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
        //Implement protocol function to display status changes
        var status = "Loading..."
        switch camera.trackingState {
        case ARCamera.TrackingState.notAvailable:
            status = "Not available"
        case ARCamera.TrackingState.limited(_):
            status = "Analyzing..."
        case ARCamera.TrackingState.normal:
            status = "Ready"
        }
        infoLabel.text = status
    }

}

extension SCNVector3 {
    func distance(to destination: SCNVector3) -> CGFloat {
        let dx = destination.x - x
        let dy = destination.y - y
        let dz = destination.z - z
        return CGFloat(sqrt(dx*dx + dy*dy + dz*dz))
    }

    static func positionFrom(matrix: matrix_float4x4) -> SCNVector3 {
        let column = matrix.columns.3
        return SCNVector3(column.x, column.y, column.z)
    }
}

您缺少定义 SphereNode 的代码。

您可以用类似这样的内容替换该行:

let sphereGeometry = SCNSphere(radius: 0.1)
let sphere = SCNNode(geometry: sphereGeometry)
sphere.position = position

你的问题的答案很简单。您正在引用一个名为 SphereNode 的 SCNNode Subclass,但它并未包含在您的项目中。

快速查看问题中提供的源代码参考指向以下 GitHub Repository:AR Measure Demo

如果您查看源代码,它们是一个名为 SphereNode.swift:

的 class
//
//  SphereNode.swift
//  ArMeasureDemo
//
//  Created by Igor K on 8/17/17.
//  Copyright © 2017 Igor K. All rights reserved.
//
import SceneKit

class SphereNode: SCNNode {
    init(position: SCNVector3) {
        super.init()
        let sphereGeometry = SCNSphere(radius: 0.005)
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.red
        material.lightingModel = .physicallyBased
        sphereGeometry.materials = [material]
        self.geometry = sphereGeometry
        self.position = position
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

因此,如果您将当前文件制作成这样,错误就会消失:

import UIKit

class SphereNode: SCNNode {
    init(position: SCNVector3) {
        super.init()
        let sphereGeometry = SCNSphere(radius: 0.005)
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.red
        material.lightingModel = .physicallyBased
        sphereGeometry.materials = [material]
        self.geometry = sphereGeometry
        self.position = position
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

//Import ARKit and SceneKit frameworks
import ARKit
import SceneKit
//Conform our ViewController to ARSCNViewDelegate protocol.
class ViewController: UIViewController, ARSCNViewDelegate {
    var nodes: [SphereNode] = []

    //Create a lazy sceneView variable to store ARSCNView instance
    lazy var sceneView: ARSCNView = {
        let view = ARSCNView(frame: CGRect.zero)
        view.delegate = self
        return view
    }()
    //Create a label to display status information.
    lazy var infoLabel: UILabel = {
        let label = UILabel(frame: CGRect.zero)
        label.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.title1)
        label.textAlignment = .center
        label.backgroundColor = .white
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //Add sceneView to our host view
        view.addSubview(sceneView)
        //Add the label to host view
        view.addSubview(infoLabel)
        //
        let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapRecognizer.numberOfTapsRequired = 1
        sceneView.addGestureRecognizer(tapRecognizer)
    }

    @objc func handleTap(sender: UITapGestureRecognizer) {
        //2
        let tapLocation = sender.location(in: sceneView)
        //3
        let hitTestResults = sceneView.hitTest(tapLocation, types: .featurePoint)
        if let result = hitTestResults.first {
            //4
            let position = SCNVector3.positionFrom(matrix: result.worldTransform)
            //5
            let sphere = SphereNode(position: position)
            //6
            sceneView.scene.rootNode.addChildNode(sphere)
            let lastNode = nodes.last
            nodes.append(sphere)
            if lastNode != nil {
                //7
                let distance = lastNode!.position.distance(to: sphere.position)
                infoLabel.text = String(format: "Distance: %.2f meters", distance)
            }
        }
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        //Resize sceneView
        sceneView.frame = view.bounds
        //Update the label position
        infoLabel.frame = CGRect(x: 0, y: 16, width: view.bounds.width, height: 64)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        //Start ARKit session
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    }

    func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
        //Implement protocol function to display status changes
        var status = "Loading..."
        switch camera.trackingState {
        case ARCamera.TrackingState.notAvailable:
            status = "Not available"
        case ARCamera.TrackingState.limited(_):
            status = "Analyzing..."
        case ARCamera.TrackingState.normal:
            status = "Ready"
        }
        infoLabel.text = status
    }

}

extension SCNVector3 {
    func distance(to destination: SCNVector3) -> CGFloat {
        let dx = destination.x - x
        let dy = destination.y - y
        let dz = destination.z - z
        return CGFloat(sqrt(dx*dx + dy*dy + dz*dz))
    }

    static func positionFrom(matrix: matrix_float4x4) -> SCNVector3 {
        let column = matrix.columns.3
        return SCNVector3(column.x, column.y, column.z)
    }
}

希望对您有所帮助...