TEXTBOOK SECTION / AI LEARNING

3Dモデルを画面に表示する

Flutterアプリケーション開発概論の「3Dモデルと描画」より、3Dモデルを画面に表示するを解説。生成AI、AI活用、DX、業務改善を実践しながら学べるオンライン教材です。

83Dモデルと描画Flutter / iOS / Android / MacOS / Windows / 基礎から学ぶ / 開発 / アプリ開発

OVERVIEW

この節で学べること

概要を表示する
項目内容
教材名Flutterアプリケーション開発概論
3Dモデルと描画
3Dモデルを画面に表示する
カテゴリFlutter / iOS / Android / MacOS / Windows / 基礎から学ぶ / 開発 / アプリ開発
学習内容生成AI、AI活用、DX、業務改善を実践しながら理解するための教材です。

TABLE OF CONTENTS

目次

CONTENT

ここから

この章では、前章で定義したモデルURLを使い、画面内へ実際の3Dモデルを表示します。あわせて、指による回転と拡大・縮小を有効にします。

モデルの読み込み状態やエラー表示は、後の章で追加します。まずは、3Dビューアーを配置して操作できるところまで進めます。

8.1 3Dモデルのファイル形式を理解する

今回表示するモデルには、GLB形式を使用します。

GLBは、形状、材質、テクスチャなど、3Dモデルの表示に必要な情報を一つのファイルへまとめられる形式です。複数の関連ファイルを個別に管理する必要がないため、Webやモバイルアプリでの配信に向いています。

前章のModelSource.modelUrlには、インターネット上に公開されているGLBファイルのURLが設定されています。

static const String modelUrl =
    '<https://modelviewer.dev/shared-assets/models/Astronaut.glb>';

外部URLから読み込むため、動作確認時にはインターネット接続が必要です。

8.2 3D表示パッケージを読み込む

model_viewer_screen.dartへ、3Dモデル表示用パッケージを追加します。

import 'package:flutter_3d_controller/flutter_3d_controller.dart';

これにより、Flutter3DViewerFlutter3DControllerを利用できるようになります。

Flutter3DViewerは3Dモデルを表示するWidgetです。Flutter3DControllerは、表示後のカメラ位置やモデル操作を制御するために使用します。

8.3 StatefulWidgetへ変更する

これまでの画面は、変化する値を持たないStatelessWidgetでした。しかし、3Dビューアーを操作するコントローラーは、画面が再構築されても同じものを保持する必要があります。

そのため、ModelViewerScreenStatefulWidgetへ変更します。

class ModelViewerScreen extends StatefulWidget {
  const ModelViewerScreen({super.key});

  /// 画面の状態オブジェクトを生成します。
  ///
  /// 入力: なし
  /// 出力: [ModelViewerScreen]の状態
  @override
  State<ModelViewerScreen> createState() => _ModelViewerScreenState();
}

StatefulWidget自身は画面の設定を持ち、変化する値や処理は対応するStateクラスへ記述します。

8.4 3Dコントローラーを作成する

Stateクラスの中へ、コントローラーを定義します。

class _ModelViewerScreenState extends State<ModelViewerScreen> {
  final Flutter3DController _controller = Flutter3DController();
}

finalは、変数へ別のコントローラーを再代入しないことを表します。ただし、コントローラー内部の状態やカメラ操作は変化します。

変数名の先頭にある_は、このファイルの外から直接使用しないprivateな値であることを示します。

8.5 3Dビューアーを配置する

前章で仮表示していた文字を、Flutter3DViewerへ置き換えます。

Flutter3DViewer(
  controller: _controller,
  src: ModelSource.modelUrl,
  enableTouch: true,
  activeGestureInterceptor: true,
  progressBarColor: const Color(0xFF151515),
)

controllerには、先ほど作成したコントローラーを渡します。

srcには、表示する3DモデルのURLを指定します。URLを画面へ直接書かず、ModelSource.modelUrlを参照することで、設定値の管理場所を一つに保てます。

progressBarColorは、パッケージ側で表示される読み込み進捗の色です。

8.6 タッチ操作を有効にする

enableTouchtrueにすると、画面上の3Dモデルを指で操作できます。

enableTouch: true,

基本操作は次のとおりです。

  • 1本指でなぞる:モデルを回転する
  • 2本指で広げる:モデルを拡大する
  • 2本指で狭める:モデルを縮小する activeGestureInterceptorを有効にすると、3Dビューアー上でのジェスチャーをビューアー側が処理します。
activeGestureInterceptor: true,

3D表示領域の外側では、通常どおりFlutterの画面操作が行われます。

8.7 この章で完成するコード

model_viewer_screen.dartを次の内容へ更新します。

import 'package:flutter/material.dart';
import 'package:flutter_3d_controller/flutter_3d_controller.dart';
import 'package:flutter_3d_model_viewer/config/model_source.dart';

/// リモートURLの3Dモデルを表示し、指操作を受け付ける画面です。
class ModelViewerScreen extends StatefulWidget {
  const ModelViewerScreen({super.key});

  /// 画面の状態オブジェクトを生成します。
  ///
  /// 入力: なし
  /// 出力: [ModelViewerScreen]の状態
  @override
  State<ModelViewerScreen> createState() => _ModelViewerScreenState();
}

class _ModelViewerScreenState extends State<ModelViewerScreen> {
  final Flutter3DController _controller = Flutter3DController();

  /// 画面全体のUIを構築します。
  ///
  /// 入力: [BuildContext]
  /// 出力: タッチ操作可能な3Dモデルを含む[Widget]
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.fromLTRB(16, 14, 16, 16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '3D MODEL',
                    style: TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.w700,
                      letterSpacing: 1.8,
                    ),
                  ),
                  SizedBox(height: 3),
                  Text(
                    ModelSource.displayName,
                    style: TextStyle(
                      fontSize: 24,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 14),
              Expanded(
                child: ColoredBox(
                  color: const Color(0xFFE8E8E5),
                  child: Flutter3DViewer(
                    controller: _controller,
                    src: ModelSource.modelUrl,
                    enableTouch: true,
                    activeGestureInterceptor: true,
                    progressBarColor: const Color(0xFF151515),
                  ),
                ),
              ),
              const SizedBox(height: 10),
              const Center(
                child: Text(
                  ModelSource.attribution,
                  style: TextStyle(
                    color: Color(0xFF777777),
                    fontSize: 11,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

アプリを起動すると、読み込み後に宇宙飛行士のモデルが表示されます。モデルを指でなぞり、向きが変わることを確認してください。さらに、2本指で拡大・縮小できることも確認します。

モデルが表示されない場合は、インターネット接続、パッケージの取得状況、モデルURLの入力内容を確認します。

8.8 この章の到達目標

この章の終了時点で、次の内容を確認します。

  • GLB形式の概要を説明できる
  • 外部パッケージをDartファイルへimportできる
  • StatefulWidgetStateの関係を説明できる
  • Flutter3DControllerを保持できる
  • URLを指定して3Dモデルを表示できる
  • 1本指でモデルを回転できる
  • 2本指でモデルを拡大・縮小できる

次章では、3D表示領域の角を丸くし、操作案内を重ねて、ビューアーの見た目を整えます。

https://app.notion.com/p/3D-UI-332b4ab5d1368107bf01c3a2a4a68f2c?v=2c7b4ab5d136802d9a64000c46ee24e8&source=copy_link

FAQ

よくある質問

3Dモデルを画面に表示するは医療関係者向けだけの内容ですか。
医療分野の例が含まれる場合もありますが、医療関係者だけに限定した内容ではありません。生成AI、AI活用、DX、業務改善、プロトタイプ開発など、一般的なAI学習の事例として読める内容です。
AI初心者でも読めますか。
はい。AIをこれから学ぶ方、数学が苦手な方、仕事でAIを使いたい方にも読み進めやすいように、教材の章と節の流れに沿って整理しています。
サムネイル画像は必ず表示されますか。
はい。教材にcoverUrlが設定されている場合はその画像を表示し、未設定の場合は代替サムネイル画像を表示します。
Flutterアプリケーション開発概論のほかの章も読めますか。
はい。教材トップから章立てを確認でき、前後の節へもページ下部のナビゲーションから移動できます。