资源 Hooks
专用 hooks 简化不同资源的加载与管理,提供等待和错误状态。
通用签名如下:
const { asset, loading, error } = useModel(src, props);
src 是 URL,props 是传给加载器的额外配置。
import { useModel } from '@playcanvas/react/hooks';
export function RenderAsset() {
const { asset, loading, error } = useModel('model.glb');
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return <Render asset={asset} />;
}
加载进度
useAsset 通过 subscribe 回调提供进度,可显示指示器或进度条,但并非所有资源类型都保证进度可用。
import { useSplat } from '@playcanvas/react/hooks';
export function RenderSplat() {
const [progress, setProgress] = useState(0);
const { asset, loading, error, subscribe } = useSplat('splat.ply');
// Subscribe to loading progress
useEffect(() => {
const unsubscribe = subscribe(({ progress }) => setProgress(progress));
return () => unsubscribe();
}, [subscribe]);
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return (<Entity>
<GSplat asset={asset} />
</Entity>);
}
全部 hooks
包括:
useModel:模型。useSplat:高斯泼溅。useTexture:纹理。useEnvAtlas:环境图集。useAsset:通用加载。
API
完整返回值如下。
| 名称 | 类型与说明 | 默认值 |
|---|---|---|
asset | Asset<string> | null已加载的资源,尚未加载或失败时为 null。 | null |
loading | boolean资源是否正在加载;加载完成或失败时为 false。 | true |
error | string | null加载失败时的错误信息,成功时为 null。 | null |
subscribe | (cb: AssetResultCallback) => () => void使用此项订阅加载进度事件。 | - |
useModel
加载 GLB/GLTF,传入 URL 和可选配置,将资源用于 Render。
import { useModel } from '@playcanvas/react/hooks';
export function RenderModel() {
const { asset, loading, error } = useModel('model.glb');
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return <Render asset={asset} />;
}
Draco 解码
useModel 开箱支持 Draco,按原文版本使用 1.5.7,从 Google CDN 延迟加载。
自行托管时,可通过 dracoInitialize 配置。
import { dracoInitialize } from 'playcanvas';
dracoInitialize({
jsUrl: '/draco_decoder.js',
wasmUrl: '/draco_decoder.wasm',
lazyInit: true
});
useSplat
加载高斯泼溅,传 URL 和配置,将资源用于 GSplat。
import { useSplat } from '@playcanvas/react/hooks';
export function RenderSplat() {
const { asset, loading, error } = useSplat('splat.ply');
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return (<Entity>
<GSplat asset={asset} />
</Entity>);
}
详情见 GSplat。
useTexture
加载纹理,供任何接受纹理的组件使用。
import { useTexture } from '@playcanvas/react/hooks';
import { useMaterial } from '@playcanvas/react/hooks';
export function RenderTexture() {
const { asset, loading, error } = useTexture('texture.jpg');
const material = useMaterial({ diffuseMap: asset?.resource });
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return <Render type="box" material={material} />;
}
详见 useMaterial 和 Render。
useEnvAtlas
加载环境图集,用于 Environment。
import { useEnvAtlas } from '@playcanvas/react/hooks';
import { Environment } from '@playcanvas/react/components';
export function RenderEnvAtlas() {
const { asset, loading, error } = useEnvAtlas('env.jpg');
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return <Environment envAtlas={asset} />;
}
详见 Environment。
useFont
文本使用 MSDF,因此 TTF/OTF 需先转换为 JSON 与一张或多张 PNG。通过 font-tools 的网页或命令行生成,再与应用一起提供,例如放到 Vite public:
npx @playcanvas/font-tools Inconsolata.ttf --charset latin -o public/fonts/inconsolata
useFont 加载 JSON 并自动加载纹理,再传给文本元素:
import { Entity } from '@playcanvas/react';
import { Element } from '@playcanvas/react/components';
import { useFont } from '@playcanvas/react/hooks';
export function RenderText() {
const { asset, loading, error } = useFont('fonts/inconsolata.json');
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
if (!asset) return null;
return (
<Entity name="label">
<Element type="text" fontAsset={asset} text="Hello, World!" />
</Entity>
);
}
useAsset
useAsset 通用加载引擎支持的任意资源,适合动态类型。
import { useAsset } from '@playcanvas/react/hooks';
const assetTypeToLoadType = {
'ply': useSplat,
'jpg': useTexture,
'png': useTexture,
'glb': useModel,
'gltf': useModel,
}
export function useDynamicAsset(src: string, props: Record<string, unknown> = {}) {
const mimeType = src.split('.').pop();
const loadType = assetTypeToLoadType[mimeType];
if (!loadType) {
throw new Error(`Unsupported asset type: ${mimeType}`);
}
return useAsset(src, loadType, props);
}