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,后面在一起加。
但行好事,莫问前程。