pmndrs / gltfjsx

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

not generating array #198

Closed yersultanur closed 1 year ago

yersultanur commented 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

drcmda commented 1 year ago

you cant re-use skinned meshes in threejs ootb.

do it like this https://codesandbox.io/s/k8phr