LoginSignup
8
4

More than 5 years have passed since last update.

ARKitで位置情報を共有するためのモデルをCodableで作成する

Last updated at Posted at 2018-12-05

昨日のARKitで空間共有して端末間通信する方法22選で、端末間でデータを送受信するのに使うのはCodableがベストだと書きました。

今日は具体的にそのCodableの使い方を紹介したいと思います。

Codableとは

Swift4から使えるJSONのエンコードとデコードが簡単にできるSwift標準ライブラリです。めちゃ簡単に使えます。

以下はJSONパーサーのパフォーマンス比較表です。DecodableのJSONをデコードするのにかかる時間は比較的短いことが分かります。これで標準なんだから使わない手はないですね。(Codableの型はDecodable & Encodable)

json
1

基本Entity

それではARKitの位置共有で使うための基本データをCodableに準拠させてどう作っていくのか紹介します。

Vector3Entity

位置座標x, y, zやオイラーアングルはSCNVector3で表されるのでそれに対応するEntityを作ります。

struct Vector3Entity: Codable {
    let x: Float
    let y: Float
    let z: Float
}

Vector4Entity

4*4行列の要素や、rotationのSCNVector4に対応するために、対応するEntityを作ります。

struct Vector4Entity: Codable {
    let x: Float
    let y: Float
    let z: Float
    let w: Float
}

実践的なEntity

PlayerEntity

例えばデバイス間で各自のデバイス位置を共有したいとき、以下のようなPlayerEntityを作って座標(position)と向き(eulerAngles)を共有します。

struct PlayerEntity: Codable {
    let position: Vector3Entity
    let eulerAngles: Vector3Entity
}

TransformEntity

4*4行列を送受信するためのEntityを作ります。このtransformはデバイス間で座標合わせをするときに必要なことが多いです。(参考: ARKitで空間共有して端末間通信する方法22選)

struct TransformEntity: Codable {
    let column0: Vector4Entity
    let column1: Vector4Entity
    let column2: Vector4Entity
    let column3: Vector4Entity
}

ARKitにおける位置情報共有の例

送信する側

例えばARSCNViewDelegateのrenderer(:updateAtTimeは毎フレームごとに呼ばれるので、ここでカメラの位置を取得して毎フレームごとに相手に送信することができます。(毎フレームごとに送るべきかは置いといて)

// MARK: - <#ARSCNViewDelegate#>
extension CameraViewController: ARSCNViewDelegate {
    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        guard let camera = sceneView.pointOfView else {
            return
        }
        // TODO: PlayerEntityのイニシャライザ作っとく
        let entity = PlayerEntity(position: camera.position,
                                  eulerAngles: camera.eulerAngles)
        let data: Data = try! JSONEncoder().encode(entity)

        // TODO: dataを送る

    }

受信する側

repositoryというクラスに相手からデータを受け取ったときに発火するonEventというクラスを用意したとして、以下のようにそのobjectをparseすることができます。

repository.onEvent { object in
    guard let data = object as? Data else {
        return
    }

    do {
        let decoder: JSONDecoder = JSONDecoder()
        let entity: PlayerEntity = try decoder.decode(PlayerEntity.self, from: data)
        // これを使って相手のデバイスを空間上で再現する
        let position = entity.position
        let eulerAngles = entity.eulerAngles
    } catch {

    }
}

まとめ

以上のようなパターンでデバイス間で位置情報を共有することができます。位置情報アプリを作りたい方の参考になれば幸いです。

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4