# 组合式函数 Vue 3的[Composition API](https://vuejs.org/guide/extras/composition-api-faq.html#what-is-composition-api) 允许您创建可在组件之间共享的可重用逻辑。它还允许您创建可在组件中使用的自定义钩子。 **TresJS** 充分利用这个API创建了一组组合式函数,可用于创建动画、与场景交互等。它还允许您创建更复杂的场景,不仅使用Vue组件(纹理、加载器等)实现。 **TresJS** 核心在内部使用这些组合式函数,因此可以使用与核心相同API。例如,需要在内部渲染循环中更新的组件使用 `useRenderLoop` 来注册一个回调函数,每当渲染器更新场景时都会调用该函数。 ## useRenderLoop `useRenderLoop` 是 **TresJS** 动画的核心。它可以注册一个回调函数,该函数将在原生刷新率下被调用。这是 **TresJS** 中最重要的组合式函数。 ```ts const { onLoop, resume } = useRenderLoop() onLoop(({ delta, elapsed, clock }) => { // 它将在每一帧运行 ~60FPS (取决于您的显示器) }) ``` ::: warning 请注意使用此组合式函数的性能影响。它将在每一帧运行,因此如果在回调中有大量逻辑,可能会影响应用程序的性能。特别是如果您正在更新响应式状态或引用。 ::: `onLoop` 回调接收一个基于[THREE clock](https://threejs.org/docs/?q=clock#api/en/core/Clock)的对象,该对象具有以下属性: - `delta`: 当前帧与上一帧之间的时间差。这是自上一帧以来的时间(以秒为单位)。 - `elapsed`: 自渲染循环开始以来的时间。 这个组合式函数基于 [vueuse](https://vueuse.org/core/useRafFn/) 中的 `useRafFn` 。感谢 [@wheatjs](https://github.com/orgs/Tresjs/people/wheatjs) 的出色贡献 ### 渲染前后 您还可以注册一个在渲染器更新场景之前和之后调用的回调函数。例如,添加了性能分析工具以测量FPS,将非常有用。 ```ts const { onBeforeLoop, onAfterLoop } = useRenderLoop() onBeforeLoop(({ delta, elapsed }) => { // 在渲染器更新场景之前运行 fps.begin() }) onAfterLoop(({ delta, elapsed }) => { // 在渲染器更新场景之后运行 fps.end() }) ``` ### 暂停和恢复 您可以使用 `pause` 和 `resume` 方法来暂停和恢复循环渲染。 ```ts const { pause, resume } = useRenderLoop() // 暂停循环渲染 pause() // 恢复循环渲染 resume() ``` 您还可以使用 `isActive` 属性获取循环渲染的活动状态。 ```ts const { resume, isActive } = useRenderLoop() console.log(isActive) // false resume() console.log(isActive) // true ``` ## useLoader `useLoader` 组合式函数可以使用 [THREE.js loaders](https://threejs.org/docs/#manual/en/introduction/Loading-3D-models) 加载器加载资源。它返回一个带有加载后资源的Promise。 ```ts import { GLTFLoader } from 'three/addons/loaders/GLTFLoader' const { scene } = await useLoader(THREE.GLTFLoader, 'path/to/asset.gltf') ``` 由于 `useLoader` 组合式函数返回一个Promise,您可以使用 `async/await` 或 `then/catch`。如果您在组件上使用它,请确保将其包装在 `Suspense` 组件中。有关更多信息,请参阅[Suspense](https://vuejs.org/guide/built-ins/suspense.html#suspense)。 ```vue ``` ## useTexture `useTexture` 组合式函数可以使用 [THREE.js texture loader](https://threejs.org/docs/#api/en/loaders/TextureLoader) 纹理加载器加载纹理。它返回一个带有已加载纹理的Promise。 ```ts const texture = await useTexture(['path/to/texture.png']) ``` **useTexture** 还可以传入一个包含以下属性的对象: - `map`: 用于物体表面的基本纹理 - `displacementMap`: 用于在物体表面添加凹凸或凹痕的纹理 - `normalMap`: 用于在物体上添加表面细节和阴影变化的纹理 - `roughnessMap`: 用于在物体表面添加粗糙度或哑光效果的纹理 - `metalnessMap`: 用于在物体表面添加金属效果的纹理 - `aoMap`: 用于在物体上添加环境遮蔽(在光被其他物体挡住的区域中添加阴影)的纹理 - `alphaMap`: 用于向物体添加 alpha(黑色部分渲染为透明)的纹理。在材质上使用这个映射,需要设置 `:transparent="true"` - `matcap`: 材质颜色和阴影的纹理编码 在这种情况下,它将返回一个包含已加载纹理的对象。 ```ts const { map, displacementMap, normalMap, roughnessMap, metalnessMap, aoMap, alphaMap, matcap } = await useTexture({ map: 'path/to/albedo.png', displacementMap: 'path/to/height.png', normalMap: 'path/to/normal.png', roughnessMap: 'path/to/roughness.png', metalnessMap: 'path/to/metalness.png', aoMap: 'path/to/ambien-occlusion.png', alphaMap: 'path/to/alpha.png', matcap: 'path/to/matcap.png', }) ``` 然后,可以将纹理绑定到材质上。 ```vue ``` 与上述类似,`useTexture` 组合式函数返回一个Promise,您可以使用 `async/await` 或 `then/catch`。如果您在组件上使用它,请确保将其包装在 `Suspense` 组件中。 ## useSeek `useSeek` 组合式函数提供了一些实用工具,可轻松遍历和浏览复杂的ThreeJS场景和对象子图。它导出了4个函数,允许您根据特定属性查找子对象。 ```ts const { seek, seekByName, seekAll, seekAllByName } = useSeek() ``` `useSeek` 函数接受三个参数: - `parent`: 一个 ThreeJS 场景或 Object3D - `property`: 用于搜索条件的属性 - `value`: 匹配的属性值 `seek` 和 `seekByName` 函数遍历对象并返回具有指定属性和值的子对象。如果找不到具有给定属性和值的子对象,则返回 null 并抛出警告。 ```ts const carRef = ref(null) watch(carRef, ({ model }) => { if (model) { const car = model.children[0] const body = seek(car, 'name', 'Octane_Octane_Body_0') body.color.set(new Color('blue')) } }) ``` 类似地,`seekAll` 和 `seekAllByName` 函数返回一个包含具有指定属性和值的子对象的数组。如果没有找到匹配项,则返回一个空数组,并抛出警告。 ```ts const character = ref(null) watch(character, ({ model }) => { if (model) { const bones = seekAll(character, type, 'Bone') } }) ``` ## useTresContext 这个组合式函数提供对包含多个有用属性的状态模型的访问。 ```ts const { camera, renderer, camera, cameras } = useTresContext() ``` ::: warning `useTresContext` 只能在 `TresCanvas` 内部使用,因为 `TresCanvas` 充当上下文数据的提供者。如果在TresCanvas的父组件中需要上下文,请使用[TresCanvas暴露的上下文](tres-canvas#exposed-public-properties)。 ::: ```vue ``` ```vue // MyModel.vue ``` ### 上下文的属性 | 属性 | 描述 | | --- | --- | | **camera** | 当前激活的相机 | | **cameras** | 场景中存在的相机| | **controls** | 场景控件 | | **deregisterCamera** | 用于取消注册相机的方法。仅在手动创建相机时需要。`template` 中的相机会自动取消注册。 | | **extend** | 扩展组件目录。请查看 [extending](/advanced/extending) | | **raycaster** | 用于鼠标事件的全局光线投射器 | | **registerCamera** | 用于注册相机的方法。只有在手动创建相机时才需要。在 `template` 中,相机会自动注册。 | | **renderer** | 场景中的 [WebGLRenderer](https://threejs.org/docs/#api/en/renderers/WebGLRenderer) | | **scene** | [场景](https://threejs.org/docs/?q=sce#api/en/scenes/Scene) | | **setCameraActive** | 设置当前激活的相机 | | **sizes** | 画布的宽度、高度和宽高比 |