Meshy AIで生成したglb形式の3DモデルをReactとThree.jsで制御!複数アニメーションを管理する方法

Meshy AIで生成したglb形式の3DモデルをReactとThree.jsで制御!複数アニメーションを管理する方法
  • URLをコピーしました!

3Dモデルのアニメーション制御に興味はありませんか?最近では、AIを活用した3Dモデル生成ツールが増えており、その中でも Meshy AI は、手軽にクオリティの高い3Dモデルを作成できるツールとして注目を集めています。

しかし、生成した3Dモデルを実際のアプリケーションで活用するには、特定のライブラリやツールを使いこなす必要があります。本記事では、ReactThree.js を使用して、Meshy AIで生成した「glb形式の3Dモデル」に複数のアニメーションを適用し、ブラウザ上で動かす方法を解説します。

📺 Meshyを確認する:こちらのリンクから公式ページで確認できます。

今回の内容は、PRO版(月3000円程度)が必須になります。(アニメーションはPRO版のみ)

TypeScript x React Three Fiberのレッスンや作品は、今後もどんどん作成していきます!
YouTubeで告知致しますので、ぜひYouTubeのチャンネル登録をして通知をお待ちください!

📺 YouTubeを見る:こちらのリンクから視聴できます。

TypeScript x React Three Fiber

React Three Fiberで何ができるのか知りたい方は、下記を参考にしてみてください!
簡単にできる作品を用意しております!

目次

3Dモデル表示のデモ

以下の動画で、完成形のデモを見ることができます。

📺 YouTubeでデモを見る:こちらのリンクから視聴できます。

さらに、このプロジェクトのソースコードはGitHubに公開しています。
ぜひコードをダウンロードして試してみてください!

💾 GitHubリポジトリ:こちらのリンクでソースコードをチェック!

「見てみたけどどうやって作るの?」と思った方、安心してください!
この記事では、この3Dモデルを表示する方法をステップバイステップで解説していきます。

必要な技術と主要ライブラリ

このプロジェクトでは、以下の技術とライブラリを使用しています。それぞれの役割を簡単に説明します。

  • React
    • フロントエンド開発のためのライブラリ
    • コンポーネントベースの設計でUIを効率的に構築できます
  • Three.js
    • 3DグラフィックスをWeb上で描画するためのライブラリ
    • WebGLの複雑な処理を簡単に扱えるようにしてくれます
  • React Three Fiber
    • ReactでThree.jsを扱うためのラッパーライブラリ
    • Reactの開発スタイルでThree.jsの強力な機能を利用できます
  • React Thee Drei
    • React Three Fiberの拡張ライブラリ
    • React Three Fiberの拡張ライブラリ
  • Meshy
    • AIを活用して高品質な3Dモデルを簡単に生成できるサービス

環境準備

このセクションでは、プロジェクトの初期設定を行います。npxコマンドでReactアプリを作成し、必要なライブラリをインストールしてフォルダ構成を整えます。

Reactアプリの作成

まず、npxコマンドを使用してReactアプリを作成します。

npx create-react-app meshy-3d-model-animathion --template typescript
  • meshy-3d-model-animathion はプロジェクトの名前です
  • --template typescript を指定することで、TypeScript対応のテンプレートを使用します

必要なライブラリのインストール

React Three Fiberやその他のライブラリをインストールします。

cd meshy-3d-model-animathion
npm install three @react-three/fiber @react-three/drei
  • three: Three.js本体
  • @react-three/fiber: ReactでThree.jsを使うためのラッパー
  • @react-three/drei: カメラコントロールやテキスト描画など、便利なヘルパー

フォルダ構成の見直しと不要ファイルの削除

初期状態から以下のようにフォルダを整理・追加します。
基本的には初期値だったりしますが、わからないファイルなどは、GitHubを見てみてください。

meshy-3d-model-animation/
├── node_modules/
├── public/
│   └── models/                      // 3Dモデルと関連ファイル
│       └── uncle_glb/              // 3Dモデルフォルダ
│           ├── Animation_Gangnam_Groove_withSkin.glb      // ダンスアニメーション付GLBファイル
│           ├── Animation_Pod_Baby_Groove_withSkin.glb     // ダンスアニメーション付GLBファイル
│           └── Animation_Superlove_Pop_Dance_withSkin.glb // ダンスアニメーション付GLBファイル
├── src/
│   ├── components/                 // 必要なら共通コンポーネントを格納
│   ├── pages/                      // ページ単位で管理するコンポーネント
│   │   ├── ThreeDDancingUncle/     // ページ単位フォルダ
│   │   │   └── ThreeDDancingUncle.tsx  // 3Dアニメーションページ
│   │   └── index.ts                // ページをエクスポートするインデックスファイル
│   ├── App.tsx                     // アプリのエントリーポイント
│   ├── index.tsx                   // Reactのレンダリング処理
│   ├── App.css                     // グローバルスタイル
│   ├── index.css                   // グローバルCSS
├── package.json                    // プロジェクト設定
├── tsconfig.json                   // TypeScriptの設定
└── README.md                       // プロジェクト概要

今回手を加えるファイルは、下記となります。

  • App.tsx: アプリのエントリーポイント
  • pages>index.ts:ページをエクスポートするインデックスファイル
  • pages/ThreeDDancingUncle: 今回作成対象のフォルダ
    • ThreeDDancingUncle.tsx: メインページのコンポーネント。

Meshyで3Dモデルの生成

今回、3Dモデルは、MeshyというAI自動生成サービスを利用します。
リンクは、下記になりますので、参考にしてみてください。

毎月200クレジット分は、無料で利用可能です。

📺 Meshyを確認する:こちらのリンクから公式ページで確認できます。

今回の内容は、PRO版(月3000円程度)が必須になります。(アニメーションはPRO版のみ)

テキスト生成モデルで3Dモデルを生成

今回は、テキストでモデルを生成します。
「新モデル」を選択してください。

おじさんにダンスをさせたかったので、「腕を広げたリアルな中年刑事の全身」としました。
この後関節とかを設定するので、なるべく腕は身体から離れていた方がいいです。

今回は左上を使ってみることにします。
選択して、テクスチャ&リメッシュで確認するを選択しましょう。

これで、選択したモデルと同じようなモデルが生成されます。

次に、アニメーションをつけるため、アニメ―ト>リギングを選択します。

今回は、人間なのでヒューマノイドを選択しましょう。

次の画面は、特に変更は不要かなと思いますが、私は身長を少しいじりました。

ここをうまく設定すると、アニメーションが綺麗になります。
関節を設定できたら、確認をしましょう。

これでアニメーションが付いている3Dモデルが生成されます。
デフォルトで歩くアニメーションが設定されています。

アニメーションの追加

今回は、ダンスアニメーションを複数追加します。

追加するボタンからお好きなダンスを複数追加してください。

歩くと走るはデフォルトで入っていますが、それ以外にダンスが3つ入っていることが確認できます。

GLB形式でダウンロード

3Dモデルの作成とアニメーションの追加ができたら、glbでダウンロードします。
この時、すべてのアニメーションにチェックを入れてください。

そうすると、下記のようにアニメーション毎にglbファイルが出力されます。
glbファイルは3Dモデルとアニメーションがセットになっていますので、モデルファイル存在しません。

glbファイルは、public配下に格納するようにしてください。
今回は、下記に格納しています。

meshy-3d-model-animation/
├── node_modules/
└── public/
    └── models/                      // 3Dモデルと関連ファイル
        └── uncle_glb/              // 3Dモデルフォルダ
            ├── Animation_Gangnam_Groove_withSkin.glb      // ダンスアニメーション付GLBファイル
            ├── Animation_Pod_Baby_Groove_withSkin.glb     // ダンスアニメーション付GLBファイル
            └── Animation_Superlove_Pop_Dance_withSkin.glb // ダンスアニメーション付GLBファイル

各ステップ毎にソースコードの詳細解説

以下のセクションでは、下記の5つのPARTを順番に詳しく解説していきます。

PART
PART
必要なモジュールのインポート
  • ReactとThree.jsの基本モジュールをインポート。
  • GLTFLoaderEXRLoader をインポートして、モデルやHDRI背景をロード可能に。
  • OrbitControls を使用して、シーン内でモデルを自由に回転・ズーム。
PART
定数の定義
  • モデルやアニメーションに関連するデータを 定数化
  • 以下の内容を定義:
    • アニメーションファイルのリスト: 複数のアニメーションファイルの名前とパスをリスト形式で保持。
    • カメラの初期設定: モデルの全体を見渡せるようにカメラの位置を定義。
    • ライト設定: 環境光、方向光、ポイントライトの強度や位置を設定。
    • HDRI背景のパス: 背景用のHDRI画像ファイルを指定。
PART
背景の設定
  • EXRLoader を使用してHDRI画像をロード
  • ロードしたHDRIを以下のように適用
    • scene.background: シーン全体の背景にHDRI画像を設定。
    • scene.environment: モデルの反射やライティングにHDRIを使用。
PART
モデルとアニメーション
  • GLTFLoader を使用してモデルを読み込み
    • 初期アニメーション(DEFAULT_ANIMATION_FILE)をロード
    • 読み込んだモデルをスケール、回転、位置を調整してシーンに配置
  • AnimationMixer を利用してアニメーションを管理
    • 読み込んだモデルにアニメーションを適用
    • 現在再生中のアニメーションを Reactの状態(useState で管理し、ユーザー操作で切り替え可能に
  • useFrame を活用してフレームごとにアニメーションを更新
PART
メインコンポーネント
  • Reactを利用して、全体のアプリケーションを構成
  • Canvas内で以下の要素を描画
    • 背景(Background コンポーネント)
    • モデルとアニメーション(Model コンポーネント)
    • ライト(環境光、方向光、ポイントライト)
  • アニメーションの切り替えボタンを配置
    • ボタンを押すと、指定のアニメーションファイルに切り替わる

全体ソースを確認

以下は、この記事で作成するMeshy AIで生成したglb形式の3DモデルをReactとThree.jsで制御の完成版ソースコードです。すべてのコードをまとめていますので、動作のイメージをつかみやすいと思います。

これ以外のソースを見たい方は、GitHubで確認してください。

💾 GitHubリポジトリ:こちらのリンクでソースコードをチェック!

import './App.css';
import { ThreeDDancingUncle } from './pages';

function App() {
  return (
    <div className="App">
      <ThreeDDancingUncle />
    </div>
  );
}

export default App;
import ThreeDDancingUncle from "./ThreeDDancingUncle/ThreeDDancingUncle";

export {ThreeDDancingUncle}
// ================================
// PART 1: 必要なモジュールのインポート
// ================================
import React, { useState, useEffect } from "react";
import { Canvas, useFrame, useThree } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
import * as THREE from "three";

// ================================
// PART 2: 定数の定義
// ================================
// アニメーションファイルのリスト
// 各アニメーションの名前とパスを格納
const ANIMATION_FILES = [
    { name: "Pod Baby Groove", path: "/models/uncle_glb/Animation_Pod_Baby_Groove_withSkin.glb" },
    { name: "Gangnam Groove", path: "/models/uncle_glb/Animation_Gangnam_Groove_withSkin.glb" },
    { name: "Pop Dance", path: "/models/uncle_glb/Animation_Superlove_Pop_Dance_withSkin.glb" },
];

// モデルファイルのパス
const DEFAULT_ANIMATION_FILE = ANIMATION_FILES[0].path;

// HDRI画像のパス (背景用)
const HDRI_FILE = "/hdri/cobblestone_street_night_4k.exr";

// 初期カメラ位置 (x, y, z)
const INITIAL_CAMERA_POSITION = new THREE.Vector3(10, 4, 10);

// モデルのスケール倍率
const MODEL_SCALE = 4;

// モデルの初期回転角度 (y軸回り、ラジアン単位)
const MODEL_ROTATION_Y = -1;

// モデルの初期位置 (x, y, z)
const MODEL_POSITION = new THREE.Vector3(0, -2, 0);

// ライトの設定
// 環境光、方向光、ポイントライトの位置と強度を定義
const LIGHT_SETTINGS = {
    ambient: { intensity: 0.5 }, // 環境光の強度
    directional: { position: new THREE.Vector3(10, 20, 10), intensity: 1.5 }, // 方向光の位置と強度
    point: { position: new THREE.Vector3(0, 10, 0), intensity: 1.5 }, // ポイントライトの位置と強度
};

// ================================
// PART 3: 背景の設定
// ================================
// シーンの背景をHDRI画像で設定
const Background: React.FC = () => {
    const { gl, scene } = useThree();

    useEffect(() => {
        const hdrLoader = new EXRLoader();
        const pmremGenerator = new THREE.PMREMGenerator(gl);
        pmremGenerator.compileEquirectangularShader();

        hdrLoader.load(HDRI_FILE, (texture) => {
            texture.mapping = THREE.EquirectangularReflectionMapping;
            const envMap = pmremGenerator.fromEquirectangular(texture).texture;
            scene.background = envMap; // シーン全体の背景を設定
            scene.environment = envMap; // 環境マップを設定

            // メモリ解放
            texture.dispose();
            pmremGenerator.dispose();
        });
    }, [gl, scene]);

    return null; // レンダリング対象はなし
};

// ================================
// PART 4: モデルとアニメーション
// ================================
// メインモデルの読み込みとアニメーションの管理
const Model: React.FC<{ currentAnimation: string }> = ({ currentAnimation }) => {
    const { camera } = useThree();
    const [model, setModel] = useState<THREE.Group | null>(null);
    const [mixer, setMixer] = useState<THREE.AnimationMixer | null>(null);

    // モデルの読み込み
    useEffect(() => {
        const loader = new GLTFLoader();
        loader.load(DEFAULT_ANIMATION_FILE, (gltf) => {
            const { scene: loadedScene } = gltf;
            loadedScene.scale.set(MODEL_SCALE, MODEL_SCALE, MODEL_SCALE); // モデルのサイズを設定
            loadedScene.rotateY(MODEL_ROTATION_Y); // モデルの初期回転を設定
            loadedScene.position.copy(MODEL_POSITION); // モデルの初期位置を設定
            setModel(loadedScene);

            const animationMixer = new THREE.AnimationMixer(loadedScene);
            setMixer(animationMixer);

            // カメラの初期位置を設定
            camera.position.copy(INITIAL_CAMERA_POSITION);
            camera.lookAt(0, 4, 0); // モデルの中心を見る
        });
    }, [camera]);

    // アニメーションの切り替え
    useEffect(() => {
        if (!model || !mixer) return;

        const loader = new GLTFLoader();
        loader.load(currentAnimation, (gltf) => {
            const newAnimation = gltf.animations[0];

            if (newAnimation) {
                const action = mixer.clipAction(newAnimation);
                mixer.stopAllAction(); // 既存のアクションを停止
                action.reset().fadeIn(0.5).play(); // 新しいアクションを再生
            }
        });
    }, [currentAnimation, model, mixer]);

    // アニメーションの更新
    useFrame((_, delta) => {
        if (mixer) mixer.update(delta);
    });

    return model ? <primitive object={model} /> : null; // モデルを表示
};

// ================================
// PART 5: メインコンポーネント
// ================================
// 全体のアプリケーションを構成
const ThreeDDancingUncle: React.FC = () => {
    const [currentAnimation, setCurrentAnimation] = useState(ANIMATION_FILES[0].path);

    return (
        <div style={{ width: "100vw", height: "100vh", position: "relative" }}>
            {/* アニメーション選択ボタン */}
            <div
                style={{
                    position: "absolute",
                    top: "10px",
                    left: "10px",
                    zIndex: 10, // ボタンをCanvasの上に表示
                }}
            >
                {ANIMATION_FILES.map((anim, index) => (
                    <button
                        key={index}
                        onClick={() => setCurrentAnimation(anim.path)} // アニメーションを切り替え
                        style={{
                            margin: "5px",
                            padding: "10px",
                            fontSize: "14px",
                            background: "rgba(255, 255, 255, 0.8)",
                            border: "1px solid #ccc",
                            borderRadius: "5px",
                            cursor: "pointer",
                        }}
                    >
                        {anim.name}
                    </button>
                ))}
            </div>
            <Canvas>
                {/* 背景コンポーネント */}
                <Background />
                {/* モデルとアニメーション */}
                <Model currentAnimation={currentAnimation} />
                {/* ライト設定 */}
                <ambientLight intensity={LIGHT_SETTINGS.ambient.intensity} />
                <directionalLight
                    position={LIGHT_SETTINGS.directional.position}
                    intensity={LIGHT_SETTINGS.directional.intensity}
                />
                <pointLight
                    position={LIGHT_SETTINGS.point.position}
                    intensity={LIGHT_SETTINGS.point.intensity}
                />
                {/* カメラ操作 */}
                <OrbitControls />
            </Canvas>
        </div>
    );
};

export default ThreeDDancingUncle;

PART 1: 必要なモジュールのインポート

ReactとThree.jsを使った3Dシーンの構築に必要なモジュールを準備になります。

// ================================
// PART 1: 必要なモジュールのインポート
// ================================
import React, { useState, useEffect } from "react";
import { Canvas, useFrame, useThree } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader";
import * as THREE from "three";
  • React
    • useState: アニメーション切り替えや状態管理を行う。
    • useEffect: モデルや背景の初期設定時に実行。
  • React Three Fiber
    • Canvas: 3Dシーンを描画するためのコンテナ。
    • useFrame: フレームごとのアニメーション更新処理を実行。
    • useThree: Three.jsのカメラ、シーン、レンダラーにアクセス。
  • @react-three/drei
    • OrbitControls: ユーザーがカメラを自由に操作(回転、ズーム、移動)できる便利なコンポーネント。
  • Three.js
    • GLTFLoader: glb形式の3Dモデルをロードするためのローダー。
    • EXRLoader: HDRI画像を読み込み、背景や環境光に利用。
    • THREE.Vector3: ベクトル操作(例: カメラやライトの位置)。
    • THREE.PMREMGenerator: HDRIを環境マップとして変換し、リアルなライティングを実現。

PART 2: 定数定義

次に定数定義です。
定数を定義することで、アプリケーション内で使用する値を一元管理し、再利用性と可読性を向上させます。3Dモデルやシーンの設定値をコード内の随所で使うため、定数化しておくとメンテナンスが容易になります。

// ================================
// PART 2: 定数の定義
// ================================
// アニメーションファイルのリスト
// 各アニメーションの名前とパスを格納
const ANIMATION_FILES = [
    { name: "Pod Baby Groove", path: "/models/uncle_glb/Animation_Pod_Baby_Groove_withSkin.glb" },
    { name: "Gangnam Groove", path: "/models/uncle_glb/Animation_Gangnam_Groove_withSkin.glb" },
    { name: "Pop Dance", path: "/models/uncle_glb/Animation_Superlove_Pop_Dance_withSkin.glb" },
];

// モデルファイルのパス
const DEFAULT_ANIMATION_FILE = ANIMATION_FILES[0].path;

// HDRI画像のパス (背景用)
const HDRI_FILE = "/hdri/cobblestone_street_night_4k.exr";

// 初期カメラ位置 (x, y, z)
const INITIAL_CAMERA_POSITION = new THREE.Vector3(10, 4, 10);

// モデルのスケール倍率
const MODEL_SCALE = 4;

// モデルの初期回転角度 (y軸回り、ラジアン単位)
const MODEL_ROTATION_Y = -1;

// モデルの初期位置 (x, y, z)
const MODEL_POSITION = new THREE.Vector3(0, -2, 0);

// ライトの設定
// 環境光、方向光、ポイントライトの位置と強度を定義
const LIGHT_SETTINGS = {
    ambient: { intensity: 0.5 }, // 環境光の強度
    directional: { position: new THREE.Vector3(10, 20, 10), intensity: 1.5 }, // 方向光の位置と強度
    point: { position: new THREE.Vector3(0, 10, 0), intensity: 1.5 }, // ポイントライトの位置と強度
};

生成した3Dモデルによっては、微調整が必要だと思いますので、下記を参考に数字をいじってみてください。

  • アニメーションファイルのリスト
    • アニメーション名とパスをペアで定義し、複数のアニメーションを管理。
  • 背景のHDRI画像パス
    • シーンの背景や環境マップとして利用するHDRI画像のパスを指定。
  • カメラの初期設定
    • カメラの初期位置や向きを定義して、モデル全体が適切に見えるように調整。
  • モデルの設定
    • モデルのスケール(大きさ)、回転角度、初期位置を定義。
  • ライト設定
    • 環境光、方向光、ポイントライトの位置や強度を定義して、シーン全体を適切に照らす。

PART 3: 背景の設定

HDRI画像を利用して、リアルで自然な背景と環境光をシーンに適用します。
HDRI画像は、「Poly Haven」などで無料でダウンロードできます。お好きな背景を選ぶといいかと思います。

// ================================
// PART 3: 背景の設定
// ================================
// シーンの背景をHDRI画像で設定
const Background: React.FC = () => {
    const { gl, scene } = useThree();

    useEffect(() => {
        const hdrLoader = new EXRLoader();
        const pmremGenerator = new THREE.PMREMGenerator(gl);
        pmremGenerator.compileEquirectangularShader();

        hdrLoader.load(HDRI_FILE, (texture) => {
            texture.mapping = THREE.EquirectangularReflectionMapping;
            const envMap = pmremGenerator.fromEquirectangular(texture).texture;
            scene.background = envMap; // シーン全体の背景を設定
            scene.environment = envMap; // 環境マップを設定

            // メモリ解放
            texture.dispose();
            pmremGenerator.dispose();
        });
    }, [gl, scene]);

    return null; // レンダリング対象はなし
};
  • HDRI画像の読み込み
    • EXRLoader を使用してHDRI画像をロード。
    • PMREMGenerator を使い、HDRIを環境マップに変換。
  • 背景の適用
    • ロードしたHDRI画像をシーンの背景(scene.background)として設定。
    • 環境マップ(scene.environment)として適用し、モデルの反射やライティングに利用。
  • メモリ管理
    • HDRI画像をシーンに適用した後、不要なリソース(テクスチャや生成器)を適切に解放。

PART 4: 地面の設定

3Dモデルをシーンに読み込み、複数のアニメーションを制御・切り替えられるようにします。
フレームごとにアニメーションをスムーズに更新し、リアルタイムでの動きを実現していきます。

// ================================
// PART 4: モデルとアニメーション
// ================================
// メインモデルの読み込みとアニメーションの管理
const Model: React.FC<{ currentAnimation: string }> = ({ currentAnimation }) => {
    const { camera } = useThree();
    const [model, setModel] = useState<THREE.Group | null>(null);
    const [mixer, setMixer] = useState<THREE.AnimationMixer | null>(null);

    // モデルの読み込み
    useEffect(() => {
        const loader = new GLTFLoader();
        loader.load(DEFAULT_ANIMATION_FILE, (gltf) => {
            const { scene: loadedScene } = gltf;
            loadedScene.scale.set(MODEL_SCALE, MODEL_SCALE, MODEL_SCALE); // モデルのサイズを設定
            loadedScene.rotateY(MODEL_ROTATION_Y); // モデルの初期回転を設定
            loadedScene.position.copy(MODEL_POSITION); // モデルの初期位置を設定
            setModel(loadedScene);

            const animationMixer = new THREE.AnimationMixer(loadedScene);
            setMixer(animationMixer);

            // カメラの初期位置を設定
            camera.position.copy(INITIAL_CAMERA_POSITION);
            camera.lookAt(0, 4, 0); // モデルの中心を見る
        });
    }, [camera]);

    // アニメーションの切り替え
    useEffect(() => {
        if (!model || !mixer) return;

        const loader = new GLTFLoader();
        loader.load(currentAnimation, (gltf) => {
            const newAnimation = gltf.animations[0];

            if (newAnimation) {
                const action = mixer.clipAction(newAnimation);
                mixer.stopAllAction(); // 既存のアクションを停止
                action.reset().fadeIn(0.5).play(); // 新しいアクションを再生
            }
        });
    }, [currentAnimation, model, mixer]);

    // アニメーションの更新
    useFrame((_, delta) => {
        if (mixer) mixer.update(delta);
    });

    return model ? <primitive object={model} /> : null; // モデルを表示
};
  • モデルの読み込み
    • GLTFLoader を使用して、glb形式の3Dモデルをロード。
    • モデルのスケール、位置、回転を適切に設定し、シーンに追加。
  • アニメーションの管理
    • AnimationMixer を利用して、モデルにアニメーションを適用。
    • ユーザー操作に応じてアニメーションを切り替える機能を実装。
  • フレームごとの更新
    • useFrame を使用して、アニメーションの進行をフレームごとに更新。
    • 経過時間(delta)に基づいてアニメーションを滑らかに進行。
  • 状態管理
    • ReactのuseState を使用して、現在のアニメーション状態を管理。
    • ユーザーが選択したアニメーションをリアルタイムで反映。

PART 5: メインコンポーネント

Reactを用いてアプリケーション全体を構成し、各機能(背景、モデル、アニメーション、ライト設定)を統合します。
ユーザーが操作可能なUI(アニメーション切り替えボタンなど)もここで記載しておきます。

// ================================
// PART 5: メインコンポーネント
// ================================
// 全体のアプリケーションを構成
const ThreeDDancingUncle: React.FC = () => {
    const [currentAnimation, setCurrentAnimation] = useState(ANIMATION_FILES[0].path);

    return (
        <div style={{ width: "100vw", height: "100vh", position: "relative" }}>
            {/* アニメーション選択ボタン */}
            <div
                style={{
                    position: "absolute",
                    top: "10px",
                    left: "10px",
                    zIndex: 10, // ボタンをCanvasの上に表示
                }}
            >
                {ANIMATION_FILES.map((anim, index) => (
                    <button
                        key={index}
                        onClick={() => setCurrentAnimation(anim.path)} // アニメーションを切り替え
                        style={{
                            margin: "5px",
                            padding: "10px",
                            fontSize: "14px",
                            background: "rgba(255, 255, 255, 0.8)",
                            border: "1px solid #ccc",
                            borderRadius: "5px",
                            cursor: "pointer",
                        }}
                    >
                        {anim.name}
                    </button>
                ))}
            </div>
            <Canvas>
                {/* 背景コンポーネント */}
                <Background />
                {/* モデルとアニメーション */}
                <Model currentAnimation={currentAnimation} />
                {/* ライト設定 */}
                <ambientLight intensity={LIGHT_SETTINGS.ambient.intensity} />
                <directionalLight
                    position={LIGHT_SETTINGS.directional.position}
                    intensity={LIGHT_SETTINGS.directional.intensity}
                />
                <pointLight
                    position={LIGHT_SETTINGS.point.position}
                    intensity={LIGHT_SETTINGS.point.intensity}
                />
                {/* カメラ操作 */}
                <OrbitControls />
            </Canvas>
        </div>
    );
};

export default ThreeDDancingUncle;
  • Canvasの設置
    • Canvas コンポーネントを利用して、3Dシーンを描画する枠組みを作成。
  • 各機能の統合
    • 背景(Background コンポーネント)をシーンに追加。
    • モデルとアニメーション(Model コンポーネント)を描画。
    • ライト設定(環境光、方向光、ポイントライト)をシーン内に配置。
  • UIの配置
    • Reactの状態管理(useState)を使用して、ユーザーが選択したアニメーションを切り替えるボタンを実装。
    • UIはCanvasの上に配置し、簡単に操作できるデザインに。
  • ユーザー操作
    • アニメーションの切り替えをボタンで行い、選択したアニメーションをリアルタイムで再生。

最後に

「Meshy AIで生成したglb形式の3DモデルをReactとThree.jsで制御」の全ステップが完了しました。これで、AIツール(Meshy)で生成した3DモデルをReactとThree.jsで動かす楽しさを体感できるシーンが完成です!

Meshyを利用して、様々な3Dモデルを表示してみてください!

📺 YouTubeでデモを見る:こちらのリンクから視聴できます。

このチュートリアルが役に立ったと感じたら、ぜひYouTubeのチャンネル登録&高評価お願いいたします!

さらに、このプロジェクトのソースコードはGitHubに公開しています。
ぜひコードをダウンロードして試してみてください!

💾 GitHubリポジトリ:こちらのリンクでソースコードをチェック!

参考になった方は、是非チャンネル登録をお願いします!

TypeScript x React Three Fiberのレッスンや作品は、今後もどんどん作成していきます!
YouTubeで告知致しますので、ぜひYouTubeのチャンネル登録をして通知をお待ちください!

📺 YouTubeを見る:こちらのリンクから視聴できます。

TypeScript x React Three Fiber

React Three Fiberで何ができるのか知りたい方は、下記を参考にしてみてください!
簡単にできる作品を用意しております!

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

情報セキュリティを勉強するために始めたブログです。
新人のため、広い心を持って見ていただけると嬉しく思います。
楽しくプログラミングを勉強するために、「Teech Lab.」もありますので、ソフトウェア開発にも興味があればぜひ覗いて見てください!

目次