#reactjs #three.js #react-three-fiber
#reactjs #three.js #react-three-fiber
Вопрос:
Ну, у меня есть анимированная модель .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;
Комментарии:
1. Что вы увидите, если сделаете
console.log(gltf.animations)
? Там что-нибудь есть?2. Да, я действительно получаю массив с многочисленными элементами AnimationClip. Посмотрите, здесь я разместил изображение консоли @Marquizzo
Ответ №1:
Я боролся с тем же самым.
Вот код, который сработал для меня.
Очевидно, что этот компонент обернут 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;
Комментарии:
1. Спасибо,
useFrame((state, delta) => { mixer?.update(delta) })
сработало для меня. Ранее я пытался использоватьuseFrame(({ clock }) => mixer?.update(clock.getDelta()));
Ответ №2:
Если вы используете @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()
}, [])