pmndrs / gltfjsx

🎮 Turns GLTFs into JSX components
https://gltf.pmnd.rs
MIT License
4.73k stars 312 forks source link

Adding bones and animation to generated GLTF from FBX #50

Closed enijar closed 3 years ago

enijar commented 3 years ago

Appologies if this is the wrong place to ask this, but I'm a bit stuck.

I have a situation where I have many GLTF files that use the same bones and animations, so I have explored the bones and animations as an FBX file to save space (instead of duplicating the animations and bones across all my GLTF files).

I tried to follow this approach but that only uses a GLTF file.

Is it possible to do this?

My code looks something like this:

function Avatar({ settings = {}, ...props }) {
  const group = React.useRef();
  const actions = React.useRef();
  const [mixer] = React.useState(() => new THREE.AnimationMixer());
  const { animations } = useFBX("/assets/models/walk-animation.fbx");
  const { nodes, materials } = useGLTF("/assets/models/avatar.glb");

  useFrame((state, delta) => mixer.update(delta));

  // I'd like to load the animations and bones from FBX and have it applied to GLTF
  React.useEffect(() => {
    actions.current = {
      walk: mixer.clipAction(animations[0], group.current),
    };
    return () => animations.forEach((clip) => mixer.uncacheClip(clip));
  }, [animations, actions, mixer, group]);

  React.useEffect(() => {
    materials.Hair.color.set(settings.hairColor);
    materials["Hair.001"].color.set(settings.hairColor);
    materials.top.color.set(settings.topColor);
    materials.skin.color.set(settings.skinColor);
    materials.eyes.color.set(settings.eyesColor);
    materials.mouth.color.set(settings.mouthColor);
  }, [materials, settings]);

  React.useEffect(() => {
    actions.current.walk[settings.playWalk ? "play" : "stop"]();
  }, [settings, actions]);

  return (
    <group ref={group} {...props} dispose={null}>
      <mesh
        visible={settings.hairStyle === 1}
        material={materials.Hair}
        geometry={nodes.big_hair.geometry}
        position={[0, 1.56, 0]}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        visible={settings.hairStyle === 2}
        material={materials.Hair}
        geometry={nodes.hair.geometry}
        position={[0, 1.56, 0]}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials["Hair.001"]}
        geometry={nodes.eye_brows.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials.top}
        geometry={nodes.top.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials.Shorts}
        geometry={nodes.shorts.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials.Shoes}
        geometry={nodes.shoes.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials.skin}
        geometry={nodes.skin.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials.mouth}
        geometry={nodes.mouth.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
      <mesh
        material={materials.eyes}
        geometry={nodes.eyes.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />
    </group>
  );
}
drcmda commented 3 years ago

i think meshes must be skinnedmeshes and materials must have the skinned prop or it cant work.

<skinnedMesh
        material={materials.skin}
        material-skinned
        geometry={nodes.skin.geometry}
        rotation={[Math.PI / 2, 0, 0]}
        scale={[0.01, 0.01, 0.01]}
      />

but i don't know much about skinning. just make sure you are working with the exact same setup you would work with if that were plain threejs.