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, but .gltf
s are usually the best fit for the web. You can use Three.js’ 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.
useGltf
hook
@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 and resusing models
You may run into the following challenges 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. - 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 reuse it as much as you’d like.
Animations
Three.js uses AnimationMixer to drive animations. Threlte provides a convenient useGltfAnimations hook for gltfs. See the animation Three.js example for how to setup a model for your animation needs.
The Threlte docs also have an animation example to help you get started.
Common mistakes
Sometimes you’ll load a model and still just see a blank screen. Here are a few common mistakes that can cause this.
- Make sure your scene has lights.
- Make sure the model is not too small or not too big for your camera to see it.
- Make sure your camera is looking at the model
- Does the model render in a viewer like gltf-viewer?
Textures
The TextureLoader
is another loader from Three.js 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}
useTexture
hook
@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 multiple textures to different mesh faces
To declaratively apply different textures to multiple 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>
Other asset types
Threlte provides many components to help get started with many other asset types (like audio), but it doesn’t have components and hooks for all of them. Checkout Three.js examples to see what models, techniques and effects you can achieve, 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 a Svelte #await
block:
{#await $texture then value}
<T.MeshStandardMaterial map={value} />
{/await}
Assets can also be loaded after initialization by calling the loader.load
method:
<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>
The Suspense component can additionally help orchestrate loading multiple assets before displaying your scene.
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.