This repository has been archived by the owner on Dec 16, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 56
/
LaserBeam.js
74 lines (63 loc) · 2.15 KB
/
LaserBeam.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import React from 'react';
import { useSpring, animated } from 'react-spring/three';
import useOnChange from '../../hooks/use-on-change.hook';
import { getSpringConfigForLight } from './Preview.helpers';
const ON_PROPS = { emissiveIntensity: 0.75, opacity: 0.75 };
const OFF_PROPS = { emissiveIntensity: 0, opacity: 0 };
const BRIGHT_PROPS = { emissiveIntensity: 1, opacity: 1 };
const LaserBeam = ({
color,
position,
rotation,
brightness,
status,
lastEventId,
isPlaying,
}) => {
const radius = 0.35;
const height = 500;
// ~~Complicated Business~~
// This component renders super often, since its `rotation` can change on
// every frame.
//
// When certain statuses occur - flash, fade - we want to reset the spring,
// so that it does the "from" and "to" again. This should happen even when
// the status hasn't changed (eg. a series of `flash` events in a row should
// all trigger the reset, and get momentarily brighter).
//
// If I just set `reset: true` based on the status, though, then it resets
// _on every frame_, meaning that the value is just perpetually locked to the
// `from` value. So I need to let a single render pass when `reset` is true.
//
// I cache the event ID so that I can distinguish the first render after it
// changes. When that happens, I set `reset` to true and update the cache,
// so that the next render sets it back to `false`.
//
// This feels hacky, but I don't know of a better way.
let springConfig = getSpringConfigForLight(
[ON_PROPS, OFF_PROPS, BRIGHT_PROPS],
status
);
useOnChange(() => {
if (!isPlaying) {
return;
}
const statusShouldReset = status === 'flash' || status === 'fade';
springConfig.reset = statusShouldReset;
}, lastEventId);
const spring = useSpring(springConfig);
return (
<group>
<mesh position={position} rotation={rotation}>
<cylinderGeometry attach="geometry" args={[radius, radius, height]} />
<animated.meshLambertMaterial
attach="material"
emissive={color}
transparent={true}
{...spring}
/>
</mesh>
</group>
);
};
export default LaserBeam;