Asset の読み込み
テクスチャ、マテリアル、3D モデルといった Asset は、どの 3D アプリにも欠かせません。一般に、読み込みに最も時間がかかります。PlayCanvas React では、さまざまな種類の Asset を読み込む専用フックと、Asset 読み込み用のユーティリティ関数を用意しています。すぐに使い始められつつ、いつ・どのように読み込むかを細かく制御できます。
基本的な使い方
Asset を読み込む最も簡単な方法は、専用フックのいずれかを使うことです。モデル、Gaussian splat、テクスチャ、環境マップ、フォントなど、それぞれにフックがあります。形はどれも似ており、PlayCanvas の Asset を返します。
GLB モデルには <Gltf> コンポーネントを使います。
import { useModel } from '@playcanvas/react/hooks';
import { Gltf } from '@playcanvas/react';
const { asset } = useModel('model.glb');
return <Gltf asset={asset} key={asset.id} />;
<Gltf> は GLB モデルを読み込んでレンダリングする推奨の方法です。モデル内部の構造にアクセスできるため、コンポーネントの変更、アニメーションの追加、物理の取り付けが容易です。変更が不要な単純なケースでは <Render asset={asset} /> も使えますが、<Gltf> の方が柔軟性があります。
アニメーションの追加、ライトの削除、物理コンポーネントの取り付けなど、GLB モデルの変更のページも参照してください。
- Demo
- Code
import { Entity } from '@playcanvas/react';
import { useModel } from '@playcanvas/react/hooks';
import { Gltf } from '@playcanvas/react';
export const ModelLoading = () => {
// Load the selected model
const { asset, error } = useModel('/assets/statue.glb');
// If there is an error, log it
if (error) {
console.error('Error loading model:', error);
return null;
}
// If the asset is not loaded, return null
if (!asset) return null;
// Match the original example framing so the shared staging camera starts outside the model.
return (
<Entity position={[0, -0.5, 0]} scale={[0.1, 0.1, 0.1]}>
<Gltf asset={asset} key={asset.id} />
</Entity>
);
};
プリロード
Asset フックは、読み込み情報やエラー状態も返します。読み込み中はプリローダーにフォールバックしたり、失敗時はエラーメッセージを表示したりできます。
import { useModel } from '@playcanvas/react/hooks';
import { Gltf } from '@playcanvas/react';
export function ModelViewer() {
const { asset, loading, error } = useModel('model.glb');
// If the asset is still loading, show a loading spinner
if (loading) return <LoadingSpinner />;
// If there is an error, show an error message
if (error) return <ErrorMessage message={error} />;
// If the asset is loaded, render it
return <Gltf asset={asset} key={asset.id} />;
}
Props を使った読み込み
一部の Asset は、読み込み方法をカスタマイズする追加プロパティを受け付けます。第 2 引数でフックに渡します。
// Load a texture with specific settings
const { asset } = useTexture('texture.jpg', {
mipmaps: true,
anisotropy: 16,
type: 'rgba'
});
Asset フック
Asset の種類ごとに異なるフックがあります。useAsset フックをラップして、より高度なフックを自作することもできます。
useModel— 3D GLTF/GLB モデルの読み込みuseTexture— テクスチャの読み込みuseSplat— Gaussian Splat の読み込みuseEnvAtlas— 環境アトラスの読み込みuseAsset— 任意のタイプの Asset の読み込みuseFont— フォントの読み込み
Asset のキャッシュ
同じファイルを何度も読み直さないよう、デフォルトで Asset はキャッシュされます。メモリの重複は抑えられますが、不要になったら正しくアンロードする必要があります。
import { useModel } from '@playcanvas/react/hooks';
import { useEffect } from 'react';
export function UnloadingModelViewer() {
const { asset, loading, error } = useModel('model.glb');
useEffect(() => {
return () => asset?.unload();
}, [asset]);
if (!asset) return null;
return <Gltf asset={asset} key={asset.id} />;
}
Asset をアンロードするとグローバルから削除されます。 同じ Asset を使っている他のコンポーネントにも影響します。
カスタムの読み込み状態
Asset の読み込み状態を確認すれば、読み込み中はプレースホルダーやカスタムローダーを表示できます。細かく制御できます。
import { useModel } from '@playcanvas/react/hooks';
import { Gltf } from '@playcanvas/react';
// A component that displays a model with a custom loading state
export function ModelWithCustomLoading() {
const { asset: plane, loading: planeLoading } = useModel('plane.glb');
const { asset: car, loading: carLoading } = useModel('car.glb');
if (planeLoading || carLoading) return <LoadingSpinner />;
return <>
<Gltf asset={car} key={car.id} />
<Gltf asset={plane} key={plane.id} />
</>
}
プログレッシブ読み込み
読み込みフックは、Asset を段階的に読み込む簡単な仕組みも提供します。まずはすぐにレンダリングし、あとから高品質なコンテンツを続けて読み込めます。
import { Entity } from '@playcanvas/react';
import { GSplat } from '@playcanvas/react/components';
import { useSplat } from '@playcanvas/react/hooks';
// 段階的読み込みでスプラットを表示するコンポーネント
export function ProgressiveAsset() {
const { asset: low } = useSplat('./low-quality-model.sog'); // 低品質 Asset を読み込む
const { asset: high } = useSplat(low && './high-quality-model.sog'); // 低品質がロードされたら高品質 Asset を読み込む
if (!low && !high ) return null;
return <GSplat asset={high || low} />
}
データ取得ライブラリ
より高度なキャッシュや読み込み戦略が必要な場合は、React Query や SWR など、Promise ベースのライブラリと fetchAsset ユーティリティを組み合わせられます。
import { fetchAsset } from '@playcanvas/react/utils';
import { useQuery } from '@tanstack/react-query';
function useQueryModel(src: string) {
const query = useQuery({
queryKey: ['asset', src],
// 'container' is the type of asset we're loading (e.g., model, texture, etc.)
queryFn: () => fetchAsset({ app, url: src, type: 'container' })
});
return query;
}
export function ModelWithQuery() {
const { data: asset, isLoading } = useQueryModel('model.glb');
if (isLoading) return <LoadingSpinner />;
return <Gltf asset={asset} key={asset.id} />;
}
使い方の詳細は React Query のドキュメントと SWR のドキュメントを参照してください。
Suspense との連携
React Query と SWR は Suspense 向けのサポートが組み込まれており、読み込み状態をより宣言的に扱えます。
import { fetchAsset } from '@playcanvas/react/utils';
import { Gltf } from '@playcanvas/react';
import { useQuery } from '@tanstack/react-query';
function useSuspendedQueryModel(src: string) {
const query = useQuery({
queryKey: ['asset', src],
queryFn: () => fetchAsset({ app, url: src, type: 'container' }),
suspense: true
});
return query;
}
export function ModelWithQuery() {
const { data: asset } = useSuspendedQueryModel('model.glb');
return <Gltf asset={asset} key={asset.id} />;
}
Suspense については React のドキュメント, および React Query のドキュメントと SWR のドキュメントも参照してください。