Skip to content

tresjs 集成

tres.js 是一个基于 vue3three.js 的封装库,它让你可以使用 vue 组件的方式来构建 3D 场景,降低了使用 three.js 的门槛,并且更适合 Vue 生态的开发者。

注意

当前版本的 tresjs 有许多需要注意的问题,详见这里

从模板开始

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

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

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

手动集成

首先安装依赖包:

shell
pnpm i @minisheep/platform-adapter-integration/tresjs

它只导出了一个函数,用于将画布和 trejs 组件关联起来。

ts
import type { App, RendererElement } from 'vue';
export function mountTresApp(
  canvas: HTMLCanvasElement,
  rootComponent: Component,
  rootProps?: Record<string, unknown> | null
): App<RendererElement>

然后在 @minisheep/three-platform-adapter/plugin 的配置中添加以下内容:

ts
import { defineConfig } from 'vite';
import threePlatformAdapter from '@minisheep/three-platform-adapter/plugin';
import vue from '@vitejs/plugin-vue'; 
import { templateCompilerOptions } from '@tresjs/core'; 

export default defineConfig({
  plugins: [
    //...
    threePlatformAdapter({
      mergePrefixGlobalOptions: { 
        include: [
          /\/@vueuse\/(core|shared)\//,
          /\/@tresjs\/(core|cientos)\//,
        ],
      }
    }),
    vue({
      ...templateCompilerOptions,
    }),
  ],
})

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

js
import { mountTresApp } from "@minisheep/platform-adapter-integration/tresjs";
import YourScene from 'path/to/YourScene.vue'

// ...
await adapter.useCanvas(`#canvas-id`).then(result=>{
  const app = mountTresApp(result.canvas, YourScene)
  // ...
});

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

uni-app 中集成

因为 uni-app 构建小程序使用的 vue 是特殊处理过的版本(见 @dcloudio/uni-mp-vue),剔除了许多 @vue/runtime-core 导出的内容。

tresjs 是基于 createRenderer 工作的,所以在之前的配置上还需要额外的处理才能让其正常工作。

tresjs 组件存放目录

首先你需要定义一个目录,专门用于存放使用 tresjs 编写的组件。 然后将它在 uni 插件的处理中排除,使其能够访问标准的 vue 而不是 uni 处理过的版本。

需要在 vite.config.ts 中添加如下配置。

ts
import { defineConfig } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
import threePlatformAdapter from '@minisheep/three-platform-adapter/plugin';
import vue from '@vitejs/plugin-vue'; 
import { templateCompilerOptions } from '@tresjs/core';
import { useStandardVuePlugin } from "@minisheep/platform-adapter-integration/tresjs/plugin";

const tresjsComponentPattern = /\/path_to_your_tresjs_component_folder\/.*.vue///
export default defineConfig({
  plugins: [
    //@ts-expect-error uni-plugin在 当前版本在以 esm 形式导出格式异常
    uni.default({
      vueOptions: {
        exclude: [tresjsComponentPattern] 
      }
    }),
    vue({
      include: [tresjsComponentPattern], 
      ...templateCompilerOptions
    }),
    useStandardVuePlugin({
      include: [
        tresjsComponentPattern
      ]
    })
  ],
})

模板中的配置还处理了一些兼容和分包问题,详细配置你可以参考此这里

强制覆盖依赖版本

由于 uni-app 相关插件固定依赖了 @vue/shared 某个版本, 可能会与 @tresjs/core 依赖的 @vue/shared 版本出现不一致的情况,为避免重复导入以及出现非预期问题, 可以通过配置强制统一版本。

你需要在 package.json 增加以下内容, 具体版本号可以根据你安装的 @tresjs/core 所依赖的 vue 版本决定

json
{
  "pnpm": {
    "overrides": {
      "@vue/shared": "^x.x.xx"
    }
  }
}
json
{
  "overrides": {
    "@vue/shared": "^3.5.13"
  }
}
json
{
  "resolutions": {
    "@vue/shared": "^3.5.13"
  }
}

额外处理

由于 trejs 目前的 Event System 在触摸设备上运行是有缺陷的,需要等待后续的 pull 被合并才可能会解决。

具体表现是光线投射的目标元素只会根据 pointermove 事件进行更新,所以在单一点击相关事件(click,pointer-down,pointer-up等)不能在正确的元素上触发。

你需要手动进行如下处理:

  • 每次在传递 touchstart 事件之前需要手动复制并修改 typetouchmove,然后传递一次。参考如下代码:
js
import { adapter } from "@minisheep/three-platform-adapter";

Page({
  tresApp: null,
  defaultHandler: ()=>{},
  async onReady() {
    const result = await adapter.useCanvas(`#tresjs_demo`, this);
    this.defaultHandler = (e) => {
      if (e.type === 'touchstart') {
        result.eventHandler({
          ...e,
          type: 'touchmove',
        }, true, true) // 这里第三个参数需要为 true
      }
      result.eventHandler(e, true)
    };
  },
})
wxml
<view class="page-container">
  <canvas
    type="webgl2"
    id="tresjs_demo"
    bindtouchstart="defaultHandler"
    bindtouchmove="defaultHandler"
    bindtouchcancel="defaultHandler"
    bindtouchend="defaultHandler"
    bindtap="defaultHandler"
  >
  </canvas>
</view>

:::