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

本节学习任务

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

需求描述

一个用户打开AR应用,在房间中放置一个物体,然后其他用户加入游戏去找这个物体

游戏规则:只有玩家靠近这个物体1m的范围内才能发现这个物体

技术难点:

用户进入AR游戏时,手机的位置和角度不可能一直,所以就造成的物体不在同一个地方被发现

解决方案1:

就是上述所说的,让两个手机在同一个位置,朝向同一个方向同时启动手机,由于进入AR场景坐标系需要移动一下手机原始坐标系才能被准确的定位,所以就造成了很大的误差

解决方案2

不同手机在任何位置,都可以启动AR场景,然后当一个玩家藏好物体后,将自己的手机坐标系和其它用户的手机坐标系进行同步转换即可完成坐标值的统一

下面先看一张原理图

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

操作分为两步

第一步 启动AR(无论在什么位置和角度都可以)
第二步 转换坐标 (将玩家1藏物体的坐标,转换的到其它玩家坐标系上,现实中的同一个位置)

ARKit 规律探究

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

底层深入分析

由于所有玩家的坐标系的y轴都是和水平面垂直的,所以我们看做坐标系的位置相对标定点的位置,是有沿着y轴旋转了一个角度,然后平移一个值所得,只要计算出两个坐标系之间相对旋转了多少度,平移了多少增量,只要将物体坐标,也按照这个规律,旋转+平移,就可以计算物体在其他玩家坐标系中的位置

先看一下底层算法实现

下面这个类主要作用是求出,偏移量和旋转角度Δθ,Δx,Δy,Δz

核心类 TARSceneConverter

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的世界坐标位置

这个算法有点复杂,其实有更好的算法,十句左右代码就可以搞定,下一篇我们演示一下,本节就先到这里,代码会发送群里(530957835),查看ToyAR,注意准备两台6S以上手机,让两个手机连上同一个局域网,注意修改在TGameRoom文件的主机ip地址,改成你手机主机的ip地址

 self.client.connectHost(host: "192.168.8.108", port: 10001, success: {
       self.client.writeData(user, success: {
        })
    }) { (err) in
        print(err!)
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • AR从其技术手段和表现形式上,可以明确分为大约两类:一是Vision based AR,即基于计算机视觉的AR,二...
    困卡阅读 11,988评论 0 7
  • 人机交互方式发展太快了,它与我们的生物反应及处理过程同步,例如眼球转动、思维过程、动觉、文化偏好等,所以最近想收集...
    徐薇薇阅读 3,412评论 0 9
  • 小时候,父母种地,有时我也跟着去。山区的地都是陡峭的,不比平原。 路边有时从上面地里溜下来好多杂七杂八的东西,泥土...
    秭归橙子和水果阅读 831评论 4 4
  • 已过三重熏风 厮渐去, 草色青腻, 急雨不期。 错弹琵琶错羌笛! 时已九五炙寒 两厢嫉, 星月微稀, 斑影不离。 ...
    ZHANGY张阳阅读 421评论 0 0
  • 很多人明明很努力的想成为自己想成为的那个人,但到最后,却发现还是那个自己,到底怎么做,才可以?其实,你缺少的可能是...
    研木君1994阅读 476评论 0 1