I'm using the react-three
package to load gltf files to my react app. However, I noticed that after the app rendered, the 3d model is not autoplaying. At first I thought it's the animation issue but the weird thing is when I scrolled up or down, the model would move just one or two frames and it was very jumpy. Also, when I clicked on the model, it started to animate normally...until not.
I'm scratching my head here to figure out this weird behavior...Can anyone help me with this? Thanks!
DEMO: https://endearing-rugelach-2ca48b.netlify.app/ (The robot model and the floating balls below have the same issue)
Code for the robot model:
import React, { Suspense, useEffect, useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { OrbitControls, Preload, useGLTF } from "@react-three/drei";
import CanvasLoader from "../Loader";
import * as THREE from "three";
const Robot = ({ isMobile }) => {
const { scene, animations } = useGLTF("./robot/scene.gltf");
let mixer = new THREE.AnimationMixer(scene);
animations.forEach((clip) => {
const action = mixer.clipAction(clip);
action.play();
});
useFrame((state, delta) => {
mixer.update(delta);
});
return (
<mesh>
<hemisphereLight intensity={0.15} groundColor="black" />
<spotLight
position={[-20, 50, 10]}
angle={0.12}
penumbra={1}
intensity={1}
castShadow
shadow-mapSize={1024}
/>
<pointLight intensity={1} />
<primitive
object={scene}
dispose={null}
scale={isMobile ? 2 : 1.6}
position={isMobile ? [-10, -6, -2] : [-2, -4, 0]}
rotation={isMobile ? [0, 1.5, 0] : [0, 1.3, 0]}
/>
</mesh>
);
};
const RobotCanvas = () => {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
// Add a listener for changes to the screen size
const mediaQuery = window.matchMedia("(max-width: 450px)");
// Set the initial value of the `isMobile` state variable
setIsMobile(mediaQuery.matches);
// Define a callback function to handle changes to the media query
const handleMediaQueryChange = (event) => {
setIsMobile(event.matches);
};
// Add the callback function as a listener for changes to the media query
mediaQuery.addEventListener("change", handleMediaQueryChange);
// Remove the listener when the component is unmounted
return () => {
mediaQuery.removeEventListener("change", handleMediaQueryChange);
};
}, []);
return (
<Canvas
frameloop="demand"
shadows
dpr={[1, 2]}
camera={{ position: [20, 3, 5], fov: 25 }}
gl={{ preserveDrawingBuffer: true }}
>
<Suspense fallback={<CanvasLoader />}>
<OrbitControls
enableZoom={false}
maxPolarAngle={Math.PI / 2}
minPolarAngle={Math.PI / 2}
/>
<Robot isMobile={isMobile} />
</Suspense>
<Preload all />
</Canvas>
);
};
export default RobotCanvas;
As @Don McCurdy mentioned in the comment, the problem is the line frameloop="demand
. After removing it, the model works great. Hope this is helpful for developers who run into the same issue.