Skip to content

GLTFJSX

Video Lecture

Section Video Links
GLTFJSX : Part 1 GLTFJSX : Part 1 GLTFJSX : Part 1
GLTFJSX : Part 2 GLTFJSX : Part 2 GLTFJSX : Part 2

Description

GLTFJSX is a command line tool that will read through a glTF model, and extract its components into a JSX equivalent.

When each of the components of the model are referenced using JSX it makes it easier to turn the different components on or off or add even more interaction to each.

GLTFJSX is beneficial if your model is quite large and contains many child meshes, lights, materials, animations, etc., and you want to access those individual components within your code to add interactivity, or even only use parts of the original file.

GLTFJSX is not the only way to traverse a model and extract its components for individual use, but it does make it quick and easy to have the JSX automatically created for you.

Resources

The shoe model used in the lesson originally came from the pushmatrix glTF-Sample-Models repository at https://github.com/pushmatrix/glTF-Sample-Models/tree/master/2.0/MaterialsVariantsShoe.

Download shoe-draco.zip and save it into your projects ./public/models/ folder.

After downloading the file and saving it to the correct folder, we will create some JSX from it using the command,

npx gltfjsx ./public/models/shoe-draco.glb

Error

When using GLTFJSX, you may see the error,

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11118:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

You may have an older version cached. You can try to run the latest version using this command.

npx gltfjsx@latest ./public/models/shoe-draco.glb

./src/App.jsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { Canvas } from '@react-three/fiber'
import { OrbitControls, Environment, ContactShadows } from '@react-three/drei'
import { Model } from './Shoe'

export default function App() {
  return (
    <Canvas shadows camera={{ position: [0, 0, 1.66] }}>
      <Environment preset="forest" />
      <Model />
      <ContactShadows position={[0, -0.8, 0]} color="#ffffff" />
      <OrbitControls autoRotate />
    </Canvas>
  )
}

./src/Shoe.jsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { useEffect, useState } from 'react'
import { useGLTF } from '@react-three/drei'
import { useControls } from 'leva'
import { Color } from 'three'

export function Model() {
  const [hovered, setHovered] = useState(false)
  const { nodes, materials } = useGLTF('/models/shoe-draco.glb')

  useEffect(() => {
    document.body.style.cursor = hovered ? 'pointer' : 'auto'
  }, [hovered])

  useControls('Shoe', () => {
    console.log('creating color pickers')

    // using forEach
    // const colorPickers = {}
    // Object.keys(materials).forEach((m) => {
    //   colorPickers[m] = {
    //     value: '#' + ((Math.random() * 0xffffff) << 0).toString(16).padStart(6, '0'),
    //     onChange: (v) => {
    //       materials[m].color = new Color(v)
    //     }
    //   }
    // })
    // return colorPickers

    // using reduce
    return Object.keys(materials).reduce(
      (acc, m) =>
        Object.assign(acc, {
          [m]: {
            value:
              '#' +
              ((Math.random() * 0xffffff) << 0).toString(16).padStart(6, '0'),
            onChange: (v) => {
              materials[m].color = new Color(v)
            },
          },
        }),
      {}
    )
  })

  // JSX of glTF created using the command
  // npx gltfjsx .\public\models\shoe-draco.glb

  return (
    <group
      dispose={null}
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}
      onClick={(e) => {
        e.stopPropagation()
        document.getElementById('Shoe.' + e.object.material.name).focus()
      }}
    >
      <mesh geometry={nodes.shoe.geometry} material={materials.laces} />
      <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh} />
      <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} />
      <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} />
      <mesh geometry={nodes.shoe_4.geometry} material={materials.sole} />
      <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes} />
      <mesh geometry={nodes.shoe_6.geometry} material={materials.band} />
      <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} />
    </group>
  )
}

useGLTF.preload('./models/shoe-draco.glb')

Compression

Another benefit of the GLTFJSX tool is that it can compress a large glTF file quickly and effectively. Use the -T option. E.g.,

npx gltfjsx ./my-very-large-gltf-file.glb -T

This will compress the geometry and textures using various algorithms. I used this tool to compress the house model from my House example from 9Mb to 1.5Mb.

Troubleshooting

Error : ENOENT: no such file or directory, lstat

When running npx commands, you may get an error stating that it cannot find lstat.

Open a command/bash/powershell prompt and run

npm install -g npm

Working Example

<>
GLTFJSX (Working Example) sbedit.net
GLTFJSX github.com/pmndrs
glTF Sample Models github.com/pushmatrix
R3F Shoe Configurator codesandbox.io

GitHub Branch

git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout gltfjsx
npm install
npm start

Comments