如何在react-three-fiber中提取和播放动画。

8

我有一个.gltf动画模型。我成功加载了模型,但无法播放嵌入的动画。我想知道是否有任何方法可以解决这个问题。顺便说一下,我是在React中开发的。谢谢您提前。

在这里您可以找到该模型 https://drive.google.com/file/d/1ZVyklaQuqKbSliu33hFxdyNpg4EQtcBH/view?usp=sharing

以下是我尝试的代码。

import * as THREE from 'three'
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
import React, { Suspense,useRef, useEffect, useState } from 'react'
import { Canvas ,extend, useThree, useFrame} from 'react-three-fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import './style.module.css'

extend({ OrbitControls })

function Hardware() {
  const [scene, set] = useState()
  useEffect(() => {
  new GLTFLoader().load("tern_construct_animation.gltf", gltf => {
    set(gltf.scene)
    const mixer = new THREE.AnimationMixer(gltf.scene)
    gltf.animations.forEach(clip => mixer.clipAction(clip).play())
  })
}, [])

return scene ? <primitive object={scene} /> : null

}

const Controls = () => {
  const orbitRef = useRef()
  const { camera, gl } = useThree()

  useFrame(() => {
    orbitRef.current.update()
  })

  return (
    <orbitControls
      autoRotate
      maxPolarAngle={Math.PI / 3}
      minPolarAngle={Math.PI / 3}
      args={[camera, gl.domElement]}
      ref={orbitRef}
    />
  )
}
const animated_element = () => {
  return (
    <Canvas camera={{ position: [0, 0, 5] }}>
      <ambientLight intensity={2} />
      <pointLight position={[40, 40, 40]} />
      <Controls/>
      <Suspense fallback={null}>
        <Hardware/>
      </Suspense>
    </Canvas>
  )
}

export default animated_element;


如果您执行 console.log(gltf.animations),会看到什么?里面有什么东西吗? - M -
是的,我确实得到了一个包含众多AnimationClip项的数组。请在这里查看我发布的控制台图像@Marquizzo:https://imgur.com/yjcVmug - Avinash
2个回答

12

我也曾经遇到过类似的问题。

这是对我有效的代码。

显然,该组件在树中较高的位置包裹了 Suspense

import { useLoader, useFrame } from 'react-three-fiber';
import { 
    GLTFLoader 
} from 'three/examples/jsm/loaders/GLTFLoader';
import * as THREE from 'three'

const Model = props => {
    const model = useLoader(
        GLTFLoader,
        props.path
    )

    // Here's the animation part
    // ************************* 
    let mixer
    if (model.animations.length) {
        mixer = new THREE.AnimationMixer(model.scene);
        model.animations.forEach(clip => {
            const action = mixer.clipAction(clip)
            action.play();
        });
    }

    useFrame((state, delta) => {
        mixer?.update(delta)
    })
    // *************************

    model.scene.traverse(child => {
        if (child.isMesh) {
            child.castShadow = true
            child.receiveShadow = true
            child.material.side = THREE.FrontSide
        }
    })

    return (
        <primitive 
            object={model.scene}
            scale={props.scale}
        />
    )
}

export default Model;

谢谢,useFrame((state, delta) => { mixer?.update(delta) }) 对我有用。我之前尝试使用的是 useFrame(({ clock }) => mixer?.update(clock.getDelta())); - Rob Myers
工作得像魔法一样!即使当我使用useAnimation钩子时它不起作用。 - undefined
你救了我...谢谢兄弟 - undefined

0
如果您正在使用@react-three/drei,您还可以执行以下操作:
    import {useAnimations} from '@react-three/drei'

    const model = useLoader(
        GLTFLoader,
        props.path
    ) 

    const modelAnimations = useAnimations(model.animations)
    
    useEffect(() => {
      modelAnimations.actions[modelAnimations.names].play()
    }, [])


这对我来说不起作用。modelAnimations.names 是一个字符串数组。 - Ryan Soderberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接