加载资源
纹理、材质和模型是三维应用关键内容,通常也是加载耗时最多的部分。React 版本提供专用 hooks 和加载工具,在便捷使用的同时精细控制加载时机和方式。
基本用法
可使用模型、高斯泼溅、纹理、环境和字体等专用 hooks,结构相似,均返回引擎 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 暴露内部结构,方便修改组件、动画和物理。简单且无需修改时也可用 <Render asset={asset} />,但 Gltf 更灵活。
详见修改 GLB,了解添加动画、移除灯光和附加物理。
- 演示
- 代码
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>
);
};
预加载
Hooks 同时返回加载与错误状态,可在等待时显示加载器,失败时显示错误。
model-viewer.tsx
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} />;
}
加载选项
部分资源接受额外选项,可作为 hook 第二参数传入。
// Load a texture with specific settings
const { asset } = useTexture('texture.jpg', {
mipmaps: true,
anisotropy: 16,
type: 'rgba'
});
资源 hooks
可通过包装 useAsset 构建更高级的专用加载逻辑。
useModel:GLTF/GLB。useTexture:纹理。useSplat:高斯泼溅。useEnvAtlas:环境图集。useAsset:任意资源。useFont:字体。
资源缓存
默认缓存,避免重复加载和内存副本。不再需要时应正确卸载。
unloading-model-viewer.tsx
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} />;
}
注意
卸载资源会全局移除它,影响共享该资源的其他组件。
自定义加载状态
可根据 loading 显示占位内容或自定义加载器。
loading-spinner.tsx
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} />
</>
}
渐进加载
可优先快速显示,再加载高质量内容。
progressive-loading.tsx
import { Entity } from '@playcanvas/react';
import { GSplat } from '@playcanvas/react/components';
import { useSplat } from '@playcanvas/react/hooks';
// A component that displays a splat with progressive loading
export function ProgressiveAsset() {
const { asset: low } = useSplat('./low-quality-model.sog'); // load the low quality asset
const { asset: high } = useSplat(low && './high-quality-model.sog'); // load the high quality asset, when the low quality is loaded
if (!low && !high ) return null;
return <GSplat asset={high || low} />
}
数据获取库
需要高级缓存或加载策略时,可通过 fetchAsset 集成 React Query、SWR 或其他基于 Promise 的库。
model-with-query.tsx
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} />;
}
详见 React Suspense、React Query 与 SWR。