/* Auto-generated by: https://github.com/pmndrs/gltfjsx */ import * as THREE from 'three' import React, { useRef, useState, useEffect, useMemo } from 'react' import { useFrame } from 'react-three-fiber' import { useGLTF } from '@react-three/drei/useGLTF' import cloneGltf from '../lib/cloneGltf' import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader' import { FrontSide } from 'three/src/constants' import { HEIGHT } from '../Player' import api, { State, Transform } from '../../store' import { Color } from 'three/src/math/Color' import { MeshNormalMaterial } from 'three/src/materials/MeshNormalMaterial' import { Object3D } from 'three/src/core/Object3D' import { SkinnedMesh } from 'three/src/objects/SkinnedMesh' type GLTFResult = GLTF & { nodes: { mesh: THREE.SkinnedMesh mixamorigHips: THREE.Bone } materials: { ['Material.001']: THREE.MeshStandardMaterial } } export type ActionName = | 'idle' | 'jump' | 'run_left' | 'run_right' | 'run' | 'turn_left' | 'turn_right' | 'walk' | 'walk_backwards' | 'walk_left' | 'walk_right' type GLTFActions = Record const Human: React.FC = ({ id, ...rest }) => { const group = useRef() const gltf = useGLTF('/model/human.glb') as GLTFResult const currentAnimation = useRef('idle') const { scene, animations } = cloneGltf(gltf as GLTFResult) const [nodes] = useState>(() => { const n = {} scene.children[0].children.forEach((child: Object3D) => { //@ts-ignore n[child.name] = child }) return n }) const material = useMemo(() => { const m = new MeshNormalMaterial({ transparent: true, side: FrontSide, flatShading: false, skinning: true, }) m.onBeforeCompile = function (shader) { shader.fragmentShader = shader.fragmentShader.replace( 'gl_FragColor = vec4( packNormalToRGB( normal ), opacity );', [ 'gl_FragColor = vec4( packNormalToRGB( normal ), opacity );', 'gl_FragColor.a = 1.0 - pow( gl_FragCoord.z, 4.75 );', 'gl_FragColor.r = 0.70;', 'gl_FragColor.g = 0.85;', 'gl_FragColor.b = 1.0;', ].join('\n'), ) } m.needsUpdate = true return m }, []) const actions = useRef() //@ts-ignore const [mixer] = useState(() => new THREE.AnimationMixer(nodes.mesh)) useEffect(() => { api.subscribe( (state: Transform | undefined | null) => { if (!state || !actions.current) { return } if (state.animation === currentAnimation.current) return const newAction = actions.current[state.animation] const previousAction = actions.current[currentAnimation.current] newAction.reset() newAction.setEffectiveTimeScale(1) const weight = state.animation === 'turn_left' || state.animation === 'turn_right' ? 0.5 : 1 const time = state.animation === 'jump' ? 0 : 0.2 newAction.setEffectiveWeight(weight) previousAction.crossFadeTo(newAction, time, true) currentAnimation.current = state.animation }, (state) => state?.userTransforms?.[id], ) }, [id]) useEffect(() => { if (actions.current && currentAnimation.current) { } }, [currentAnimation.current]) useFrame((_, delta) => { mixer.update(delta) }) useEffect(() => { actions.current = { idle: mixer.clipAction(animations[0], group.current), jump: mixer.clipAction(animations[1], group.current), run_left: mixer.clipAction(animations[2], group.current), run_right: mixer.clipAction(animations[3], group.current), run: mixer.clipAction(animations[4], group.current), turn_left: mixer.clipAction(animations[5], group.current), turn_right: mixer.clipAction(animations[6], group.current), walk: mixer.clipAction(animations[7], group.current), walk_backwards: mixer.clipAction(animations[8], group.current), walk_left: mixer.clipAction(animations[9], group.current), walk_right: mixer.clipAction(animations[10], group.current), } Object.values(actions.current).forEach((a) => { a.setEffectiveWeight(0) a.enabled = true a.setEffectiveTimeScale(1) a.play() }) if (currentAnimation.current) { actions.current[currentAnimation.current].play() } }, [group, animations, mixer]) return ( ) } useGLTF.preload('/model/human.glb') export default Human