Search code examples
reactjsnext.js3dgltfreact-three-drei

nextjs & @react-three/drei - TypeError: Failed to parse URL


I'm building a nextjs app with 3D animations using @react-three/drei.

I have a gltf file in the public folder, under the desktop_pc folder called scene. gltf.

The path from the project root is: /public/desktop_pc/scene.gltf.

When importing the gltf file into the useGLTF hook, I'm getting the error:

TypeError: Failed to parse URL from /desktop_pc/scene.gltf

Github Repository - nextjs & @react-three/drei - TypeError: Failed to parse URL

This is the component code:

import { useGLTF } from "@react-three/drei";
import React from "react";

const Computers = () => {
  const computer = useGLTF("/desktop_pc/scene.gltf");
  return <div>Computers</div>;
};

export default Computers;

These are my attempts so far (The links leads to the GitHub solution of them):

  1. Dynamic import - https://github.com/ItayTur/Portfolio/tree/invalid-url-error-dynamic-solution
  2. Lazy import - https://github.com/ItayTur/Portfolio/tree/invalid-url-error-lazy-solution
  3. Installing the Three & three-stdlib npm packages.
  4. Specify the exact path from the component to the file location.
  5. Adding a dot at the start of the path string.

Solution

  • Solution:

    1. Download three and react-three-fiber packages.
    2. Use the @react-three/fiber hook: useLoader.
    • NOT useGLTF from @react-three/drei
    1. Wrap the GLTF model component with a Canvas component.
    import { Canvas } from "@react-three/fiber";
    import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
    import { useLoader } from "@react-three/fiber";
    
    const Computers = ({ isMobile = false }) => {
      const gltf = useLoader(GLTFLoader, "/desktop_pc/scene.gltf");
    
      return (
        <group>
          <primitive
            scale={isMobile ? 0.7 : 0.75}
            position={isMobile ? [0, -3, -2.2] : [0, -3.25, -1.5]}
            rotation={[-0.01, -0.2, -0.1]}
            object={gltf.scene}
          />
        </group>
      );
    };
    
    const ComputersCanvas = () => {
      return (
        <Canvas>
          <Computers />
        </Canvas>
      );
    };
    
    export default ComputersCanvas;
    
    1. Use as any other component
    const Hero = () => {
      return (
        <section className={`relative w-full h-screen mx-auto`}
          <ComputersCanvas />
        </section>
      );
    };
    
    export default Hero;
    }
    

    GitHub Links:

    1. First working commit
    2. Full PR