tresjs 集成
tres.js
是一个基于vue3
和three.js
的封装库,它让你可以使用vue
组件的方式来构建 3D 场景,降低了使用three.js
的门槛,并且更适合 Vue 生态的开发者。
注意
在小程序中使用当前版本的 tresjs
有许多需要注意的问题,详见这里。
从模板开始
建议直接使用集成好的项目模板,它包含了完整的分包优化/代码兼容性配置。
如遇下载失败,你也可以手动到 github 代码仓库根据对应分支下载模板。
npx degit minisheeep/threejs-miniprogram-template#uni-ts-tresjs my-project
npx degit minisheeep/threejs-miniprogram-template#weapp-vite-tresjs my-project
手动集成
安装
pnpm i @minisheep/platform-adapter-integration
使用
然后在 vite
的配置文件中添加以下内容:
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(),
vue({
...templateCompilerOptions,
}),
],
})
然后使用包导出的 mountTresApp
方法将你使用 tresjs
编写的场景组件挂载到画布上。
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)
// ...
});
相关函数声明如下。
import type { App, RendererElement } from 'vue';
export function mountTresApp(
canvas: HTMLCanvasElement,
rootComponent: Component,
rootProps?: Record<string, unknown> | null
): App<RendererElement>
需要注意的是,挂载的场景组件需要满足如下要求:
- 只有一个
TresCanvas
根节点 - 禁止包含其他小程序元素
例如:
<template>
<TresCanvas clear-color="#82DBC5" shadows alpha window-size>
<!-- 场景内容 -->
</TresCanvas>
</template>
完整的代码你可以参考此模板。
在 uni-app
中使用
在 uni-app
中集成 tresjs
会稍显复杂, 原因在于 uni-app
构建小程序时使用的是一个经过特殊处理的 Vue 版本(详见 @dcloudio/uni-mp-vue),该版本移除了 @vue/runtime-core
中的多个导出项。
而 tresjs
是基于被移除的 createRenderer
构建的,因此,除了基本配置外,还需要额外处理,才能使其在 uni-app
中正常工作。
将 tresjs
组件专门存放
首先,你需要为基于 tresjs
开发的组件单独定义一个目录。
接着在 uni
插件的处理逻辑中排除该目录,以确保这些组件可以访问标准的 Vue 运行时,而非 uni
定制的版本。
在 vite.config.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";
// 匹配组件的 pattern
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
}),
// ⬇️ 这会使 pattern 匹配到的文件能够使用标准的 vue 导出
useStandardVuePlugin({
include: [
tresjsComponentPattern
]
})
],
})
然后像之前一样将组件通过 mountTresApp
挂载到画布上即可。
模板中的配置还处理了一些兼容和分包问题,详细配置你可以参考它。
强制覆盖依赖版本
由于 uni-app
相关插件固定依赖了 @vue/shared
某个版本, 可能会与 @tresjs/core
依赖的 @vue/shared
版本出现不一致的情况,为避免重复导入以及出现非预期问题, 可以通过配置强制统一版本。
你需要在 package.json
增加以下内容, 具体版本号可以根据你安装的 @tresjs/core
所依赖的 vue
版本决定
{
"pnpm": {
"overrides": {
"@vue/shared": "^x.x.xx"
}
}
}
{
"overrides": {
"@vue/shared": "^3.5.13"
}
}
{
"resolutions": {
"@vue/shared": "^3.5.13"
}
}
额外处理
由于 trejs
目前的 Event System
在触摸设备上运行是有缺陷的,需要等待后续的 pull 被合并才可能会解决。
具体表现是光线投射的目标元素只会根据 pointermove
事件进行更新,导致单一点击相关事件(click,pointer-down,pointer-up等)不能在正确的元素上触发。
你需要手动进行如下处理:
- 每次在传递
touchstart
事件之前需要手动复制并修改type
为touchmove
,然后传递一次。参考如下代码:
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)
};
},
})
<view class="page-container">
<canvas
type="webgl2"
id="tresjs_demo"
bindtouchstart="defaultHandler"
bindtouchmove="defaultHandler"
bindtouchcancel="defaultHandler"
bindtouchend="defaultHandler"
bindtap="defaultHandler"
>
</canvas>
</view>