-
Notifications
You must be signed in to change notification settings - Fork 730
/
Copy pathEdges.tsx
48 lines (41 loc) · 2.16 KB
/
Edges.tsx
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
import * as React from 'react'
import * as THREE from 'three'
import { ReactThreeFiber, type ThreeElements } from '@react-three/fiber'
import { LineSegmentsGeometry, LineMaterial, LineMaterialParameters, Line2, LineSegments2 } from 'three-stdlib'
import { ForwardRefComponent } from '../helpers/ts-utils'
import { Line } from './Line'
export type EdgesRef = THREE.Mesh<LineSegmentsGeometry, LineMaterial>
export type EdgesProps = Partial<ThreeElements['mesh']> & {
threshold?: number
lineWidth?: number
} & Omit<LineMaterialParameters, 'vertexColors' | 'color'> &
Omit<ReactThreeFiber.Object3DNode<Line2, typeof Line2>, 'args' | 'geometry'> &
Omit<ReactThreeFiber.Object3DNode<LineMaterial, [LineMaterialParameters]>, 'color' | 'vertexColors' | 'args'> & {
geometry?: THREE.BufferGeometry
color?: THREE.ColorRepresentation
}
export const Edges: ForwardRefComponent<EdgesProps, EdgesRef> = /* @__PURE__ */ React.forwardRef<EdgesRef, EdgesProps>(
({ threshold = 15, geometry: explicitGeometry, ...props }: EdgesProps, fref) => {
const ref = React.useRef<LineSegments2>(null!)
React.useImperativeHandle(fref, () => ref.current, [])
const tmpPoints = React.useMemo(() => [0, 0, 0, 1, 0, 0], [])
const memoizedGeometry = React.useRef<THREE.BufferGeometry>()
const memoizedThreshold = React.useRef<number>()
React.useLayoutEffect(() => {
const parent = ref.current.parent as THREE.Mesh
const geometry = explicitGeometry ?? parent?.geometry
if (!geometry) return
const cached = memoizedGeometry.current === geometry && memoizedThreshold.current === threshold
if (cached) return
memoizedGeometry.current = geometry
memoizedThreshold.current = threshold
const points = (new THREE.EdgesGeometry(geometry, threshold).attributes.position as THREE.BufferAttribute)
.array as Float32Array
ref.current.geometry.setPositions(points)
ref.current.geometry.attributes.instanceStart.needsUpdate = true
ref.current.geometry.attributes.instanceEnd.needsUpdate = true
ref.current.computeLineDistances()
})
return <Line segments points={tmpPoints} ref={ref} raycast={() => null} {...props} />
}
)