ちょっと話題の記事

[iOS 11][ARKit] 近所の駐車場で、大型ディスプレイでビデオを見る!

2017.09.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

うちの近所の駐車場には、縦3m、横5mの大型ディスプレイは、ありません・・・

そこで、ARKitで、その気になれるサンプルアプリを作成して見ました。

これは、ARKitでシーン上に1つのキューブを表示して、そのテクスチャーに動画を貼ったものです。

今回は、このようなアプリの作成方法について紹介させて頂きます。

2 SKVideoNode

SKVideoNodeは、SpriteKitで使用するノードの一つであり、名前からも想像できるとおり、ビデオの再生ができます。
Documentation > SpriteKit > SKVideoNode

残念ながら、SKVideoNodeは、SpriteKit(2D)のシーン(SKScene)にしか追加できませんが、SceneKit(3D)のノードの表面を表現するSCNMaterialには、テクスチャーのようにSKSceneを適用することができます。

従って、AVPlayer -> SKVideoNode(2D) -> SKScene(2D) -> SCNMaterial(3D)という順に適用すれば、SceneKit(3D)のノードのテクスチャーとして動画を使用できることになります。

3 動画テクスチャーとして適用したキューブ

先の適用順でSCNNodeを生成するコードは、下記のようになります。

func createVideoNode(size:CGFloat, videoUrl: URL) -> SCNNode {
    // AVPlayerを生成する
    let avPlayer = AVPlayer(url: videoUrl)

    // SKSceneを生成する
    let skScene = SKScene(size: CGSize(width: 1000, height: 1000)) // あまりサイズが小さいと、ビデオの解像度が落ちる

    // AVPlayerからSKVideoNodeの生成する
    let skNode = SKVideoNode(avPlayer: avPlayer)
    // シーンと同じサイズとし、中央に配置する
    skNode.position = CGPoint(x: skScene.size.width / 2.0, y: skScene.size.height / 2.0)
    skNode.size = skScene.size
    skNode.yScale = -1.0 // 座標系を上下逆にする
    skNode.play() // 再生開始

    // SKSceneに、SKVideoNodeを追加する
    skScene.addChild(skNode)

    // SCNBoxノードを生成して、マテリアルにSKSeceを適用する
    let node = SCNNode()
    node.geometry = SCNBox(width: size, height: size, length: size, chamferRadius: 0)
    let material = SCNMaterial()
    material.diffuse.contents = skScene
    node.geometry?.materials = [material]
    node.scale = SCNVector3(1.7, 1, 1) // サイズは横長
    return node
}

そして、このノードを生成して、シーンに追加する要領です。

// ビデオのURL
let videoUrl = Bundle.main.url(forResource: "video", withExtension: "mp4")!
// ビデオ動画をテクスチャーとして適用した縦3mのキューブの生成
let videoNode = createVideoNode(size: 3.0, videoUrl: videoUrl)
// 位置は、カメラの前方5m
videoNode.position = SCNVector3(0, 0, -5.0)
// シーンに追加する
sceneView.scene.rootNode.addChildNode(videoNode)

4 動画のループ再生

動画をエンドレスに再生したい場合、AVPlayerの機能でループ再生するだけです。

//ループ再生
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.none;
NotificationCenter.default.addObserver(self,
                                        selector: #selector(ViewController.didPlayToEnd),
                                        name: NSNotification.Name("AVPlayerItemDidPlayToEndTimeNotification"),
                                        object: avPlayer.currentItem)

再生が終了した時点で、最初までシークする

@objc func didPlayToEnd(notification: NSNotification) {
    let item: AVPlayerItem = notification.object as! AVPlayerItem
    item.seek(to: kCMTimeZero, completionHandler: nil)
}

5 最後に

動画がテクスチャーとして利用できると、また、色々楽しそうなものが作れそうです。

ほんと、ARKitは凄いと思います。

コードは、下記に置きました。参考になれば幸いです。
github [GitHub] https://github.com/furuya02/ARKitVideoSample

※動画は、ATTRIBUTION LICENSE 3.0 で公開されている、Mikah氏のものを利用させて頂きました。 http://mazwai.com/#/grid/videos/14

6 参考リンク


Introducing ARKit
Apple Developer > Documentation > ARKit
WWDC2017 Session 602 Introducing ARKit: Augmented Reality for iOS
ARKit by Example — Part 3: Adding geometry and physics fun
[iOS 11] はじめてのARKit #WWDC2017
[iOS 11][ARKit] 距離の計測について #WWDC2017
[iOS 11][ARKit] 平面の検出について #WWDC2017
[iOS 11][ARKit] 物理衝突を実装して、キューブを落として見る #WWDC2017
[iOS 11][ARKit] 空間に3Dテキストを表示してみる #WWDC2017
[iOS 11] ARKitでソファー設置からあの子の身長測定まで色々やってみた