ARKit__2_尺子项目

一、ARkit尺子项目学到了什么?

先看效果,如下图:

  • 1.SCNVector3本质就是一个三维坐标
  • 2.画线的步骤就是:拿到2个坐标 --> 选择“线”这个“几何” --> 渲染--> 最后生成节点。这个过程待会会详细的代码解释。
  • 3.坐标之间的转换,世界坐标、摄像头。这个和SLAM里面的很类似。
  • 4.SCNText,一个很特殊的“几何”,如图中的8.52cm就是用SCNText表示的,当然最后都会放到节点里面去。
  • 5.对节点的使用更加的清晰,每个点、每根线、以及描述的text都会被添加到节点,然后ARSCNView的scene.rootNode.addChildNode(node)

二、下面开始具体的讲解整个实现的逻辑和流程。 

 先解释下:图中的 白色"+"是始终位于屏幕的正中间的,整个项目都是以这个点为瞄准点。

开始第一步:

extension ARSCNView {
    //拿到三维坐标
    func worldVector(for position:CGPoint) ->SCNVector3?{
        let results = self.hitTest(position, types: [.featurePoint])
        guard let result = results.first else {
            return nil
        }
        // 获取点的坐标,类型是matrix_float4x4 ,调这个方法就可以拿到相机的镜头
        return SCNVector3.positionTransform(result.worldTransform)
    }
}
//  拿到镜头的坐标
    static func positionTransform(_ transform: matrix_float4x4) -> SCNVector3{

        return SCNVector3Make(transform.columns.3.x, transform.columns.3.y, transform.columns.3.z)

    }
  •  1.点击手机屏幕,然后获取到一个CGPoint,
  •  2.通过 self.hitTest(position, types: [.featurePoint]).first 就拿到一个 为matrix_float4x4类型的坐标。
  •  3.通过positionTransform方法得到镜头的坐标。
实话里面到底是如何实现的,我也很想知道。我通过之前对SLAM的学习,大概知道,里面的矩阵变换的过程。对于iOS开发者,知道需要转换即可,具体的深究留到自己对AR的掌握到了一定程度的时候会比较好。

第二步:画线

//画线的方法
    func drawLine( vector: SCNVector3, color:UIColor) -> SCNNode {
        let indices: [UInt32] = [0,1] // 指数    
//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 }
  •  1.数据源:两个坐标
  • 2.选择几何模型--线
  • 3.生成节点 

第三步:什么时候绘制了?

实在ARSCNViewDelegate中的渲染方法里面进行绘制。具体代码:

 {
    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {     
        DispatchQueue.main.async {
            self.scanWorld()
        }
    }
 //扫描外部真实世界,开始测量
    func scanWorld() {
        //我们以中间点为开始点,也就是那个十字标图片指的点为开始的点。
        guard let worldPosition = sceneView.worldVector(for: view.center) else {
            return
        }
             vectorStart = worldPosition
              currentLine = Line.init(sceneView: self.sceneView, startVector: vectorStart, unit: self.unit)
            //设置结束的节点
            vectorEnd = worldPosition
            currentLine?.update(to: vectorEnd)
            infoLabel.text = currentLine?.distance(to: vectorEnd) ?? "是同一个点"    
        }
    }

进行扫描真实的世界,在scanWorld()方法里面调用绘制的方法进行绘制。

三、总结一下思路

  • 选择开始的点
  • 然后开始绘制并计算长度
  • 再次点击屏幕获取终点--结束。

实现的难点:想到坐标的转换、然后绘制的时机、对节点的使用的掌握。

项目代码,我后续会传到GitHub,后面在一起加。 

但行好事,莫问前程。
原文地址:https://www.cnblogs.com/yuhui-snail/p/8515335.html