【AR】拡張現実に文字を表示してみよう

AR
スポンサーリンク

最近めっちゃARにハマっています笑

本日は文字を描画するプログラムを書いていこうと思います。

興味があったら是非見ていってください。

今回作成するプログラム

作るプログラムはこれだ! 

とてもシンプルなアプリですw。

まず「拡張現実を表示するエリア」、「表示する文字を入力するテキストボックス」、「位置を変化させるボタン」、そして「文字を配置するボタン」が存在します。

テキストボックスに文字を入力して位置を調整し配置ボタンを押すと、指定した位置に文字が描画されるという仕掛けになっております。

プログラムの解説

ARの部分を重点的に解説できればと思います!

@IBOutlet weak var sceneView: ARSCNView!

まずは、ARSCNViewの変数を用意しております。

公式サイトに説明がある通り、ARSCNViewオブジェクトはSceneKitを使ってAR体験を表示できるようにするビューです。

公式サイトには以下のような説明がありました。

Secenkit

Create 3D games and add 3D content to apps using high-level scene descriptions. Easily add animations, physics simulation, particle effects, and realistic physically based rendering.

https://developer.apple.com/documentation/scenekit

高度な3Dゲームや3Dコンテンツを作りあげるフレームワークということですね。

このフレームワークを利用することによって、アニメーションや物理シミュレーションなどのレンダリングが簡単に実現できるみたいです。

    override func viewDidLoad() {
        super.viewDidLoad()
        //デリケートを設定する
        sceneView.delegate = self
        textField.delegate = self
        //デバッグモードを指定
        sceneView.debugOptions = [ARSCNDebugOptions.showWorldOrigin,ARSCNDebugOptions.showFeaturePoints]
        //シーンを作成
        let scene = SCNScene()
        sceneView.scene = scene
    }

4行目はおなじみのデリケートですね。詳細は他のサイトで調べていただければと思いますが、テックアカデミーの解説が一番分かりやすかったです。リンク載せておきます。

Swiftで書くデリゲート (delegate)の使い方【初心者向け】 | TechAcademyマガジン
プログラミング初心者向けにSwiftで書くdelegate(デリゲート)の使い方を解説しています。UIKitでよく利用されるデリゲートの使い方などを実際にコードを書きながら説明しているので、理解しやすいでしょう。

SceneViewではアンカーが追加された時や更新された時などにデリケート処理がはしります。

今回はデリケート処理を行っていないので、4行目は正直不要です。ただ拡張性を持たせるために記述しています。

5行目はデバックモードを指定しています。

showWorldOriginはARワールド座標系の位置と方向を示す軸を表示するための記述です。

showFeaturePointsはARKitがデバイスの位置を追跡するために使用するシーン分析の中間結果を示す点群を表示するための記述です。

黄色い粒々がいっぱい表示されます。これで物体を認識しているみたいです。

デバックモードはいろいろありますので、公式サイトの以下のURLを参考にしてください。

Apple Developer Documentation

9,10行目は、シーンです。

3Dコンテンツを表示するためには、ノードとシーンを作成する必要があります。

ノードを定義しても何も表示されません。あくまでコンテンツの位置や方向、スケールのみを管理しているものだからです。

このノードに後で出てくるジオメトリを紐づけることによって初めて3Dコンテンツが表示されます。

シーンはノードを階層構造で管理する役割を持っています。

   //テキストオブジェクト生成
    func createTextObject(x:Float,y:Float,z:Float,text:String) {
        //テキストオブジェクト(ジオメトリ)のインスタンスを生成
        let sampleText = SCNText(string: text, extrusionDepth: 0)
        //視覚的プロパティ定義するためにmaterialのインスタンスを生成
        let sampleMaterial = SCNMaterial()
        //色を定義(今回は黒を指定)
        sampleMaterial.diffuse.contents = UIColor.black
        //四角形オブジェクトに視覚的効果を付与
        sampleText.materials = [sampleMaterial]
        //ノードにsampleTextを追加
        let sampleNode = SCNNode(geometry: sampleText)
        //ノードの位置情報を定義
        sampleNode.position = SCNVector3(x,y,z)
        //ノードの大きさを指定
        sampleNode.scale = SCNVector3(0.2,0.2,0.2)
        //ノードにオブジェクトを追加
        sceneView.scene.rootNode.addChildNode(sampleNode)
    }

さて、上記のコードが今回の肝になる部分ですね。

ここでノードにジオメトリを関連付けています。

ジオメトリは実施に目に見える物体を作り出します。

ジオメトリはいくつか種類があります。

四角形や丸を作り出すものとかですね。

今回はそのうちの一つ文字を形成するためのSCNTextを使用しています。

そしてマテリアル(外観を決めるオブジェクト)を指定し、外観を整えた上でノートに関連づけています。

最後シーンにノードを紐づけて完成です。

プログラムの全体像

//
//  ViewController.swift
//  sampleAr4
//
//  Copyright © 2020 エンジニアの日記. All rights reserved.
//

import UIKit
import SceneKit
import ARKit
import CoreLocation

class ViewController: UIViewController, ARSCNViewDelegate, UITextFieldDelegate  {

    @IBOutlet weak var sceneView: ARSCNView!
    @IBOutlet weak var x: UILabel!
    @IBOutlet weak var y: UILabel!
    @IBOutlet weak var z: UILabel!
    
    @IBOutlet weak var ValueX: UIStepper!
    @IBOutlet weak var ValueY: UIStepper!
    @IBOutlet weak var ValueZ: UIStepper!
    
    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //デグレードを設定する
        sceneView.delegate = self
        textField.delegate = self
        //デバッグモードを指定
        sceneView.debugOptions = [ARSCNDebugOptions.showWorldOrigin,ARSCNDebugOptions.showFeaturePoints]
        //シーンを作成
        let scene = SCNScene()
        sceneView.scene = scene
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        sceneView.session.pause()
    }
    
    @IBAction func stepperX(_ sender: UIStepper) {
        x.text = String(format: "%.1f",sender.value)
    }

    @IBAction func stepperY(_ sender: UIStepper) {
        y.text = String(format: "%.1f",sender.value)
    }
    
    @IBAction func stepperZ(_ sender: UIStepper) {
        z.text = String(format: "%.1f",sender.value)
    }
    
    @IBAction func addObject(_ sender: Any) {
        //テキストオブジェクトを配置する
        createTextObject(x : Float(ValueX.value),y : Float(ValueY.value),z : Float(ValueZ.value),text : textField.text!)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        // キーボードを閉じる
        textField.resignFirstResponder()
        return true
    }
    
   //テキストオブジェクト生成
    func createTextObject(x:Float,y:Float,z:Float,text:String) {
        //テキストオブジェクトのインスタンスを生成
        let sampleText = SCNText(string: text, extrusionDepth: 0)
        //滑らかにする
        sampleText.flatness = 0.001
        //視覚的プロパティ定義するためにmaterialのインスタンスを生成
        let sampleMaterial = SCNMaterial()
        //色を定義(今回は黒を指定)
        sampleMaterial.diffuse.contents = UIColor.black
        //四角形オブジェクトに視覚的効果を付与
        sampleText.materials = [sampleMaterial]
        //ノードにsampleBok追加
        let sampleNode = SCNNode(geometry: sampleText)
        //ノードの位置情報を定義
        sampleNode.position = SCNVector3(x,y,z)
        //ノードの大きさを指定
        sampleNode.scale = SCNVector3(0.001,0.001,0.001)
        //ノードにオブジェクトを追加
        sceneView.scene.rootNode.addChildNode(sampleNode)
    }
}


AR
スポンサーリンク
エンジニアの日記

コメント