Vue 3 Composition API te permite crear lógica reutilizable que se puede compartir entre los componentes. También te permite crear hooks personalizados que puede ser usado en tus componentes.
TresJS aprovecha mucho está API para crear un grupo de funciones composables que se pueden usar para crear animaciones, interactuar con la escena y más. También te permite crear escenas más complejas que podrían no ser posible solo usando los componentes de Vue (Textures, Loaders, etc.).
El core de TresJS usa estos composables internalmente, entonces estarías usando el mismo API que usa el core. Por ejemplo, componentes que se necesitan actualizar en el render loop internal usa el composable useRenderLoop
para registrar un callback que se llamará cada vez el renderer actualiza la escena.
El composable useRenderLoop
es el core de los animaciones de TresJS. Te permite registrar un callback que se llamará en el ritmo nativo de actualizar. Esto es el composable más importante de TresJS.
const { onLoop, resume } = useRenderLoop()
onLoop(({ delta, elapsed, clock, dt }) => {
// I will run at every frame ~ 60FPS (depending of your monitor)
})
::: precaución Está consciente de la implicación sobre el rendimiento de usar est composable. Se funcionará a cada frame, entonces si tienes mucha lógica en tu callback, podría impactar el rendimiento de tu app. Especialmente si estás actualizando los estados reactivos o las referencias. :::
El callback onLoop
recibe un objeto con las propiedades siguientes en base del THREE clock:
delta
: El delta tiempo entre el frame actual y frame final. Esto es el tiempo en segundos desde el frame ultimo.
elapsed
: El tiempo transcurrido desde cuando comenzó el render loop.
Este composable se base en useRafFn
de vueuse. Gracias a @wheatjs por la contribución increíble.
También puedes registrar un callback que se llamará antes y después el renderer actualiza la escena. Eso es útil si añades un profiler para medir el FPS por ejemplo.
const { onBeforeLoop, onAfterLoop } = useRenderLoop()
onBeforeLoop(({ delta, elapsed }) => {
// I will run before the renderer updates the scene
fps.begin()
})
onAfterLoop(({ delta, elapsed }) => {
// I will run after the renderer updates the scene
fps.end()
})
Puedes pausar y continuar el render loop usando los metodos expuestos de pause
y resume
.
const { pause, resume } = useRenderLoop()
// Pause the render loop
pause()
// Resume the render loop
resume()
También puedes conseguir el estado activo del render loop usando la propiedad isActive
.
const { resume, isActive } = useRenderLoop()
console.log(isActive) // false
resume()
console.log(isActive) // true
El composable useLoader
te permite cargar recursos usando el THREE.js loaders. Se desvuelve una promesa con recurso cargado.
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
const { scene } = await useLoader(THREE.GLTFLoader, 'path/to/asset.gltf')
Desde el composable useLoader
se desvuelve una promesa, puedes usarlo con un async/await
o then/catch
. Si estás usándolo en un componente, te aseguras de que es 'wrapped' con un componente Suspense
. Ve Suspense para más información.
<template>
<Suspense>
<TheComponentUsingLoader />
</Suspense>
</template>
El composable useTexture
te permite cargar texturas usando el THREE.js texture loader. Se desvuelve una promesa con uno o más texturas cargadas.
const texture = await useTexture(['path/to/texture.png'])
También useTexture se acepta un objeto con las propiedades siguientes:
map
:una textura básica que se aplica al superficie de un objeto.displacementMap
: una textura que se usa para añadir protuberancias o abolladuras al superficie del objeto.normalMap
: una textura que se usa para añadir detalles superficiales y variaciones de tonalidad al objeto.roughnessMap
: una textura que se usa para añadir rugosidad o una terminación mate al superficie del objeto.metalnessMap
: una textura que se usa para añadir un efecto metálico al superficie del objeto.aoMap
: una textura que se usa para añadir oclusión ambiental (tonalidad en zonas donde la luz se bloquea por otros objetos) al objeto.En este caso, se desvuelve un objeto con las texturas cargadas.
const { map, displacementMap, normalMap, roughnessMap, metalnessMap, aoMap } = 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',
})
Puedes atar las texturas al material.
<template>
<TresMesh>
<TresMeshSphereGeometry />
<TresMeshStandardMaterial
:map="map"
:displacementMap="displacementMap"
:normalMap="normalMap"
:roughnessMap="roughnessMap"
:metalnessMap="metalnessMap"
:aoMap="aoMap"
/>
</TresMesh>
</template>
Similar al composable arriba, el composable useTexture
se desvuelve una promesa puedes usarlo con async/await
o then/catch
. Si estás usándolo con un componente, te aseguras de que es 'wrapped' con un componente Suspense
.
El composable useCatalogue
te permite extender el catálogo internal de componentes. Se desvuelve una función que puedes usar a registrar componentes nuevos.
Esto es especialmente útil si quieres usar objetos que no son parte del ThreeJS core como OrbitControls o funcionalidad externa, como física.
import { useCatalogue } from '@tresjs/core'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
const { extend } = useCatalogue()
extend({ OrbitControls })
Puedes usar el componente nuevo en tu plantilla. Nota que el nuevo componente se prefije con Tres
para evitar colisiones de nombres con elementos nativos de HTML , similar al resto de los core components.
<template>
<TresCanvas shadows alpha>
<TresScene>
<TresOrbitControls v-if="state.renderer" :args="[state.camera, state.renderer?.domElement]" />
</TresScene>
</TresCanvas>
</template>
Este composable intenta proveer acceso al modelo estado que se contiene el renderer por defacto, la cámara, la escena, y otras propiedades útiles. Todavía es experimental y no se recomienda que lo usas en producción porque hay un probabilidad alto que va a cambiar.
const { state } = useTres()
console.log(state.camera) // THREE.PerspectiveCamera
console.log(state.renderer) // THREE.WebGLRenderer
Hasta que este composable es estable, se recomienda que usas el provide/inject
API para acceder a los elementos que necesitas. Estos son los llaves disponibles:
camera
: se desvuelve la cámara activa actualrenderer
: se desvuelve el renderer activo actuallocal-scene
: se desvuelve la escena activa actualcatalogue
: se desvuelve el catálogo activo actual de componentesextend
: se desvuelve la función extend
del composable useCatalogue
. Especialmente necesario si eres autor de un plugin.aspect-ratio
: se desvuelve relación de aspecto actual del canvas
import { provide, inject } from 'vue'
const camera = inject<Ref<Camera>>('camera')
const renderer = inject<Ref<WebGLRenderer>>('renderer')
console.log(camera.value) // THREE.PerspectiveCamera
console.log(renderer.value) // THREE.WebGLRenderer