parent
94bc4d114b
commit
9b29855a4a
Binary file not shown.
@ -0,0 +1,160 @@
|
||||
/*
|
||||
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 { 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'
|
||||
|
||||
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<ActionName, THREE.AnimationAction>
|
||||
|
||||
const Human: React.FC<JSX.IntrinsicElements['group'] & { id: number }> = ({
|
||||
id,
|
||||
...rest
|
||||
}) => {
|
||||
const group = useRef<THREE.Group>()
|
||||
const { nodes, animations } = useGLTF('/model/human.glb') as GLTFResult
|
||||
const currentAnimation = useRef<ActionName>('idle')
|
||||
|
||||
const material = useMemo(() => {
|
||||
const m = new MeshNormalMaterial({
|
||||
transparent: true,
|
||||
side: FrontSide,
|
||||
flatShading: false,
|
||||
skinning: true,
|
||||
})
|
||||
|
||||
m.onBeforeCompile = function (shader) {
|
||||
console.log(shader.fragmentShader)
|
||||
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, 0.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<GLTFActions>()
|
||||
const [mixer] = useState(() => new THREE.AnimationMixer(nodes.mesh))
|
||||
|
||||
useEffect(() => {
|
||||
api.subscribe(
|
||||
(state: Transform | 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.enabled = true
|
||||
newAction.setEffectiveTimeScale(1)
|
||||
newAction.setEffectiveWeight(1)
|
||||
previousAction.crossFadeTo(newAction, 0.2, 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 (
|
||||
<group
|
||||
ref={group}
|
||||
{...rest}
|
||||
dispose={null}
|
||||
rotation={[0, -Math.PI, 0]}
|
||||
position={[0, -HEIGHT, 0]}
|
||||
>
|
||||
<group name="root" rotation={[0, -0.09, 0]}>
|
||||
<primitive object={nodes.mixamorigHips} />
|
||||
<skinnedMesh
|
||||
material={material}
|
||||
geometry={nodes.mesh.geometry}
|
||||
skeleton={nodes.mesh.skeleton}
|
||||
></skinnedMesh>
|
||||
</group>
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
useGLTF.preload('/model/human.glb')
|
||||
|
||||
export default Human
|
Loading…
Reference in new issue