1
+ import { ref } from 'vue'
2
+ import {
3
+ Vector3 ,
4
+ Color ,
5
+ Object3D ,
6
+ InterleavedBuffer ,
7
+ } from 'three'
8
+ import type { Mesh , InstancedMesh } from 'three'
9
+ import { MeshSurfaceSampler } from 'three-stdlib'
10
+
11
+ export interface useSurfaceSamplerProps {
12
+ /*
13
+ * A function that can be .
14
+ *
15
+ * @type {function }
16
+ * @memberof useSamplerProps
17
+ */
18
+ transform ?: TransformFn
19
+ /*
20
+ * Specifies a vertex attribute to be used as a weight when sampling from the surface.
21
+ *
22
+ * @type {string }
23
+ * @memberof useSamplerProps
24
+ */
25
+ weight ?: string
26
+ /*
27
+ * Number of samples.
28
+ *
29
+ * @type {number }
30
+ * @memberof useSamplerProps
31
+ */
32
+ count ?: number
33
+ /*
34
+ * Surface mesh from which to sample.
35
+ *
36
+ * @type {Mesh }
37
+ * @memberof useSamplerProps
38
+ */
39
+ mesh ?: Mesh
40
+ /*
41
+ * Instanced mesh to scatter.
42
+ *
43
+ * @type {InstancedMesh }
44
+ * @memberof useSamplerProps
45
+ */
46
+ instanceMesh ?: InstancedMesh | null
47
+ }
48
+
49
+ interface SamplePayload {
50
+ /**
51
+ * The position of the sample.
52
+ */
53
+ position : Vector3
54
+ /**
55
+ * The normal of the mesh at the sampled position.
56
+ */
57
+ normal : Vector3
58
+ /**
59
+ * The vertex color of the mesh at the sampled position.
60
+ */
61
+ color : Color
62
+ }
63
+
64
+ type TransformPayload = SamplePayload & {
65
+ /**
66
+ * The dummy object used to transform each instance.
67
+ * This object's matrix will be updated after transforming & it will be used
68
+ * to set the instance's matrix.
69
+ */
70
+ dummy : Object3D
71
+ /**
72
+ * The mesh that's initially passed to the sampler.
73
+ * Use this if you need to apply transforms from your mesh to your instances
74
+ * or if you need to grab attributes from the geometry.
75
+ */
76
+ sampledMesh : Mesh
77
+ }
78
+
79
+ export type TransformFn = ( payload : TransformPayload , i : number ) => void
80
+
81
+ export const useSurfaceSampler = (
82
+ mesh : Mesh ,
83
+ count : number = 16 ,
84
+ instanceMesh ?: InstancedMesh | null ,
85
+ weight ?: string ,
86
+ transform ?: TransformFn ,
87
+ ) => {
88
+ const arr = new Float32Array ( count * 16 )
89
+ const buffer = ref ( new InterleavedBuffer ( arr , 16 ) )
90
+
91
+ const updateBuffer = ( ) => {
92
+ if ( ! mesh ) return
93
+
94
+ const sampler = new MeshSurfaceSampler ( mesh )
95
+
96
+ if ( weight ) {
97
+ sampler . setWeightAttribute ( weight )
98
+ }
99
+ sampler . build ( )
100
+
101
+ const position = new Vector3 ( )
102
+ const normal = new Vector3 ( )
103
+ const color = new Color ( )
104
+ const dummy = new Object3D ( )
105
+
106
+ mesh . updateMatrixWorld ( true )
107
+
108
+ for ( let i = 0 ; i < count ; i ++ ) {
109
+ sampler . sample ( position , normal , color )
110
+
111
+ if ( typeof transform === 'function' ) {
112
+ transform (
113
+ {
114
+ dummy,
115
+ sampledMesh : mesh ,
116
+ position,
117
+ normal,
118
+ color,
119
+ } ,
120
+ i ,
121
+ )
122
+ }
123
+ else {
124
+ dummy . position . copy ( position )
125
+ }
126
+ dummy . updateMatrix ( )
127
+
128
+ if ( instanceMesh ) {
129
+ instanceMesh . setMatrixAt ( i , dummy . matrix )
130
+ }
131
+ dummy . matrix . toArray ( buffer . value . array , i * 16 )
132
+ }
133
+ if ( instanceMesh ) {
134
+ instanceMesh . instanceMatrix . needsUpdate = true
135
+ }
136
+
137
+ buffer . value . needsUpdate = true
138
+ }
139
+
140
+ updateBuffer ( )
141
+
142
+ return { buffer }
143
+ }
0 commit comments