Closed yersultanur closed 1 year ago
"use client"
import React, { Suspense, useEffect, useRef, useState } from "react" import { useAnimations, useGLTF } from "@react-three/drei" import { Canvas, useFrame, useLoader } from "@react-three/fiber" import * as THREE from "three" import { GLTF } from "three-stdlib"
type GLTFResult = GLTF & { nodes: { Object_7: THREE.SkinnedMesh _rootJoint: THREE.Bone } materials: { CH_NPC_MOB_GEagle_A02_MI_IRS: THREE.MeshStandardMaterial } animations: GLTFAction[] }
type ActionName = "CINEMA_4D_Principal" interface GLTFAction extends THREE.AnimationClip { name: ActionName }
export function Eagle( props: JSX.IntrinsicElements["group"] & { speed: number; factor: number } ) { const { speed, factor } = props const group = useRef(null!) const mesh = useRef(null!) const { nodes, materials, animations } = useGLTF( "/white_eagle_animation_fast_fly.glb" ) as GLTFResult const { actions } = useAnimations(animations, group) const [mixer] = useState(() => new THREE.AnimationMixer(nodes._rootJoint))
const [start] = useState(() => Math.random() * 5000)
useEffect(() => { const action = mixer.clipAction(animations[0]) action.play()
return () => { mixer.stopAllAction() }
}, [mixer, animations]) useFrame((state, delta) => { if (mesh.current) { mesh.current.position.y = Math.sin(start + state.clock.elapsedTime) 5 mesh.current.rotation.x = Math.PI / 2 + (Math.sin(start + state.clock.elapsedTime) Math.PI) / 10 mesh.current.rotation.y = (Math.sin(start + state.clock.elapsedTime) * Math.PI) / 2 }
group.current.rotation.y += Math.sin((delta * factor) / 2) * Math.cos((delta * factor) / 2) * 1.5 mixer.update(delta * speed)
})
return ( <group ref={group} {...props} dispose={null}>
</group> </group> </group>
) }
useGLTF.preload("/white_eagle_animation_fast_fly.glb")
function Birds() { const numEagles = 25 // Set the desired number of eagles
const eagles = Array.from({ length: numEagles }).map((_, i) => { const x = (15 + Math.random() 30) (Math.round(Math.random()) ? -1 : 1) const y = 10 + Math.random() 20 const z = 5 + Math.random() 10 const speed = 0.5 const factor = 0.5 + Math.random()
return ( <Eagle key={i} position={[x, y, z]} rotation={[0, x > 0 ? Math.PI : 0, 0]} speed={speed} factor={factor} /> )
return {eagles} }
export default function Eagles() { return ( <Canvas camera={{ position: [0, 0, 300] }}>
<pointLight position={[40, 40, 40]} /> <Birds /> </Canvas>
using Typescript and Nextjs, on render I have only 1 eagle generated, other props are working fine, like speed and factor but array not generating more than 1 eagle
you cant re-use skinned meshes in threejs ootb.
do it like this https://codesandbox.io/s/k8phr
"use client"
import React, { Suspense, useEffect, useRef, useState } from "react" import { useAnimations, useGLTF } from "@react-three/drei" import { Canvas, useFrame, useLoader } from "@react-three/fiber" import * as THREE from "three" import { GLTF } from "three-stdlib"
type GLTFResult = GLTF & { nodes: { Object_7: THREE.SkinnedMesh _rootJoint: THREE.Bone } materials: { CH_NPC_MOB_GEagle_A02_MI_IRS: THREE.MeshStandardMaterial } animations: GLTFAction[] }
type ActionName = "CINEMA_4D_Principal" interface GLTFAction extends THREE.AnimationClip { name: ActionName }
export function Eagle( props: JSX.IntrinsicElements["group"] & { speed: number; factor: number } ) { const { speed, factor } = props const group = useRef(null!)
const mesh = useRef(null!)
const { nodes, materials, animations } = useGLTF(
"/white_eagle_animation_fast_fly.glb"
) as GLTFResult
const { actions } = useAnimations(animations, group)
const [mixer] = useState(() => new THREE.AnimationMixer(nodes._rootJoint))
const [start] = useState(() => Math.random() * 5000)
useEffect(() => { const action = mixer.clipAction(animations[0]) action.play()
}, [mixer, animations]) useFrame((state, delta) => { if (mesh.current) { mesh.current.position.y = Math.sin(start + state.clock.elapsedTime) 5 mesh.current.rotation.x = Math.PI / 2 + (Math.sin(start + state.clock.elapsedTime) Math.PI) / 10 mesh.current.rotation.y = (Math.sin(start + state.clock.elapsedTime) * Math.PI) / 2 }
})
return ( <group ref={group} {...props} dispose={null}>
) }
useGLTF.preload("/white_eagle_animation_fast_fly.glb")
function Birds() { const numEagles = 25 // Set the desired number of eagles
const eagles = Array.from({ length: numEagles }).map((_, i) => { const x = (15 + Math.random() 30) (Math.round(Math.random()) ? -1 : 1) const y = 10 + Math.random() 20 const z = 5 + Math.random() 10 const speed = 0.5 const factor = 0.5 + Math.random()
})
return{eagles}
}
export default function Eagles() { return ( <Canvas camera={{ position: [0, 0, 300] }}>
) }
using Typescript and Nextjs, on render I have only 1 eagle generated, other props are working fine, like speed and factor but array not generating more than 1 eagle