Reputation: 101
How to load a model GLTF model in next.js?
I spend hours looking for this. Nothing works :(
What I tried so far:
useLoader(GLTFLoader,url) / useGLTF(url) and some more
next/dynamic
component / dont do itsuspense
not beeing support by installing next with react 18three-stdlib
next.config.js
read every issue and forum post i could find on tis issue
The error i get at the moment is:
Server Error
Error: Could not load <url> response.body.getReader is not a function
with a component looking like this:
import React from 'react'
import { useGLTF } from '@react-three/drei'
import { Canvas, } from '@react-three/fiber'
import { Suspense } from 'react/cjs/react.production.min';
export default function Spinner({ ...props }) {
const model = useGLTF("http://localhost:3000/spinner.glb")
return (
<Suspense fallback={"loading"}>
<Canvas
camera={{ position: [1, 1, 1] }}
>
<primitive object={model.scene} />
<color attach="background" args={["hotpink"]} />
</Canvas>
</Suspense>
)
}
package.json:
},
"dependencies": {
"@react-three/drei": "^7.27.3",
"@react-three/fiber": "^7.0.21",
"axios": "^0.24.0",
"next": "^12.0.7",
"react": "^18.0.0-beta-24dd07bd2-20211208",
"react-dom": "^18.0.0-beta-24dd07bd2-20211208",
"three": "^0.135.0",
"three-stdlib": "^2.6.1"
},
"devDependencies": {
"eslint": "8.4.1",
"eslint-config-next": "12.0.7",
"file-loader": "^6.2.0"
}
}
node-version:
16 LTS
Upvotes: 4
Views: 6090
Reputation: 305
What worked in my case is :
import React from 'react'
import { useGLTF } from '@react-three/drei'
import Spinner from "@/public/spinner.glb"
export default function Model () {
const glb = useGLTF(Spinner.src)
return (
<primitive object={model.scene} />
)
}
Upvotes: -1
Reputation: 39
In nextJS you don't need to use the suspense component. Use the useTexture hook from @react-three/drei instead of loading using useLoader.
This example code loads the model with texture.
import React from "react";
import { useTexture } from "@react-three/drei";
function Box() {
const colorMap = useTexture("/img/robot.png");
return (
<mesh rotation={[90, 0, 20]}>
<boxBufferGeometry attach="geometry" args={[2, 2, 2]} />
<meshNormalMaterial attach="material" />
</mesh>
);
}
export default Box;
Upvotes: 0
Reputation: 156
Wrapping your Model component with the parent and using lazy import solves the issue, e.g.
Model component
import React from 'react'
import { useGLTF } from '@react-three/drei'
export default function Model() {
const model = useGLTF("http://localhost:3000/spinner.glb")
return (
<primitive object={model.scene} />
)
}
Scene component with lazy() import
import { lazy, Suspense } from 'react'
import { Canvas, } from '@react-three/fiber'
const ModelComponent = lazy(() => import("./model"));
export default function Spinner({ ...props }) {
return (
<Suspense fallback={"loading"}>
<Canvas
camera={{ position: [1, 1, 1] }}
>
<ModelComponent />
<color attach="background" args={["hotpink"]} />
</Canvas>
</Suspense>
)
}
This seems to be related to SSR. Similar problems are with TextureLoaders in Next and was having similar hard time to fix it and eventually found that solution with lazy() import. I had just tried that for the model load and it works fine. Can't track this original thread right now, but will try to track and add it here.
Upvotes: 10