After GLB file load, App starts taking more than 2GB of RAM on Chrome

I am using $ npx gltfjsx model.gltf command to turn GLTF assets into dynamic, re-usable react-three-fiber JSX components, but when the model and animations are loaded it starts taking almost 2GB of RAM on Chrome. My whole project starts lagging because of this. If anybody knows what I am doing wrong please help. Thank you.
Reference: https://github.com/pmndrs/gltfjsx

import React, { useRef, useState, useEffect, useLayoutEffect } from 'react'
import { useLoader, useFrame} from 'react-three-fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import {TWEEN} from 'three/examples/jsm/libs/tween.module.min';


export default function Model(props) {
  const group = useRef()
  const { nodes, materials, animations } = useLoader(GLTFLoader, './GLTF/car1/car1.gltf')
  const actions = useRef()
  const [mixer] = useState(() => new THREE.AnimationMixer())
  const [tween, setTween] = useState(false);
  const [loaded, setLoaded] = useState(false);
  const [animStatus, SetAnimStatus] = useState(false);

  useFrame((state, delta) => {
    mixer.update(delta);
    if(tween){
      TWEEN.update();
    }
  })

  useEffect(() => {
  console.log("Use Effect Car");
  if(!loaded)
    {
      setLoaded(true);
      console.log("ModelLoaded");
      if(props.OnLoadedModel != null && !loaded)props.OnLoadedModel();
      group.current.children[1].material.side = THREE.FrontSide
      group.current.children[1].material.roughness = 0.06;
      group.current.children[1].material.metalness = 0;
      group.current.children[1].material.color = new THREE.Color( 0xffffff );
      
      group.current.children[2].material.side = THREE.FrontSide
      group.current.children[2].material.roughness = 0.08;
      group.current.children[2].material.metalness = 1;
      
      group.current.children[3].material.side = THREE.FrontSide
      group.current.children[3].material.roughness = 0.73;
      group.current.children[3].material.metalness = 1;
     
      group.current.children[4].material.side = THREE.FrontSide
      group.current.children[4].material.roughness = 0;
      group.current.children[4].material.metalness = 1;
      group.current.children[4].material.transparent = true;
      group.current.children[4].material.opacity = 0.28;
      
      group.current.children[5].material.side = THREE.FrontSide
      group.current.children[5].material.roughness = 0.13;
      group.current.children[5].material.metalness = 1;

      group.current.children[6].material.side = THREE.FrontSide
      group.current.children[6].material.roughness = 0.71;
      group.current.children[6].material.metalness = 1;

      group.current.children[7].material.side = THREE.FrontSide
      group.current.children[7].emissiveIntensity = 3;

      group.current.children[8].material.side = THREE.FrontSide
      group.current.children[8].material.roughness = 0.81;
      group.current.children[8].material.metalness = 0.53;

      group.current.children[9].material.side = THREE.FrontSide
      group.current.children[9].material.roughness = 1;
      group.current.children[9].material.metalness = 0;
      
      group.current.children[10].material.side = THREE.FrontSide
      group.current.children[10].material.roughness = 0.3;
      group.current.children[10].material.metalness = 0.73;

      group.current.children[11].material.side = THREE.FrontSide
      group.current.children[11].material.roughness = 0.8;
      group.current.children[11].material.metalness = 0;
  }
  if(loaded){
    if(props.colorChanged){
      setTween(true);
        console.log("Material Changing")
        let mtl = group.current.children[1].material.color;
        group.current.children[1].material.color = props.color;
        if(props.OnColorChangeComplete != null) props.OnColorChangeComplete();
    }
  }
  mixer.addEventListener( 'finished',(e) => {
    console.log("Mixer event listener")
    if(e.direction === 1){
    if(props.OnAnimationEnd !== null) props.OnAnimationEnd(false);
    SetAnimStatus(true);
    }
    else{
    if(props.OnAnimationEnd !== null) props.OnAnimationEnd(true);
    SetAnimStatus(false);}
  });

  actions.current = {ArmatureAction: mixer.clipAction(animations[0], group.current)}
  if(props.PlayAnimation){
    console.log("Play Animation")
    var animClip = actions.current.ArmatureAction;
    if(props.Direction === true && !animStatus){
      console.log("Playing Forward");
      animClip.time = 0;
      animClip.timeScale =1
      animClip.clampWhenFinished = true;
      animClip.setLoop(THREE.LoopOnce);
      animClip.paused = false;
      animClip.play();
    }
    else if(props.Direction === false && animStatus){
      animClip.timeScale = -1;
      animClip.setLoop(THREE.LoopOnce);      
      animClip.paused = false;
    }
}

})

  return (
    <group ref={group} {...props} dispose={null}>
      <primitive object={nodes.root} />
      <skinnedMesh
        material={materials['Car05_Body01.001']}
        geometry={nodes.Car05_Body_LOD0_0.geometry}
        skeleton={nodes.Car05_Body_LOD0_0.skeleton}
      />
      <skinnedMesh
        material={materials['Car05_Parts01.001']}
        geometry={nodes.Car05_Body_LOD0_1.geometry}
        skeleton={nodes.Car05_Body_LOD0_1.skeleton}
      />
      <skinnedMesh
        material={materials.InteriorBody}
        geometry={nodes.Car05_Body_LOD0_2.geometry}
        skeleton={nodes.Car05_Body_LOD0_2.skeleton}
      />
      <skinnedMesh
        material={materials['Car05_Glass01.001']}
        geometry={nodes.Car05_Body_LOD0_3.geometry}
        skeleton={nodes.Car05_Body_LOD0_3.skeleton}
      />
      <skinnedMesh
        material={materials['Car05_Wheel01.001']}
        geometry={nodes.Car05_Body_LOD0_4.geometry}
        skeleton={nodes.Car05_Body_LOD0_4.skeleton}
      />
      <skinnedMesh
        material={materials['Car05_Grill01.001']}
        geometry={nodes.Car05_Body_LOD0_5.geometry}
        skeleton={nodes.Car05_Body_LOD0_5.skeleton}
      />
      <skinnedMesh
        material={materials['Car05_LightsEmissive.001']}
        geometry={nodes.Car05_Body_LOD0_6.geometry}
        skeleton={nodes.Car05_Body_LOD0_6.skeleton}
      />
      <skinnedMesh
        material={materials.Leather}
        geometry={nodes.Car05_Body_LOD0_7.geometry}
        skeleton={nodes.Car05_Body_LOD0_7.skeleton}
      />
      <skinnedMesh
        material={materials.CarbonFibre}
        geometry={nodes.Car05_Body_LOD0_8.geometry}
        skeleton={nodes.Car05_Body_LOD0_8.skeleton}
      />
      <skinnedMesh
        material={materials.Chrome}
        geometry={nodes.Car05_Body_LOD0_9.geometry}
        skeleton={nodes.Car05_Body_LOD0_9.skeleton}
      />
      <skinnedMesh
        material={materials.SteeringWheel}
        geometry={nodes.Car05_Body_LOD0_10.geometry}
        skeleton={nodes.Car05_Body_LOD0_10.skeleton}
      />
      <skinnedMesh
        material={materials.InteriorBody}
        geometry={nodes.Car05_Body_LOD0_11.geometry}
        skeleton={nodes.Car05_Body_LOD0_11.skeleton}
      />
    </group>
  )
}
1 Like

The memory allocation primarily depends on the size of your asset. Also notice that browsers tend to have in general a high memory footprint.

What is the memory allocation of your app without loading a glTF asset?

Without GLTF asset the memory allocation of my app is 800MB or so. With GLTF it crosses 2000MB.
And my asset alone is 8.68MB.

A 3D model could easily take up much more memory than its actual filesize. For example, PNG textures are uncompressed for the GPU, and objects are inflated into THREE.Mesh and THREE.Object3D instances. You can optimize that, but without access to the model, I can’t tell you whether 2000MB is simply an outcome of the model you’re using, or a problem in project code.

1 Like