跳到主要内容

加载资源

纹理、材质和模型是三维应用关键内容,通常也是加载耗时最多的部分。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,了解添加动画、移除灯光和附加物理。

预加载​

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 构建更高级的专用加载逻辑。

资源缓存​

默认缓存,避免重复加载和内存副本。不再需要时应正确卸载。

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。