threlte logo
@threlte/extras

useGltf

A Hook to load glTF files and use separate object nodes and materials of it.

Use the component <GLTF> if you want to use a model in its entirety.

<script lang="ts">
  import { Canvas } from '@threlte/core'
  import Scene from './Scene.svelte'
</script>

<div>
  <Canvas>
    <Scene />
  </Canvas>
</div>

<style>
  div {
    height: 100%;
  }
</style>
<script lang="ts">
  import { T, useThrelte } from '@threlte/core'
  import { OrbitControls } from '@threlte/extras'
  import { Color } from 'three'
  import Tokyo from './Tokyo.svelte'

  const { scene } = useThrelte()
  scene.background = new Color(0xeae8e2)

  let showTokyo = true
</script>

<svelte:window
  on:keypress={() => {
    showTokyo = !showTokyo
  }}
/>

<T.PerspectiveCamera
  makeDefault
  position={[600, 200, 600]}
  near={10}
  far={10000}
>
  <OrbitControls
    autoRotate
    autoRotateSpeed={0.2}
    enableDamping
    enableZoom={false}
    target={[-60, -75, 0]}
  />
</T.PerspectiveCamera>

<T.AmbientLight />
<T.DirectionalLight position={[5, 10, 5]} />

{#if showTokyo}
  <Tokyo />
{/if}
<script lang="ts">
  import { GLTF, useGltfAnimations } from '@threlte/extras'

  const { gltf, actions } = useGltfAnimations<'Take 001'>()

  $: $actions['Take 001']?.play()
</script>

<GLTF
  bind:gltf={$gltf}
  url="/models/LittlestTokyo.glb"
  useDraco="https://www.gstatic.com/draco/v1/decoders/"
/>
<script lang="ts">
  import { Canvas } from '@threlte/core'
  import Scene from './Scene.svelte'
</script>

<div>
  <Canvas>
    <Scene />
  </Canvas>
</div>

<style>
  div {
    height: 100%;
  }
</style>
<script lang="ts">
  import { T, useTask } from '@threlte/core'
  import { Environment, useGltf } from '@threlte/extras'
  import type { Material, Object3D } from 'three'

  let rotation = 0
  useTask((delta) => {
    const f = 1 / 60 / delta // ~1 at 60fps
    rotation += 0.005 * f
  })

  const gltf = useGltf<{
    nodes: {
      'node_damagedHelmet_-6514': Object3D
    }
    materials: {
      Material_MR: Material
    }
  }>('/models/helmet/DamagedHelmet.gltf')
</script>

<Environment
  path="/hdr/"
  files="shanghai_riverside_1k.hdr"
/>

<T.PerspectiveCamera
  makeDefault
  position.z={10}
  fov={20}
/>

<T.DirectionalLight
  position.y={10}
  position.z={10}
/>

<T.Group rotation.y={rotation}>
  {#await gltf}
    <!-- Place loading placeholder here -->
  {:then value}
    <T is={value.nodes['node_damagedHelmet_-6514']} />
  {/await}
</T.Group>

Model: Battle Damaged Sci-fi Helmet by theblueturtle_

Examples

Basic Example

gltf is a store which gets populated as soon as the model loaded.

<script lang="ts">
  import { T } from '@threlte/core'
  import { useGltf } from '@threlte/extras'
  import { MeshBasicMaterial } from 'three'

  const gltf = useGltf('/path/to/model.glb')
</script>

<!-- Use an object node entirely -->
{#if $gltf}
  <T is={$gltf.nodes['node-name']} />
{/if}

<!-- or only the geometry -->
{#if $gltf}
  <T.Mesh
    geometry={$gltf.nodes['node-name'].geometry}
    material={new MeshBasicMaterial()}
  />
{/if}

DRACO decoding

Use a DRACO decoder for compressed glTF files, defaults to CDN loaded DRACO binaries.

import { useGltf } from '@threlte/extras'

const gltf = useGltf('/path/to/model.glb', {
  useDraco: true
})

You can set a custom path to DRACO decoder binaries.

import { useGltf } from '@threlte/extras'

const gltf = useGltf('/path/to/model.glb', {
  useDraco: '/custom/draco/decoders/path'
})

You can also provide your own instance of DRACOLoader

import { useGltf } from '@threlte/extras'

const myLoader = new DRACOLoader().setDecoderPath(path)

const gltf = useGltf('/path/to/model.glb', {
  useDraco: myLoader
})

Meshopt decoding

Use a meshopt decoder for compressed glTF files, defaults to Three’s included decoder.

import { useGltf } from '@threlte/extras'

const gltf = useGltf('/path/to/model.glb', {
  useMeshopt: true
})

Nodes and Materials

The hook provides a map of all objects and materials in the loaded glTF.

<script lang="ts">
  import { useGltf } from '@threlte/extras'

  const gltf = useGltf('/path/to/model.glb')
  $: nodes: $gltf?.nodes
  $: materials: $gltf?.materials
</script>

Provide types and you will gain autocompletion for these objects and materials.

<script lang="ts">
  import { useGltf } from '@threlte/extras'

  const gltf = useGltf<{
    nodes: {
      MeshA: THREE.Mesh
      MeshB: THREE.Mesh
      Object3DA: THREE.Object3D
    }
    materials: {
      MaterialA: THREE.MeshStandardMaterial
      MaterialB: THREE.MeshBasicMaterial
    }
  }>('/path/to/model.glb')

  $: if ($gltf) {
    const objectA = $gltf.nodes['MeshA'] // -> THREE.Mesh
    const materialA = $gltf.materials['MaterialA'] // -> THREE.MeshStandardMaterial
  }
</script>

How to get the types?

On the loading-assets page, Threlte provides the @threlte/gltf CLI tool that can be used to generate a reusable Svelte component for your gltf as well as its types.

Types can be separated into a typescript file and imported like so if you feel the need.

SomeGltf.ts
export type SomeGltf = {
  nodes: {
    Suzanne: THREE.Mesh
  }
  materials: {}
}
MyComponent.svelte
<script lang="ts">
  import { useGltf } from '@threlte/extras'
  import type { SomeGltf } from './SomeGltf.ts'

  useGltf<SomeGltf>('model.glb')
</script>