ReactでPlayCanvasが使えるライブラリが公開されたので早速使ってみました!

こんにちは。GMOグローバルサイン・ホールディングス CTO室 所属のはが(@mxcn3)です。

前回の記事では、「Meta Questでのボディトラッキングについて」を紹介をさせて頂きました。

今回は、PlayCanvasのリポジトリに公開された@playcanvas/reactというライブラリについて、その特徴と使い方を解説します。

まず、PlayCanvasとは

PlayCanvas Logo
PlayCanvasロゴ

PlayCanvasは、WebGLを利用した3Dグラフィックスを作成できるJavaScriptライブラリです。オープンソースソフトウェアとして開発されており、Three.jsBabylon.jsといった他のWebGLライブラリと同様に利用できます。

PlayCanvas Editor
PlayCanvas エディター

PlayCanvasには、開発環境としてエディターが付属しています。これはブラウザベースの統合開発環境(IDE)で、3Dアセットの管理、シーンの編集、スクリプトの作成などが行えます。

プロジェクトの作成から編集、公開までをブラウザ上で完結できるため、特別なソフトウェアをインストールする必要はなく、UnityやUnreal Engineといった他のゲームエンジンのエディターと似た操作性を持っているため、これらのエンジンを使った経験がある方ならスムーズに使い始めることができます。

この記事について

@playcanvas/react Repository
@playcanvas/react リポジトリ

2024年11月にplaycanvas/reactリポジトリが公開されました。ライブラリの開発を進めているのはPlayCanvasのコア開発者であり、PlayCanvasのバージョン2.0.0から導入されたESMスクリプト対応の開発を進めている、@marklundinさんです。

ESM(ECMAScript Modules)は、JavaScriptのモジュールシステムの仕様です。コード内でimportexportを使用することで、コードをモジュール単位で開発できます。
PlayCanvas内のオブジェクトを制御するスクリプトもESMスクリプトとして対応が進めれています。

PlayCanvasの開発では、エディターでの開発とエンジンでの開発の2つの方法があり、どちらかというと専用のPlayCanvasエディターでの開発をされる方の方が多いため、今まではこういったReactでの開発と統合をするような仕組みはほとんありませんでした。

Three.jsというWebGL開発のフレームワークでは、既に、「React Three Fiber (R3F)」といった、ライブラリを使うことでReactのフロントエンドのエコシステムで開発をすることができます。

React Three Fiber (R3F)は、ReactでThree.jsを使用できるようにするためのライブラリです。コンポーネントベースで3Dシーンの構築や管理を行えます。

そして、この @playcanvas/react を使うとPlayCanvasでも、Reactアプリケーションに統合することができるので、特に、ウェブフロントエンドの開発者の方々がPlayCanvasを使うための手助けになるような仕組みだと思います。

この背景には、PlayCanvasのESMへの対応も関わっているためそちらも紹介をします。

PlayCanvasのESMへの対応について

PlayCanvasでは、PlayCanvasエンジンv2.0.0、PlayCanvasエディターのバージョンv1.45.3から、エディターとエンジンの両方でESMスクリプトとして利用できるようになりました。

対応を時系列でまとめると、以下のようになります。

  • 2024年8月: PlayCanvasエンジン v2.0.0公開 (エンジンのみ対応)
  • 2024年9月: PlayCanvasエディター v1.45.3でESMスクリプト対応
  • 2024年11月: @playcanvas/react 公開

早速使ってみました

GlbViewer
GLBビューア
SplatViewer
3D Gaussian Splattingビューア

今回は@playcanvas/reactを使った2つのデモページを作成いたしました。

3D Gaussian Splattingは、レンダリング手法の一つであり、点群データを滑らかな表現に変換する技術です。PlayCanvasでは、エディター・エンジンともに描画に対応をしています。また、SuperSplatというブラウザ上で点群データを編集できるソフトも公開をしています。

ソースコードは、GitHub ( yushimatenjin/playcanvas-react-next)で公開しています。

PlayCanvasのバージョンは、本ブログ執筆時点の最新バージョンのPlayCanvas エンジン (v2.2.2)を利用しています。

@playcanvas/reactは公開されたばかりのライブラリです。

早速その使い方を見ていきましょう。

デモの実行方法

今回は、私が作成をしたplaycanvas-react-nextのリポジトリを元にモデルビューアを動かす手順を紹介します。

実行には、Node.jsの実行環境が必要です。

1. リポジトリのクローン

git clone git@github.com:yushimatenjin/playcanvas-react-next.git

2. プロジェクトディレクトリへの移動

cd playcanvas-react-next

3. 依存パッケージのインストール

npm install

4. 実行

以下のコマンドでローカル環境にデモを起動します。

npm run dev

起動後、以下のURLでデモにアクセスできます。

デモの画面

GlbViewer
GLBビューア
SplatViewer
3D Gaussian Splattingビューア

それでは、これらのコードを見ていきましょう。

PlayCanvas Reactの実装について

このデモプロジェクトは、Next.jsフレームワークと@playcanvas/reactを組み合わせてビューアを構築しています。

主要なコードは以下のファイルに含まれています。

  • /app/glb-viewer/layout.tsx
  • /app/glb-viewer/page.tsx

@playcanvas/reactの実装部分を中心に解説します。

// /app/glb-viewer/layout.tsx
'use client';
// FILLMODE_FILL_WINDOWの設定をインポート
import { FILLMODE_FILL_WINDOW } from 'playcanvas';
// @playcanvas/reactライブラリからApplicationをインポート
import { Application } from '@playcanvas/react';
// アセットのロード管理のためにreact-queryというライブラリを利用
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient();

export default function GlbViewerLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <QueryClientProvider client={queryClient}>
      <Application fillMode={FILLMODE_FILL_WINDOW}>
        {children}
      </Application>
    </QueryClientProvider>
  );
}

まず、/app/glb-viewer/layout.tsx ファイルでは、@playcanvas/reactApplicationコンポーネントを使用して、PlayCanvasのアプリケーション環境を設定しています。
FILL_MODE_FILL_WINDOWなどPlayCanvasアプリケーションの設定も行うことができます

FILL_MODE_FILL_WINDOWは、PlayCanvasアプリケーションに設定ができる項目で、有効にすると画面サイズに応じてコンテンツが自動的にスケーリングされます。
PlayCanvasドキュメント
https://api.playcanvas.com/classes/Engine.Application.html

<Application fillMode={FILLMODE_FILL_WINDOW}>
  {children}
</Application>

非同期でのモデルやテクスチャのアセットデータを取得するために、react-queryQueryClientProviderを使用しています。

<QueryClientProvider client={queryClient}>
</QueryClientProvider>

次に、ページの設定を見ていきます。/app/glb-viewer/page.tsxではエンティティーのヒエラルキーを宣言的に設定をして3Dシーンを構築しています。

以下がpage.tsxのコードです。

// /app/glb-viewer/page.tsx
"use client";
// playcanvasライブラリからColorをインポート
import { Color } from "playcanvas";
// Entity, Containerをインポート
import { Entity, Container } from "@playcanvas/react";
// カメラ、ライト、スカイボックスの設定コンポーネントをインポート
import { Camera, Light, EnvAtlas } from "@playcanvas/react/components";
// オービットコントロールのスクリプトをインポート
import { OrbitControls } from "@playcanvas/react/scripts";
// アセットのロード用のHooksをインポート
import { useModel, useEnvAtlas } from "../../utils/hooks";

const Scene = () => {
  // public/environment-map.pngからスカイボックス用の画像をロード
  const { data: envMap, isPending: isEnvLoading } = useEnvAtlas(
    "./environment-map.png"
  );
  // public/guitar.glbからギターのモデルデータをロード
  const { data: model, isPending: isModeLoading } = useModel("./guitar.glb", {
    autoRelease: true,
  });
  // ロードが完了したらシーンを表示
  if (isEnvLoading || isModeLoading || !envMap || !model) return null;
  return (
    <>
      <EnvAtlas asset={envMap} />
      <Entity name="light" rotation={[45, 45, 0]}>
        <Light type="directional" color={Color.WHITE} />
      </Entity>
      <Entity name="camera" position={[0, 0.5, 2]}>
        <Camera clearColor="#ccccff" />
        <OrbitControls inertiaFactor={0.6} distanceMin={1.4} />
      </Entity>
      <Entity name="model">
        <Container name="guitar" asset={model} />
      </Entity>
    </>
  );
};

export default Scene;

これらを設定した上での表示はこのようになります。

GlbViewer
GLBビューアの実行画面

アセットデータの非同期読み込み

import { useModel, useEnvAtlas } from "../../utils/hooks";
// ...
const { data: envMap, isPending: isEnvLoading } = useEnvAtlas( "./environment-map.png" );
const { data: model, isPending: isModeLoading } = useModel("./guitar.glb", { autoRelease: true });

この部分では、useModeluseEnvAtlasというカスタムフックを使用して、非同期で3Dアセットを読み込んでいます。これらは/utils/hooks.tsに定義されていますが、パッケージには含まれていないため、@playcanvas/reactのリポジトリ内のソースコードからコピーする必要があります。

3D Gaussian Splatting ビューア

3D Gaussian Splattingの読み込みコードも見ていきましょう。

/app/splat-viewer/page.tsxのコードです。

// /app/splat-viewer/page.tsx
"use client";
// playcanvasライブラリからColorをインポート
import { Color } from "playcanvas";
// Entityをインポート
import { Entity } from "@playcanvas/react";
// カメラ、ライト、 3D Gaussian Splattingの設定コンポーネントをインポート
import { Camera, Light, GSplat } from "@playcanvas/react/components";
// オービットコントロールのスクリプトをインポート
import { OrbitControls } from "@playcanvas/react/scripts";
// アセットのロード用のHooksをインポート
import { useSplat } from "../../utils/hooks";

const Scene = () => {
  // public/stone.plyから石のデータ( 3D Gaussian Splatting) をロード
  const { data: model, isPending: isModeLoading } = useSplat("./stone.ply", { autoRelease: true });
   // ロードが完了したらシーンを表示
  if (isModeLoading || !model) return null;
  return (
    <>
      <Entity name="light" rotation={[45, 45, 0]}>
        <Light type="directional" color={Color.WHITE} />
      </Entity>
      <Entity name="camera" position={[4, 2, 4]}>
        <Camera clearColor="#ccccff" />
        <OrbitControls inertiaFactor={0.6} distanceMax={5} distanceMin={3} />
      </Entity>
      <Entity name="model">
        <GSplat asset={model} />
      </Entity>
    </>
  );
};

export default Scene;

コードは、GLBビューアと大きな違いはありません。

GSplatコンポーネントを使用して、3D Gaussian Splattingのデータを表示しています。

表示結果はこのようになります。

まとめ

まず、今回触ってみて分かった点としてライブラリの内での機能使い分けは以下のようになっているようです。

  • playcanvas: PlayCanvasエンジンの機能を提供するライブラリ
  • @playcanvas/react: 主にEntityContainerというコンポーネントを提供するライブラリ
  • @playcanvas/react/components: CameraLight など、PlayCanvasエディターでも使用されるコンポーネントを提供するライブラリ。Entity の子要素として設定することで、エンティティにコンポーネントを追加できます。
  • @playcanvas/react/scripts: OrbitControlsなど、便利なスクリプトがいくつか提供されています。

また、今回実装した内容をPlayCanvasエディターで再現すると、
以下のようになります。

このように、ヒエラルキー構造がPlayCanvasエディターでの構成と同じになっているため、PlayCanvasエディターの操作に慣れている方は、Reactアプリケーションでもスムーズにコードを書くことができ、フロントエンドの開発者の方は、Reactのエコシステム上で開発ができるため、多くの人がPlayCanvasを利用できるようになる可能性のあるライブラリだと思います。

参考リンク

質問や不明点がありましたら、Twitterの@mxcn3までお気軽にお問い合わせください。