# ARKit多机画面同步解决方案,原理分析,技术讲解

ARKit局域网内如何实现多个手机AR画面同步

3BB791B7-27AA-4C67-874B-1853A88DA5E7.png

ARKit 规律探究

1.无论手机在什么角度和位置开启AR场景坐标系的Y轴总是和水平面垂直 2.标定手机是让手机表面平行方向一致,这个时候相当于将两个手机的照相机的坐标自身的坐标系是同一个坐标系,这个时候,将玩家1,放置物体的坐标(x1,y1,z1)先转换到相机坐标系中,转换后的坐标为(x2,y2,z2),之后在将这个坐标,转换至世界坐标系中,转换后的坐标为(x3,y3,z3) 3.完成上面转换后,只要在坐标x3,y3,z3处放置物体即可

```import SceneKit
import Foundation

class TARSceneConverter{
var Δθ: Float = 0.0
var Δx: Float = 0.0
var Δy: Float = 0.0
var Δz: Float = 0.0

init(referBeginRef1:SCNVector3, referEndRef1: SCNVector3,
referBeginRef2: SCNVector3,referEndRef2: SCNVector3,
collisionPosition1: SCNVector3,
collisionPosition2: SCNVector3) {
calculateΔθByBeginPosition(referBeginRef1, endPosition1: referEndRef1, beginPosition2: referBeginRef2, endPosition2: referEndRef2)
calaulteFactor(position1: collisionPosition1, position2: collisionPosition2)
}
init() {

}

// 计算xz面上向量的旋转角度
// θ = -1 标识
func     calculateRotationY(beginPosition:SCNVector3,endPosition:SCNVector3) -> Float{
var θ:Float = 0.0
let x = endPosition.x
let z = endPosition.z
if z > 0 && x > 0{
θ = atan(z/x)
}else if z > 0 && x < 0  {
θ = atan(z/x) + Float.pi
}else if z < 0 && x > 0{
θ = 2*Float.pi + atan(z/x)
}else if z < 0 && x < 0{
θ =  Float.pi + atan(z/x)
}else if x == 0 {
if z > 0 {
θ = 0
}else if z < 0 {
θ = Float.pi
}else if z == 0 {
θ = 0
}
}
return θ
}
private func calculateΔθByBeginPosition(_ beginPostion1: SCNVector3,
endPosition1: SCNVector3,
beginPosition2: SCNVector3,
endPosition2: SCNVector3){
self.Δθ = Float( calculateRotationY(beginPosition: beginPostion1, endPosition: endPosition1) - calculateRotationY(beginPosition: beginPosition2, endPosition: endPosition2))
}
// 计算需要的因子
private func calaulteFactor(position1:SCNVector3,position2:SCNVector3){
let θ2 = calculateRotationY(beginPosition: SCNVector3Zero, endPosition: position2)
let θ21 = θ2 + self.Δθ

let x1 = position1.x
let y1 = position1.y
let z1 = position1.z
let x2 = position2.x
let y2 = position2.y
let z2 = position2.z
let r2 = sqrt(pow(x2, 2)+pow(z2, 2))

let x21 = Float(cos(θ21)) * r2
let z21 = Float(sin(θ21)) * r2
let y21 = y2
self.Δx = x21 - x1
self.Δy = y21 - y1
self.Δz = z21 - z1
}

// 转换值从机场景坐标
func convertPositionToMachine(position:SCNVector3)->SCNVector3{
let x1 = position.x
let y1 = position.y
let z1 = position.z
let x2 = x1 + self.Δx
let y2 = y1 + self.Δy
let z2 = z1 + self.Δz
print("Δx:\(self.Δx)-Δy\(self.Δy)-Δz\(self.Δz)")
print("x2:\(x2)-y2:\(y2)-z2:\(z2)")
let θ2 = calculateRotationY(beginPosition: SCNVector3Zero, endPosition: SCNVector3Make(x2, y2, z2))
print("角度\(θ2)")
let r2 = sqrt(pow(x2, 2)+pow(z2, 2))
print(r2)
let θ21 =  θ2 - self.Δθ
let x21 = cos(θ21) * r2
let y21 = y2
let z21 = sin(θ21) * r2
return SCNVector3Make(x21, y21, z21)
}
// 先平移目标坐标系
func translatePositionToMachine(position:SCNVector3)->SCNVector3{
let x1 = position.x
let y1 = position.y
let z1 = position.z
let x2 = x1 + self.Δx
let y2 = y1 + self.Δy
let z2 = z1 + self.Δz
return SCNVector3Make(x2, y2, z2)
}
// 旋转至目标坐标系
func rotationByYToMachine(position:SCNVector3)->SCNVector3{
let x1 = position.x
let y1 = position.y
let z1 = position.z
let θ2 = calculateRotationY(beginPosition: SCNVector3Zero, endPosition: SCNVector3Make(x1, y1 ,z1))
print("角度\(θ2)")
let r2 = sqrt(pow(x1, 2)+pow(z1, 2))
print(r2)
let θ21 =  θ2 - self.Δθ
let x21 = cos(θ21) * r2
let y21 = y1
let z21 = sin(θ21) * r2
return SCNVector3Make(x21, y21, z21)
}

func getFactor()->(Float,Float,Float,Float){
return (self.Δx,self.Δy,self.Δz,self.Δθ)
}
}```

TRSceneConvert.switf

```import Foundation
import SceneKit
private let sceneManager = TARSceneManager()
class TARSceneManager{
var referBeginPosition1: SCNVector3!
var referEndPosition1: SCNVector3!
var referBeginPosition2: SCNVector3!
var referEndPosition2: SCNVector3!
var collisionPosition1: SCNVector3!
var collisionPosition2:SCNVector3!
var converter: TARSceneConverter!
class func share() -> TARSceneManager{
return sceneManager
}
// 开始执行标记
func handleMark(){
converter = TARSceneConverter(referBeginRef1: referBeginPosition1, referEndRef1: referEndPosition1, referBeginRef2: referBeginPosition2, referEndRef2: referEndPosition2, collisionPosition1:collisionPosition1, collisionPosition2: collisionPosition2)
}
// 转换坐标到下面的场景
func convertPositionToFollowScene(position:SCNVector3)->SCNVector3{
if converter != nil {
return converter.convertPositionToMachine(position: position)
}else{
fatalError("converter is nil")
}
}
}```

var referBeginPosition1: SCNVector3! // 主机,初始化时,放置在主机相机坐标系的一个点,在世界坐标系的位置 var referEndPosition1: SCNVector3! //主机,标定时 ,上面那个节点在世界坐标系的位置 var referBeginPosition2: SCNVector3! // 主机,初始化时,放置在主机相机坐标系的一个点,在世界坐标系的位置 var referEndPosition2: SCNVector3! //主机,标定时 ,上面那个节点在世界坐标系的位置 var collisionPosition1: SCNVector3! // 标定时,相机1的世界坐标位置 var collisionPosition2:SCNVector3! // 标定时,相机2的世界坐标位置

``` self.client.connectHost(host: "192.168.8.108", port: 10001, success: {
self.client.writeData(user, success: {
})
}) { (err) in
print(err!)
}```

208 篇文章30 人订阅

0 条评论

## 相关文章

### 英伟达开源数据增强和数据解码库，解决计算机视觉性能瓶颈

【新智元导读】在CVPR 2018大会上，英伟达开源了数据增强库DALI和数据解码库nvJPEG。

14840

89870

385140

84920

42860

48980

9530

35380

### 【学习】R语言中的情感分析与机器学习

#玩转大数据#利用机器学习可以很方便的做情感分析。本篇文章将介绍在R语言中如何利用机器学习方法来做情感分析。在R语言中，由Timothy P.Jurka开发的情...

38480

13310