この記事は、【 可茂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(拡張現実)を作ってみてはいかがでしょうか?
参考