Skip to content

react-three-fiber 集成

react-three-fiber(简称 R3F)是一个基于 React 封装 Three.js 的库,它将 Three.js 转换为 React 组件,使开发者可以用 JSX 直接声明 3D 场景,并利用 React 的状态管理、hooks 和组件系统构建复杂的 3D 应用。

从模板开始

建议直接使用集成好的项目模板,它包含了完整的分包优化/代码兼容性配置。

如遇下载失败,你也可以手动到 github 代码仓库根据对应分支下载模板。

shell
npx degit minisheeep/threejs-miniprogram-template#uni-ts-r3f my-project
shell
npx degit minisheeep/threejs-miniprogram-template#weapp-vite-r3f my-project

手动集成

安装

shell
pnpm i @minisheep/platform-adapter-integration

使用

然后在 vitets 的配置文件中添加以下内容:

ts
import { defineConfig } from 'vite';
import threePlatformAdapter from '@minisheep/three-platform-adapter/plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    //...
    threePlatformAdapter(),
    react(),
  ],
})
json5
{
  "compilerOptions": {
    //...
    "jsx": "react"
  }
}

然后使用包导出的 createRoot 方法将你使用 tresjs 编写的场景组件挂载到画布上。

jsx
import { createRoot } from "@minisheep/platform-adapter-integration/r3f";
import { YourScene } from 'path/to/YourScene.tsx'

// ...
await adapter.useCanvas(`#canvas-id`).then(result => {
  createRoot(result.canvas).render(<YourScene/>);
  // ...
});

相关函数声明如下。

ts
import type { ReactNode } from 'react';

export declare function createRoot(canvas: HTMLCanvasElement): {
  render(reactElement: ReactNode, callback?: (() => void) | null): any;
  unmount(callback?: () => void): void;
};

需要注意的是,挂载的场景组件需要满足如下要求

  • 只有一个 R3F 的 Canvas 根节点
  • 禁止包含其他小程序元素

例如:

jsx
import { Canvas } from '@react-three/fiber'

export function YourFirstScene() {
  return (
    <Canvas>
      <mesh>
        <torusGeometry args={[1, 0.5, 16, 32]}/>
        <meshBasicMaterial color="orange"/>
      </mesh>
      <ambientLight intensity={1}/>
    </>
  );
}

完整的代码你可以参考此模板

uni-app 中使用

uni-app 中集成 tresjs 显得有些特别,因为 uni-app 基于 vue 生态,而 R3F(React Three Fiber)属于 react 体系, 尽管如此,R3F 所具备的一些优势依然值得关注:

  • 相较于 tres.jsR3F 更加成熟稳定。
  • 拥有更活跃的社区和丰富的使用场景示例。

但这也带来了一些挑战:

  • 你需要额外引入 react 的核心依赖,这将显著增加包体积。

配置以支持 react-jsx

你仅需在 vite.config.ts 中添加以下配置,否则 uni 会拦截 jsx 的相关处理

ts
import { defineConfig } from 'vite';
import threePlatformAdapter from '@minisheep/three-platform-adapter/plugin';
import react from '@vitejs/plugin-react';
import { supportR3fInUni } from '@minisheep/platform-adapter-integration/r3f/plugin'; 

export default defineConfig({
  plugins: [
    //...
    threePlatformAdapter(),
    react(),
    supportR3fInUni(),
  ],
})

⚠️注意

这个插件可能会破坏 uni 处理 jsx 的能力(仅构建小程序目标的用户不影响)。

额外处理

如果你需要使用 @react-three/drei 提供的 Text 组件,还需通过 @minisheep/troika-three-text 来强制覆盖默认的 troika-three-text 包。 该版本修复了一些兼容性问题,使其在特定环境中能够正常运行。

package.json 中添加如下配置:

json
{
  "pnpm": {
    "overrides": {
      "troika-three-text": "npm:@minisheep/troika-three-text@^0.52.4"
    }
  }
}
json
{
  "overrides": {
    "troika-three-text": "npm:@minisheep/troika-three-text@^0.52.4"
  }
}
json
{
  "resolutions": {
    "troika-three-text": "npm:@minisheep/troika-three-text@^0.52.4"
  }
}

同时,还需要手动禁用该库的 worker 功能:

js
import { configureTextBuilder } from 'troika-three-text';

configureTextBuilder({
  useWorker: false, // 必须禁用 worker,否则会导致运行异常
});