Flutter GPU初期プレビュー版で3Dモデルを回転・拡大縮小できるビューアを作る
はじめに
こんにちは!
Altive株式会社 Flutterアプリエンジニアの中村です。
Flutter3.24から使えるようになったFlutter GPUで3Dモデルぐるぐる回したり拡大縮小できるビューアを実装してみました。
3Dモデルは MaterialsVariantsShoe をお借りしています👟
主に参考にした記事はGetting started with Flutter GPUです🙏🏻
こんな感じになります
プロジェクトの設定
メインチャンネルに切り替える
Flutter GPU
を利用した3DレンダリングライブラリのFlutter Scene
を使って3Dモデルを表示させていきますが、Flutter GPU
とFlutter Scene
のどちらもプレビュー段階にあるためFlutterのメインチャンネルに切り替えてから使用する必要があります。
flutter channel main
flutter upgrade
ネイティブアセット機能を有効にする
Flutter Scene
は実験的なネイティブアセット機能に依存しているため、有効にする必要があります。
flutter config --enable-native-assets
モデルをインポートする
今回は冒頭で紹介したMaterialsVariantsShoe
を使います。
curl -O https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/DamagedHelmet/glTF-Binary/MaterialsVariantsShoe.glb
Flutter Scene
内で使用できる形式に変換するため、flutter_scene_importer
を追加します。
flutter pub add flutter_scene_importer
このパッケージを使用すると、コマンドでモデルの形式を変換できるようになります。
input
とoutput
のパスは任意の場所に修正してください。
dart --enable-experiment=native-assets \
run flutter_scene_importer:import \
--input "path/to/my/source_model.glb" \
--output "path/to/my/imported_model.model"
出力したモデルをアプリで使用できるように、pubspec.yaml
のasset
にパスを追加します。
flutter:
assets:
- build/models/
3Dモデルをアプリに表示する
参考記事だと時間の経過に伴ってモデルをぐるぐる回す例が紹介されていますが、今回はGestureDetector
を使ってユーザーの操作で回転・拡大縮小できるビューアを作ってみました。
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_scene/scene.dart';
import 'package:vector_math/vector_math.dart';
class FlutterGpuPage extends StatefulWidget {
const FlutterGpuPage({super.key});
FlutterGpuPageState createState() => FlutterGpuPageState();
}
class FlutterGpuPageState extends State<FlutterGpuPage> {
double hAngle = 1;
double vAngle = 1;
double radius = 1;
final initResources = Scene.initializeStaticResources();
final scene = Scene();
Vector3 calculateCameraPosition() {
final y = radius * sin(vAngle);
final x = radius * cos(vAngle) * sin(hAngle);
final z = radius * cos(vAngle) * cos(hAngle);
return Vector3(x, y, z);
}
void initState() {
super.initState();
unawaited(
// アセットからモデルを読み込む
Node.fromAsset('assets/Shoe.model').then(scene.add),
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter GPU Demo'),
),
body: FutureBuilder(
// リソースの初期化処理
future: initResources,
builder: (context, snapShot) {
if (snapShot.connectionState != ConnectionState.done) {
return const Center(
child: CircularProgressIndicator.adaptive(),
);
}
return Center(
child: SizedBox(
height: 500,
width: MediaQuery.sizeOf(context).width,
child: GestureDetector(
child: CustomPaint(
painter: ScenePainter(
scene: scene,
camera: PerspectiveCamera(
position: calculateCameraPosition(),
),
),
),
onScaleUpdate: (details) {
setState(() {
radius = (radius / details.scale).clamp(0.5, 1.0);
final dx = details.focalPointDelta.dx / 100;
final dy = details.focalPointDelta.dy / 100;
hAngle += dx;
vAngle += dy;
vAngle = vAngle.clamp(-pi / 2, pi / 2);
});
},
),
),
);
},
),
);
}
}
class ScenePainter extends CustomPainter {
ScenePainter({required this.scene, required this.camera});
Scene scene;
Camera camera;
void paint(Canvas canvas, Size size) {
scene.render(camera, canvas, viewport: Offset.zero & size);
}
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
おわりに
この記事ではFlutter GPU
とFlutter Scene
を使って、3Dモデルを操作できるビューアの作成方法を紹介しました。
Flutterで3Dレンダリングがこんなにも簡単にできるのかと感動しました!
現状ではまだプレビュー段階ですが、今後正式リリースされれば3Dコンテンツの開発がさらに身近になりそうです。
自分でも3Dモデルを作れるようになって、いつかアプリで動かしてみたいです☺️
Discussion