Kudan AR SDK で AR iOS アプリを作ってみよう〜マーカー上に 3D モデルを表示

こんにちは。エクセルソフトの田淵です。

弊社取り扱いの Kudan AR SDK のエントリーです。

SDK のダウンロードは こちら からお申込みください。SDK を使った開発と、個人開発者のリリースは無料でご利用いただけます。企業の方は有料になりますので、@ytabuchi までご連絡ください。

前回の iOS のエントリー ではマーカー上で画像を表示しました。

今回は 3D モデルを表示します。基本的には Android と同じ流れで、画面を作り、コードを追記していきます。

現時点でのサンプルコードは ytabuchi の Github にアップしてあります。この後もコミット追加していくのでスナップショットです。

Asset の準備

最初に 3D モデルのモデルファイルとテクスチャーファイルをプロジェクトに読み込みます。

プロジェクトのルートを右クリックして、「New Group」をクリックし、「Assets」フォルダを作成します。

ダウンロードした assets.zip を展開し、ben.jetben.armodel に拡張子を変更します。
ben.jet のままでも動作します。逆に、Android では .jet の拡張子の必要があるようです。)

拡張子が見えていない場合は macOS Sierra: ファイル名拡張子を表示する/隠す を参考に見えるようにしておくと何かと便利です。

ben.armodelbigBenTexture.png を作成した Assets フォルダにドラッグ&ドロップします。

コピーするかを聞かれますので、「add to targets」にチェックが入っていることを確認し、プロジェクトにコピーします。

Type が、ben.armodel は「Default – Data」、bigBenTexture.png は「Default – PNG Image」になっていて、「Target Membership」にチェックが入っていることを確認してください。

これでコードから参照できる状態になりました。

UI の設定

Storyboard にボタンを配置します。

詳細は割愛しますが、Constraints などを設定し、Option キーを押しながら ViewController.swift を開き、OutletAction を設定しておきましょう。

@IBOutlet weak var clearButton: UIButton!
@IBOutlet weak var imageButton: UIButton!
@IBOutlet weak var modelButton: UIButton!

@IBAction func clearButton_TouchUpInside(_ sender: Any) {
}

@IBAction func imageButton_TouchUpInside(_ sender: Any) {
}

@IBAction func modelButton_TouchUpInside(_ sender: Any) {
}

コード(ViewController.swift)の編集

setupContent の内容を分解

最初に複数のメソッドからアクセスされるクラス変数 var imageTrackable:ARImageTrackable?Action の下、setupContent の上に定義します。

setupImageTrackable を用意して ImageTrackable にマーカーを追加するコードを移動します。

func setupImageTrackable() {
    // ARImageTrackable オブジェクトのインスタンス化と初期化
    imageTrackable = ARImageTrackable.init(image: UIImage(named: "lego.jpg"), name: "lego")
    
    // image tracker manager のインスタンスを取得して初期化
    let imageTrackerManager = ARImageTrackerManager.getInstance()
    imageTrackerManager?.initialise()
    
    // ARImageTrackable を image tracker manager に追加
    imageTrackerManager?.addTrackable(imageTrackable)
}

次に addImageNode を用意して、画像のオブジェクトを追加するコードを移動します。

func addImageNode() {
    // ImageNode を表示させたい画像で初期化
    // PNG の場合は拡張子は不要です。
    let imageNode = ARImageNode(image: UIImage(named: "cow"))
    
    // ARImageTrackable に imageNode を追加
    imageTrackable?.world.addChild(imageNode)
    
    // マーカー画像のサイズに合わせるように、それぞれの幅から拡大率を計算
    let scaleRatio = Float(imageTrackable!.width)/Float(imageNode!.texture.width)
    
    // 拡大率を ImageNode に適用
    imageNode?.scale(byUniform: scaleRatio)
    
    imageNode?.visible = false
}

その下に clearButton の TouchUpInside のアクションで呼ばれる、全てのノードを非表示にする clearAllNodes メソッドを用意して、以下のコードを追加します。

func clearAllNodes() {
    let nodes = imageTrackable?.world.children
    nodes?.forEach({ (node) in
        node.visible = false
    })
}

メソッドが用意できたので、ボタンのアクションに追加しましょう。以下のコードを Action に追加します。

@IBAction func clearButton_TouchUpInside(_ sender: Any) {
    clearAllNodes()
}

@IBAction func imageButton_TouchUpInside(_ sender: Any) {
    clearAllNodes()
    imageTrackable?.world.children[0].visible = true
}

この時点で動かしてみましょう。

https://platform.twitter.com/widgets.js

こんな感じです。良い感じですね!

3D モデルの処理を追加

ViewController.swift に戻り、clearAllNodes メソッドの前に、addModelNode メソッドを追加します。

func addModelNode() {
    // モデルのインポート
    let modelImporter = ARModelImporter(bundled: "ben.armodel")
    let modelNode = modelImporter?.getNode()
    
    // モデルの ARMeshNode にアンビエントライトを適用
    if let meshNodes = modelNode?.meshNodes {
        for case let meshNode as ARMeshNode in meshNodes {
            let material = meshNode.material as? ARLightMaterial
            material?.ambient.value = ARVector3(valuesX: 0.8, y: 0.8, z: 0.8)
        }
    }
    
    // 向きと拡大率を指定
    modelNode?.rotate(byDegrees: 90, axisX: 1, y: 0, z: 0)
    modelNode?.scale(byUniform: 0.25)
    
    // ARImageTrackable に modelNode を追加
    imageTrackable?.world.addChild(modelNode)
    
    modelNode?.visible = false
}

ARModelNode クラスのメッシュオブジェクトが格納されている meshNodes は [Any]? 型なのでアンラップして ARMeshNode のオブジェクトの material に割り当てています。

Android ではモデルファイルとテクスチャーファイルを指定していましたが、このコードでは、ARLightMaterial を使用していルため、モデルファイルに含まれる(?)テクスチャーのファイル名を自動的に参照してくれるようです。そのため、コード内では bigBenTexture.png を参照していません。

現時点で私が Material についてあまり知識を持っていないのでまだよく分かっていませんが、理解できたらこのエントリーも更新したいと思います。

最後にボタンの TouchUpInside イベントにコードを追加しましょう。

@IBAction func modelButton_TouchUpInside(_ sender: Any) {
    clearAllNodes()
    imageTrackable?.world.children[1].visible = true
}

最終的に ViewController.swift は以下のようになっているはずです。

import UIKit
import KudanAR

class ViewController: ARCameraViewController {

    @IBOutlet weak var clearButton: UIButton!
    @IBOutlet weak var imageButton: UIButton!
    @IBOutlet weak var modelButton: UIButton!
    
    @IBAction func clearButton_TouchUpInside(_ sender: Any) {
        clearAllNodes()
    }
    
    @IBAction func imageButton_TouchUpInside(_ sender: Any) {
        clearAllNodes()
        imageTrackable?.world.children[0].visible = true
    }
    
    @IBAction func modelButton_TouchUpInside(_ sender: Any) {
        clearAllNodes()
        imageTrackable?.world.children[1].visible = true
    }
    
    var imageTrackable:ARImageTrackable?
    
    override func setupContent() {
        
        setupImageTrackable()
        
        addImageNode()
        addModelNode()
    }
    
    func setupImageTrackable() {
        // ARImageTrackable オブジェクトのインスタンス化と初期化
        imageTrackable = ARImageTrackable.init(image: UIImage(named: "lego.jpg"), name: "lego")
        
        // image tracker manager のインスタンスを取得して初期化
        let imageTrackerManager = ARImageTrackerManager.getInstance()
        imageTrackerManager?.initialise()
        
        // ARImageTrackable を image tracker manager に追加
        imageTrackerManager?.addTrackable(imageTrackable)
    }
    
    func addImageNode() {
        // ImageNode を表示させたい画像で初期化
        // PNG の場合は拡張子は不要です。
        let imageNode = ARImageNode(image: UIImage(named: "cow"))
        
        // マーカー画像のサイズに合わせるように、それぞれの幅から拡大率を計算
        let scaleRatio = Float(imageTrackable!.width)/Float(imageNode!.texture.width)
        // 拡大率を ImageNode に適用
        imageNode?.scale(byUniform: scaleRatio)

        // ARImageTrackable に imageNode を追加
        imageTrackable?.world.addChild(imageNode)

        imageNode?.visible = false
    }
    
    func addModelNode() {
        // モデルのインポート
        let modelImporter = ARModelImporter(bundled: "ben.armodel")
        let modelNode = modelImporter?.getNode()
        
        // モデルの ARMeshNode にアンビエントライトを適用
        if let meshNodes = modelNode?.meshNodes {
            for case let meshNode as ARMeshNode in meshNodes {
                let material = meshNode.material as? ARLightMaterial
                material?.ambient.value = ARVector3(valuesX: 0.8, y: 0.8, z: 0.8)
            }
        }
 
        // 向きと拡大率を指定
        modelNode?.rotate(byDegrees: 90, axisX: 1, y: 0, z: 0)
        modelNode?.scale(byUniform: 0.25)
        
        // ARImageTrackable に modelNode を追加
        imageTrackable?.world.addChild(modelNode)
        
        modelNode?.visible = false
    }
    
    func clearAllNodes() {
        let nodes = imageTrackable?.world.children
        nodes?.forEach({ (node) in
            node.visible = false
        })
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

「3D Model」ボタンをクリックして、以下のようにマーカー上に時計台が表示されれば成功です。

この後は

次は動画を表示してみましょう。

Kudan AR SDK エントリー一覧

Kudan AR SDK チュートリアル記事まとめ | エクセルソフト ブログ

をご覧ください。

以上です。

タイトルとURLをコピーしました