Basics
Loading Assets
There are a number of different asset types you might like to use in your Threlte application. Three.js has a ton of different loaders that Threlte integrates well with. You’re recommended to use the useLoader hook which will cache any asset it loads and wrap the asset in an asyncWritable for convenience. Caching assets will reduce network requests, bandwidth, and memory usage, which will improve the performance of your application.
This section assumes you placed your assets in your public folder or in a place in your application where you can import them easily.
Models
Models come in many different formats. For example, .gltf
’s are mostly json files. You can use three’s GLTFLoader
to load a .gltf
model.
<script>
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { useLoader } from '@threlte/core'
const gltf = useLoader(GLTFLoader).load('/assets/model.gltf')
</script>
{#if $gltf}
<T is={$gltf.scene} />
{/if}
The <GLTF/>
component is roughly equivalent to the example above.
Convenient: useGltf
@threlte/extras
provides a handy hook for loading .gltf
models called useGltf:
<script>
import { useGltf } from '@threlte/extras'
</script>
{#await useGltf('/assets/model.gltf') then gltf}
<T is={gltf.scene} />
{/await}
Adjusting Parts and Multiple Copies
There are some challenges you’ll probably run into when working with models in Threlte:
- Your model may have multiple parts that you’d like to adjust individually but there’s no easy way to declaritively achieve that with only one
<T/>
component. - The model is cached which is great but you can’t seem to place multiple copies in your scene.
To address both of these issues, you can use Threlte’s CLI tool @threlte/gltf to generate a svelte component for your model. The generated component has <T/>
components for all of your models parts. Adjust the component to your liking, then import and reused it as much as you’d like.
Animations
Three.js uses AnimationMixer to drive animations. Threlte provides a convenient useGltfAnimations hook for gltf’s. See the three.js examples for how to setup a model for your animation needs.
Threlte has a few animation examples to help you get started.
Textures
The TextureLoader
is another loader from three that is used for textures.
<script>
import { TextureLoader } from 'three'
import { useLoader } from '@threlte/core'
const texture = useLoader(TextureLoader).load('/assets/texture.png')
</script>
{#if $texture}
<T.MeshStandardMaterial map={$texture} />
{/if}
Convenient: useTexture
@threlte/extras
provides a handy hook for loading textures called useTexture:
<script>
import { useTexture } from '@threlte/extras'
</script>
{#await useTexture('/assets/texture.png') then texture}
<T.MeshStandardMaterial map={texture} />
{/await}
Multiple textures
Sometimes you’ll want your materials to be composed of multiple textures. useLoader
provides a way to load multiple textures at once and spread the loaded textures on a material.
Loading two textures for the map
and normalMap
channels can be done like this:
const textures = useLoader(TextureLoader).load({
map: '/assets/texture.png',
normalMap: '/assets/normal.png'
})
or with the useTexture
hook:
const textures = useTexture({
map: '/assets/texture.png',
normalMap: '/assets/normal.png'
})
Then spread on a material:
{#if $textures}
<T.MeshStandardMaterial {...$textures} />
{/if}
If multiple textures are given, the promise only resolves once all textures have loaded.
Applying different textures to different faces
To declaratively apply two different textures to two different faces of a BoxGeometry
, set the attach
prop to a function.
<T.Mesh>
<T.BoxGeometry />
<T.MeshStandardMaterial
map={texture1}
attach={({ parent, ref }) => {
if (Array.isArray(parent.material)) parent.material = [...parent.material, ref]
else parent.material = [ref]
}}
/>
<T.MeshStandardMaterial
map={texture2}
attach={({ parent, ref }) => {
if (Array.isArray(parent.material)) parent.material = [...parent.material, ref]
else parent.material = [ref]
}}
/>
</T.Mesh>
Alternatively, mix declarative and normal three.js code like so for the same result:
<script>
// imports and other code
const customMaterials = [
new MeshStandardMaterial({ map: texture1 }),
new MeshStandardMaterial({ map: texture2 })
]
</script>
<T.Mesh>
<T.BoxGeometry />
<T
is={customMaterials}
attach="material"
/>
</T.Mesh>
Other Assets
Threlte provides many components to help get started with other assets (like audio) but we don’t have convenient components and hooks for all of them yet. Checkout three.js examples to see what models, techniques and effects you can acheive, then use those examples as a guide for your own custom components.
Async Loading
The return value from useLoader is an AsyncWritable
custom store. Its value will be undefined
until the asset has loaded.
Since the underlying store’s value is a promise, you can use it within svelte’s await blocks:
{#await $texture then value}
<T.MeshStandardMaterial map={value} />
{/await}
These hooks can be used similarly to Svelte’s onMount
hook however assets can also be loaded after initialization by separating out the load call:
<script>
import { AudioLoader } from 'three'
import { useLoader } from '@threlte/core'
// Instantiate the loader at component initialization
const loader = useLoader(AudioLoader)
const onSomeEvent = async () => {
// Load the asset when needed
const audioBuffer = await loader.load('/assets/sound.mp3')
}
</script>
Another set of tools to help orchestrate loading multiple assets before displaying something is the suspense component and hooks.
Context Awareness
The useLoader
hook, and other hooks like useTexture
, use svelte contexts. The assets loaded with them are only available for child components of your <Canvas>
component.