ARKit連載三之太空尺

太空尺.gif

太空尺原理非常簡單:通過ARKit捕捉真實世界的兩個點,然后計算出兩個點之間的距離。所以可以直接下載代碼查看,下面列出重要實現(xiàn)步驟及代碼。
1, 是否劃線-狀態(tài)控制

class ViewController
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if !isMeasuring {
            // 開始測量
            isMeasuring = true
            targetImageView.image = UIImage(named: "GreenTarget")
            
            vectorStart = SCNVector3()
            vectorEnd = SCNVector3()
        } else {
            // 測量結(jié)束
            isMeasuring = false
            
            if let line = currentLine {
                lines.append(line)
                currentLine = nil
                targetImageView.image = UIImage(named: "WhiteTarget")
            }
        }
    }

2, 因為我們要時刻掃描劃線,所以實現(xiàn)代理方法:func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval)

class ViewController
    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        DispatchQueue.main.async {
            scanWorld()
        }
    }

后邊所有步驟及代碼幾乎都在scanWorld方法內(nèi)為其服務(wù)

3, 這里捕捉點,就通過屏幕的中心點捕捉吧!

class ViewController.scanWorld()
        let point = view.center
        let results = sceneView.hitTest(point, types: [.featurePoint])
        guard let result = results.first else {
            return
        }
        let transform = result.worldTransform
        let worldPosition = SCNVector3Make(transform.columns.3.x, transform.columns.3.y, transform.columns.3.z)

4, 控制劃線狀態(tài)與劃線的邏輯:

  • 在剛開啟劃線狀態(tài)時,通過步驟3中掃描的點作為線的終點,如果起點都還沒有確定,那么該點還是線的起點。
  • 在確定起點時,創(chuàng)建Line對象
  • 在確定終點時,更新線。因為劃線狀態(tài)沒有被切換時,終點一直在變,也就是前面創(chuàng)建的展示線的節(jié)點一直在變
class ViewController.scanWorld()
        if isMeasuring {
            // 確定線的起點,創(chuàng)建線條
            if vectorStart == vectorZero {
                vectorStart = worldPosition
                currentLine = Line(sceneView: sceneView, startVector: vectorStart, unit: unit)
            }
            
            // 更新線條
            currentLine?.update(to: worldPosition)
            infoLabel.text = currentLine?.distance ?? "update line..."
        }

extension SCNVector3: Equatable {
    
    public static func == (lhs: SCNVector3, rhs: SCNVector3) -> Bool {
        return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z)
    }
}

5, 上邊代碼創(chuàng)建Line不是關(guān)鍵,而是Line的更新:currentLine?.update(to: worldPosition)

  • 此時worldPosition就表示currentLine的終點
  • 由于線的終點變化,所以需要移除掉之前的線節(jié)點
  • 通過起點與新的終點,創(chuàng)建并展示新的線節(jié)點
class Line:
    var distance: String? {
        let distanceX = startVector.x - endVector.x
        let distanceY = startVector.y - endVector.y
        let distanceZ = startVector.z - endVector.z
        let value = sqrt((distanceX * distanceX) + (distanceY * distanceY) + (distanceZ * distanceZ))
        
        return String(format:"%0.2f %@", value*unit.factor, unit.name)
    }

    func update(to vector: SCNVector3) {
        lineNode?.removeFromParentNode()
        
        endVector = vector
        
        lineNode = startVector.line(to: endVector, color: color)
        sceneView.scene.rootNode.addChildNode(lineNode!)
        
        // 文字節(jié)點
        text.string = distance // text是SCNText,是文字節(jié)點的幾何形
        textNode.position = SCNVector3((startVector.x + vector.x) / 2.0 , (startVector.y + vector.y) / 2.0 ,(startVector.z + vector.z) / 2.0 )
        
        endNode.position = vector
        if endNode.parent == nil {
            sceneView.scene.rootNode.addChildNode(endNode)
        }
    }

6, 通過兩點之間在3D場景劃線:startVector.line(to: endVector, color: color)

extension SCNVector3
    func line(to vector: SCNVector3, color: UIColor) -> SCNNode {
        let indices: [UInt32] = [0, 1]
        
        let source = SCNGeometrySource(vertices: [self, vector])
        let element = SCNGeometryElement(indices: indices, primitiveType: .line)
        
        let geometry = SCNGeometry(sources: [source], elements: [element])
        geometry.firstMaterial?.diffuse.contents = color
        
        let node = SCNNode(geometry: geometry)
        return node
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容