from: http://blog.csdn.net/Oboe_b/article/details/78009568

简介:

上篇回顾:

在ARKit(光线与动画处理),使用Objective-C在一个正常的项目开启的一个AR项目,实现一个solar system的demo,实现太阳的公转与自转,包括之间的关系,各个节点谁是谁的子节点,设置地月节点,然后添加黄道,把动画添加在黄道节点,处理地球与太阳的关系,当然在动画的处理之后,添加光照度与更全面的渲染

本篇介绍:

拿到三维坐标点,拿到相机的实时位置(两个分类),计算距离:

//        A(x1,y1,z1),B(x2,y2,z2),则A,B之间的距离为

//        d=√[(x1-x2)^2+(y1-y2)^2+(z1-z2)^2]

之后我们来记录起始点,此处写了一个Line类,在其中实现其中主要的角色以及实现的主要场景,创建SCNGeometrySource物件,创建SCNGeometryElement把创建的顶点连起来,用line的方式来画一条线(GPU操作可以减少CPU负担),然后获取到实时测试的距离,在我们的现实世界中将你所在的初始原点位置,和你结束的位置的距离来测量出来

正文:

效果展示:

使用示例:

实现思路:

1.搭建基本环境,开启全局追踪

2.拿到三维坐标点

3.拿到相机实时位置

4.初始化场景与角色

5.实时跟踪,处理事件,完善

步骤:

1.搭建基本框架

session.run方法开启全局追踪<提问:全局追踪失效?>

搭建基本框架基本控件属性

@IBOutlet weak var sceneV: ARSCNView!

@IBOutlet weak var InfoL: UILabel!//这个label的命名大家不要介意,手残了

@IBOutlet weak var targetIM: UIImageView!

var session = ARSession()

var configuration = ARWorldTrackingConfiguration()

2.代理,全局的追踪状态

func session(_ session: ARSession, didFailWithError error: Error) {

InfoL.text = "错误"

}

func sessionWasInterrupted(_ session: ARSession) {

InfoL.text = "中断~"

}

func sessionInterruptionEnded(_ session: ARSession) {

InfoL.text = "结束"

}

4.BXARSCNView+Extension类来拿三维坐标

func worldVector(for position:CGPoint) ->SCNVector3?{

//result

let results = hitTest(position, types: [.featurePoint])

guard let result = results.first else {

return nil

}

//-->返回相机的位置

return SCNVector3.positionTranform(result.worldTransform)

}

此处设置结果(let results)的时候,使用了types,这里相机与物件之间的距离,用来搜索ARSession检测到的锚点,真实世界中的对象不是view中的SceneKit里面的内容,假设找内容的话用(option)

5.BXSCNVector3 + Extension将坐标的x,y,z回传,计算距离,画线

回传xyz

static func positionTranform(_ tranform:matrix_float4x4) -> SCNVector3{

//将坐标的x,y,z轴回传出去

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

}

计算距离

func distance(for vector:SCNVector3) -> Float {

let distanceX = self.x-vector.x//现在的位置减去出发的位置

let distanceY = self.y-vector.y

let distanceZ = self.z-vector.z

return sqrt((distanceX * distanceX)+(distanceY * distanceY)+(distanceZ * distanceZ))

}

画线

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 geomtry = SCNGeometry(sources: [source], elements: [element])//几何

geomtry.firstMaterial?.diffuse.contents = color//渲染颜色

let node = SCNNode(geometry: geomtry)//返回一个节点

return node

}

6.初始化主要角色与场景

定义

var color = UIColor.red,

var startNode : SCNNode

var endNode : SCNNode

var textNode : SCNNode

var text : SCNText

var lineNode : SCNNode?

let sceneView: ARSCNView

let startVector: SCNVector3

初始化:创建节点-添加子节点

self.sceneView = sceneView

self.startVector = startVector

self.unit = unit

let dot = SCNSphere(radius: 0.5)

dot.firstMaterial?.diffuse.contents = color

dot.firstMaterial?.lightingModel = .constant//光照,表面看起来都是一样的光亮,不会产生阴影

dot.firstMaterial?.isDoubleSided = true//两面都很亮

startNode = SCNNode(geometry: dot)

startNode.scale = SCNVector3(1/500.0,1/500.0,1/500.0)

startNode.position = startVector

sceneView.scene.rootNode.addChildNode(startNode)

endNode = SCNNode(geometry: dot)//这里只需要先创建出来,稍后添加

endNode.scale = SCNVector3(1/500.0,1/500.0,1/500.0)//这里也有坑

text = SCNText(string: "", extrusionDepth: 0.1)

text.font = .systemFont(ofSize: 5)

text.firstMaterial?.diffuse.contents = color

text.firstMaterial?.lightingModel = .constant

text.firstMaterial?.isDoubleSided = true

text.alignmentMode = kCAAlignmentCenter//位置

text.truncationMode = kCATruncationMiddle//........

let textWrapperNode = SCNNode(geometry: text)

textWrapperNode.eulerAngles = SCNVector3Make(0, .pi, 0) // 数字对着自己

textWrapperNode.scale = SCNVector3(1/500.0,1/500.0,1/500.0)

textNode = SCNNode()

textNode.addChildNode(textWrapperNode)//添加到包装节点上

let constraint = SCNLookAtConstraint(target: sceneView.pointOfView)//来一个约数

constraint.isGimbalLockEnabled = true

textNode.constraints = [constraint]

sceneView.scene.rootNode.addChildNode(textNode)

SCNVector3(A representation of a three-component vector.

SceneKit uses three-component vectors for a variety of purposes, such as

describing node or vertex positions, surface normals, and scale or translation

transforms. The different vector components should be interpreted based on the

context in which the vector is being used.

Important

In macOS, the x, y, and z fields in this structure are CGFloat values. In iOS,

tvOS, and watchOS, these fields are Float values.)此处我们来描述节点或者是顶点的位置时候注意要用CGFloat-->否则会出现意想不到的情况(消失不见????)

7.处理更新文字

lineNode?.removeFromParentNode()//移除掉所有线

lineNode = startVector.line(to: vector, color: color)

sceneView.scene.rootNode.addChildNode(lineNode!)

//更新文字a

text.string = distance(to: vector)

//文字位置

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)

}

8.点击屏幕的时候,进入测试状态,开始画线,记录开始点和结束点

当然我们追踪显示时间需要在主线程中

DispatchQueue.main.async {}

优化:

1.全局追踪的高级用法:在生命周期view将要显示的时候移除所有锚点,并且重新开启追中效率会大大提高,当生命周期view将要消失的时候,我们所追踪的位置并不一定还留在原来的位置,所以说我们移掉所有锚点之后在次来一次追踪,效率是不是会提高很多-->resetTracking  removeExistingAnchors

2.Equatable协议防止重复:

public static func == (lhs: SCNVector3, rhs: SCNVector3) -> Bool {

//当左边的与右边的相等

return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z)

}

3.移除remove

line.remove(),当点击Reset的时候进行清除

总结:

本文主要难点,在于三维坐标点的获取,相机的实时位置,距离的计算以及画线

最后为大家献上本文代码地址,我在git中的demo中也写了注释,大家可以仔细看一下demo,欢迎大家下载,star

C博客地址

ARKit-带你走进全新的世界(三:追踪/距离感应/AR尺子)相关推荐

  1. ARKit-带你走进全新的世界(四:平面检测)

    简介: 上篇回顾: 上篇文章中我们简单写了一个AR尺子测量距离的demo,计算距离的公式--> A(x1,y1,z1),B(x2,y2,z2),则A,B之间的距离为d=√[(x1-x2)^2+( ...

  2. 【密码学】一万字带您走进密码学的世界(下)

    引文 密码学是研究编制密码和破译密码的技术科学.研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学:应用于破译密码以获取通信情报的,称为破译学,总称密码学. 在<一万字带您走进密 ...

  3. 带你走进rsync的世界

    导读 Rsync(remote synchronize)是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件,也可以使用 Rsync 同步本地硬盘中的不同目录.rsync共有3种使用方 ...

  4. 【密码学】一万字带您走进密码学的世界(上)

    引文 密码学是研究编制密码和破译密码的技术科学.研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学:应用于破译密码以获取通信情报的,称为破译学,总称密码学. 为了使读者对密码学有一个整 ...

  5. 冷链冷库|果蔬保鲜储藏冷链冷库 海格里斯带你走进果蔬冷库世界

    冷链行业涵盖冷冻加工,冷藏贮藏,冷链运输和冷链销售全过程.冷链行业的主要设施包括冷库或低温物流中心.生鲜食品加工中心(包括中央厨房).冷藏运输车.超市陈列柜等.而冷链行业景气度的提升则会带动冷库,冷藏 ...

  6. 轻松带你走进shiro的世界

    2019独角兽企业重金招聘Python工程师标准>>> 1.10分钟带你轻松入门shiro Shiro是apache旗下的一款轻量级的Java安全框架,它可以提供如下服务: Auth ...

  7. 【Java】带你走进Debug的世界

    关于Debug和本文 Debug,意为"调试",是程序员必备技能之一. Debug开始用的时候还是很不习惯的,需要适应,本文面向新手介绍Debug相关内容. Debug的三种手段 ...

  8. vLive带你走进虚拟直播世界

    虚拟直播是什么? 虚拟直播是基于5G+实时渲染技术,在绿幕环境下拍摄画面,通过实时抠像.渲染与合成,再推流到直播平台的一种直播技术.尽管这种技术早已被影视工业所采用,但在全民化进程中却是困难重重,面临 ...

  9. ARKit-带你走进全新的世界(二:动画与光线处理)

    简介: 上篇回顾: ARKit初探篇(链接)中写到怎样开启一个AR项目,包括开发环境,建立项目,及基础代码实现,在git的demo添加了手势的处理,简单实现点击球体实现图片轮换 本篇介绍: 将虚拟世界 ...

最新文章

  1. 阮一峰网络日志 第41期 2019年01月25日
  2. scikit-learn 逻辑回归类库使用小结
  3. php delete和truncate,TRUNCATE 删除表,无法回退。默认选择为整个表的内容,所以不能加条件。...
  4. Linux的启动流程简析(以Debian为例)
  5. 【Python】处理FutureWarning: Pass threshold=18 as keyword args.
  6. [转载] python学习-基础教程、深度学习
  7. javascript面向对象技术基础
  8. 南阳理工ACM 2括号配对问题
  9. Python空间分析| 03 利用Python进行地理加权回归(GWR)
  10. C语言函数库之字符串比较函数(string.h)
  11. Stata:图示交互效应-调节效应
  12. WS4665D-8/TR单通道负载开关WILLSEM封装DFN2x2-8L
  13. 三个数据分析的技巧:找趋势、看分布、做细化
  14. 如何破解Aspose.word带水印问题
  15. crontab python不生效_crontab 中 python 脚本执行失败的解决方法
  16. 【190319】VC++ C/S结构视频聊天软件源码源代码
  17. markdown常用的语法(乌迪尔)
  18. waves服务器系统盘,在Midas调音台上使用Waves插件
  19. 认识因特网络(小学计算机课件),小学信息技术- 认识因特网 课件.ppt
  20. MatePad11基于SpaceDesk的屏幕扩展优化

热门文章

  1. NEO改进协议提案6(NEP-6)
  2. Wish关联后,应该怎么办?
  3. 全球与中国高光谱成像设备市场深度研究分析报告
  4. 用OpenCV实现Photoshop算法(九): 高反差保留
  5. 久坐电脑者养生从养肝开始
  6. 【Web开发】粒子插件vue-particles的使用
  7. 涂鸦APP可以添加多少路的设备
  8. 电脑投屏到vr手机_如何将智能手机的VR体验投射到电视上
  9. EMV密钥管理体系与商业银行卡
  10. 从两边往中间流水灯c语言程序,单片机控制LED流水灯从中间向两边.doc