|
| 1 | +import * as React from 'react' |
| 2 | +import { Vector3 } from 'three' |
| 3 | +import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader' |
| 4 | +import { withKnobs, select, number } from '@storybook/addon-knobs' |
| 5 | + |
| 6 | +import { Setup } from '../Setup' |
| 7 | + |
| 8 | +import { useAnimations, useGLTF, useMatcapTexture } from '../../src' |
| 9 | + |
| 10 | +export default { |
| 11 | + title: 'Abstractions/useAnimations', |
| 12 | + component: useAnimations, |
| 13 | + decorators: [(storyFn) => <Setup cameraPosition={new Vector3(0, 0, 3)}>{storyFn()}</Setup>, withKnobs], |
| 14 | +} |
| 15 | + |
| 16 | +type GLTFResult = GLTF & { |
| 17 | + nodes: { |
| 18 | + YB_Body: THREE.SkinnedMesh |
| 19 | + YB_Joints: THREE.SkinnedMesh |
| 20 | + mixamorigHips: THREE.Bone |
| 21 | + } |
| 22 | + materials: { |
| 23 | + YB_Body: THREE.MeshStandardMaterial |
| 24 | + YB_Joints: THREE.MeshStandardMaterial |
| 25 | + } |
| 26 | +} |
| 27 | + |
| 28 | +type AnimationControllerProps = { |
| 29 | + ybotRef: React.MutableRefObject<THREE.Group | undefined | null> |
| 30 | + animations: THREE.AnimationClip[] |
| 31 | +} |
| 32 | + |
| 33 | +function AnimationController(props: AnimationControllerProps) { |
| 34 | + const { actions } = useAnimations(props.animations, props.ybotRef) |
| 35 | + |
| 36 | + // Storybook Knobs |
| 37 | + const actionOptions = Object.keys(actions) |
| 38 | + const selectedAction = select('Animation', actionOptions, actionOptions[2]) |
| 39 | + const blendDuration = number('Blend duration', 0.5, { |
| 40 | + range: true, |
| 41 | + min: 0, |
| 42 | + max: 2, |
| 43 | + step: 0.1, |
| 44 | + }) |
| 45 | + |
| 46 | + React.useEffect(() => { |
| 47 | + actions[selectedAction].reset().fadeIn(blendDuration).play() |
| 48 | + return () => void actions[selectedAction].fadeOut(blendDuration) |
| 49 | + }, [actions, selectedAction, blendDuration]) |
| 50 | + |
| 51 | + return null |
| 52 | +} |
| 53 | + |
| 54 | +function YBotModel(props: JSX.IntrinsicElements['group']) { |
| 55 | + const ybotRef = React.useRef<THREE.Group>(null) |
| 56 | + const { nodes, animations } = useGLTF('ybot.glb') as GLTFResult |
| 57 | + const [matcapBody] = useMatcapTexture('293534_B2BFC5_738289_8A9AA7', 1024) |
| 58 | + const [matcapJoints] = useMatcapTexture('3A2412_A78B5F_705434_836C47', 1024) |
| 59 | + |
| 60 | + return ( |
| 61 | + <> |
| 62 | + <group ref={ybotRef} {...props} dispose={null}> |
| 63 | + <group rotation={[Math.PI / 2, 0, 0]} scale={[0.01, 0.01, 0.01]}> |
| 64 | + <primitive object={nodes.mixamorigHips} /> |
| 65 | + <skinnedMesh geometry={nodes.YB_Body.geometry} skeleton={nodes.YB_Body.skeleton}> |
| 66 | + <meshMatcapMaterial attach="material" matcap={matcapBody} skinning={true} /> |
| 67 | + </skinnedMesh> |
| 68 | + <skinnedMesh geometry={nodes.YB_Joints.geometry} skeleton={nodes.YB_Joints.skeleton}> |
| 69 | + <meshMatcapMaterial attach="material" matcap={matcapJoints} skinning={true} /> |
| 70 | + </skinnedMesh> |
| 71 | + </group> |
| 72 | + </group> |
| 73 | + |
| 74 | + <AnimationController ybotRef={ybotRef} animations={animations} /> |
| 75 | + </> |
| 76 | + ) |
| 77 | +} |
| 78 | + |
| 79 | +useGLTF.preload('ybot.glb') |
| 80 | + |
| 81 | +function UseAnimationsScene() { |
| 82 | + return ( |
| 83 | + <React.Suspense fallback={null}> |
| 84 | + <YBotModel position={[0, -1, 0]} /> |
| 85 | + </React.Suspense> |
| 86 | + ) |
| 87 | +} |
| 88 | + |
| 89 | +export const UseAnimationsSt = () => <UseAnimationsScene /> |
| 90 | +UseAnimationsSt.storyName = 'Default' |
0 commit comments