3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

可茂IT塾Advent Calendar 2023

Day 16

【Flutter】 arkitを使ってARに3dモデルを表示する方法

Last updated at Posted at 2023-12-18

この記事は、【 可茂IT塾 Advent Calendar 2023 】の16日目の記事です。

はじめに

arkit_pluginライブラリを使ってARにglTF・glb形式の3dオブジェクトを表示する方法を解説します。

開発環境

  • Flutter 3.14.0
  • Dart 3.2.0
  • arkit_plugin 1.0.7
  • collection 1.18.0
  • vector_math 2.1.4

実装手順

1. ライブラリのインストール

flutterでARを表示するには、arkit_plugin ( https://pub.dev/packages/arkit_plugin ) というパッケージを使用します。
また、本記事ではarkit_pluginに加えてcollection、vector_mathの2つのライブラリも使用します。こちらもインストールしてください。

使用ライブラリ一覧
arkit_plugin ( https://pub.dev/packages/arkit_plugin )
collection ( https://pub.dev/packages/collection )
vector_math ( https://pub.dev/packages/vector_math )

2. Info.plistの更新

ARKitはデバイスのカメラを使用するのでNSCameraUsageDescriptionを指定する必要があります。
以下のコードを ios/Runner/Info.plist に追記してください。

<key>NSCameraUsageDescription</key>
<string>Describe why your app needs AR here.</string>

3. ライブラリのインポート

使用するライブラリをインポートします

import 'package:arkit_plugin/arkit_plugin.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

4. ARを表示するクラスの実装

class _MyArAppState extends State<MyArApp> {
  late ARKitController arkitController;

  //初期化
  @override
  void dispose() {
    arkitController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Christmas Decorations')),
        body: ARKitSceneView(
          showFeaturePoints: true, //特徴点を表示(オブジェクトを置ける場所)
          enableTapRecognizer: true, //タップ認識を有効にする
          planeDetection:
              ARPlaneDetection.horizontalAndVertical, //垂直方向と平面方向の両方で平面を検出
          onARKitViewCreated:
              onARKitViewCreated, //ARKitViewが作成されたときに呼ばれるコールバック関数
        ),
      );

  //ARKitViewが作成されたときの処理
  void onARKitViewCreated(ARKitController arkitController) {
    this.arkitController = arkitController;
    //特徴点を取得
    this.arkitController.onARTap = (ar) {
      final point = ar.firstWhereOrNull(
        (o) => o.type == ARKitHitTestResultType.featurePoint,
      );
      //特徴点が取得できたら
      if (point != null) {
        _onARTapHandler(point);
      }
    };
  }

  void _onARTapHandler(ARKitTestResult point) {
    //タップされた座標を取得
    final position = vector.Vector3(
      point.worldTransform.getColumn(3).x,
      point.worldTransform.getColumn(3).y,
      point.worldTransform.getColumn(3).z,
    );
    final node = _getNodeFromFlutterAsset(position); //ARオブジェクトを作成
    arkitController.add(node); //ARオブジェクトを追加
  }

  ARKitGltfNode _getNodeFromFlutterAsset(vector.Vector3 position) =>
      ARKitGltfNode(
        //ARオブジェクトの設定
        assetType: AssetType.flutterAsset, //アセットタイプ
        url: 'assets/Tree.glb', //① モデルデータ
        scale: vector.Vector3(0.1, 0.1, 0.1), //拡大率
        position: position, //位置
      );
}

4. モデルデータ(url)の設定方法について

ARKitGltfNode _getNodeFromFlutterAsset(vector.Vector3 position) =>
      ARKitGltfNode(
        //アセットタイプ
        url: 'assets/Tree.glb', //① モデルデータ
        ---省略---
      );

urlの部分で3DモデルのURLを指定します。本投稿時ではglb・glTF形式のみ対応していました(usdzも使えない)。
また、上記のコードのようにあらかじめダウンロードした3Dモデルデータを用いる場合は、pubspec.yamlに以下のように追記する必要があります。

assets:
    - assets/Tree.glb

下記のように3dモデルのurlを貼り付ける方法でも実装できます。

ARKitGltfNode _getNodeFromFlutterAsset(vector.Vector3 position) =>
      ARKitGltfNode(
        //アセットタイプ
        url: 'https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Box/glTF-Binary/Box.glb',
        ---省略---
      );

実行結果

クリスマスが近いこともあって無事、クリスマスツリーを飾ることができました!
※キラキラしているところ(特徴点)にのみオブジェクトを配置できます。

コード全文

import 'package:arkit_plugin/arkit_plugin.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Christmas Decorations',
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: const MyArApp(),
    );
  }
}

class MyArApp extends StatefulWidget {
  const MyArApp({Key? key}) : super(key: key);
  @override
  State<MyArApp> createState() => _MyArAppState();
}

class _MyArAppState extends State<MyArApp> {
  late ARKitController arkitController;

  //初期化
  @override
  void dispose() {
    arkitController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Christmas Decorations')),
        body: ARKitSceneView(
          showFeaturePoints: true, //特徴点を表示(オブジェクトを置ける場所)
          enableTapRecognizer: true, //タップ認識を有効にする
          planeDetection:
              ARPlaneDetection.horizontalAndVertical, //垂直方向と平面方向の両方で平面を検出
          onARKitViewCreated:
              onARKitViewCreated, //ARKitViewが作成されたときに呼ばれるコールバック関数
        ),
      );

  //ARKitViewが作成されたときの処理
  void onARKitViewCreated(ARKitController arkitController) {
    this.arkitController = arkitController;
    //特徴点を取得
    this.arkitController.onARTap = (ar) {
      final point = ar.firstWhereOrNull(
        (o) => o.type == ARKitHitTestResultType.featurePoint,
      );
      //特徴点が取得できたら
      if (point != null) {
        _onARTapHandler(point);
      }
    };
  }

  void _onARTapHandler(ARKitTestResult point) {
    //タップされた座標を取得
    final position = vector.Vector3(
      point.worldTransform.getColumn(3).x,
      point.worldTransform.getColumn(3).y,
      point.worldTransform.getColumn(3).z,
    );
    final node = _getNodeFromFlutterAsset(position); //ARオブジェクトを作成
    arkitController.add(node); //ARオブジェクトを追加
  }

  ARKitGltfNode _getNodeFromFlutterAsset(vector.Vector3 position) =>
      ARKitGltfNode(
        //ARオブジェクトの設定
        assetType: AssetType.flutterAsset, //アセットタイプ
        url: 'assets/Tree.glb', //モデルデータ
        scale: vector.Vector3(0.1, 0.1, 0.1), //拡大率
        position: position, //位置
      );
}

最後に

arkit_pluginを使うと、簡単に3DモデルをARに表示することができました。ARってテンション上がりますよね。arkit_pluginでは3Dモデルの色を変えたり、動かしたり、スクショを撮れるようにしたり、他にもワクワクする機能がたくさんあります。是非色々と試して、自分だけのAR(拡張現実)を作ってみてはいかがでしょうか?

参考

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?