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