@@ -2,19 +2,17 @@ import {
2
2
afterNextRender ,
3
3
ChangeDetectionStrategy ,
4
4
Component ,
5
+ computed ,
5
6
CUSTOM_ELEMENTS_SCHEMA ,
6
7
effect ,
7
8
ElementRef ,
8
9
inject ,
9
10
Injector ,
10
11
input ,
11
- signal ,
12
- untracked ,
13
12
viewChild ,
14
13
} from '@angular/core' ;
15
- import { checkUpdate , extend , getLocalState , NgtGroup , omit , resolveRef } from 'angular-three' ;
14
+ import { checkUpdate , extend , getLocalState , NgtGroup , omit , pick , resolveRef } from 'angular-three' ;
16
15
import { assertInjector } from 'ngxtension/assert-injector' ;
17
- import { injectAutoEffect } from 'ngxtension/auto-effect' ;
18
16
import { mergeInputs } from 'ngxtension/inject-inputs' ;
19
17
import { BufferGeometry , Color , Group , InstancedBufferAttribute , InstancedMesh , Mesh , Object3D , Vector3 } from 'three' ;
20
18
import { MeshSurfaceSampler } from 'three-stdlib' ;
@@ -62,82 +60,80 @@ export function injectSurfaceSampler(
62
60
{ injector } : { injector ?: Injector } = { } ,
63
61
) {
64
62
return assertInjector ( injectSurfaceSampler , injector , ( ) => {
65
- const buffer = signal (
66
- ( ( ) => {
67
- const arr = Array . from ( { length : options ( ) . count ?? 16 } , ( ) => [
68
- 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ,
69
- ] ) . flat ( ) ;
70
- return new InstancedBufferAttribute ( Float32Array . from ( arr ) , 16 ) ;
71
- } ) ( ) ,
72
- ) ;
73
-
74
- effect (
75
- ( ) => {
76
- const currentMesh = resolveRef ( mesh ( ) ) ;
77
- if ( ! currentMesh ) return ;
78
-
79
- const localState = getLocalState ( currentMesh ) ;
80
- if ( ! localState ) return ;
81
-
82
- const nonObjects = localState . nonObjects ( ) ;
83
- if (
84
- ! nonObjects ||
85
- ! nonObjects . length ||
86
- nonObjects . every ( ( nonObject ) => ! ( nonObject as BufferGeometry ) . isBufferGeometry )
87
- ) {
88
- return ;
63
+ const initialBufferAttribute = ( ( ) => {
64
+ const arr = Array . from ( { length : options ( ) . count ?? 16 } , ( ) => [
65
+ 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ,
66
+ ] ) . flat ( ) ;
67
+ return new InstancedBufferAttribute ( Float32Array . from ( arr ) , 16 ) ;
68
+ } ) ( ) ;
69
+
70
+ const buffer = computed ( ( ) => {
71
+ const currentMesh = resolveRef ( mesh ( ) ) ;
72
+ if ( ! currentMesh ) return initialBufferAttribute ;
73
+
74
+ const localState = getLocalState ( currentMesh ) ;
75
+ if ( ! localState ) return initialBufferAttribute ;
76
+
77
+ const nonObjects = localState . nonObjects ( ) ;
78
+ if (
79
+ ! nonObjects ||
80
+ ! nonObjects . length ||
81
+ nonObjects . every ( ( nonObject ) => ! ( nonObject as BufferGeometry ) . isBufferGeometry )
82
+ ) {
83
+ return initialBufferAttribute ;
84
+ }
85
+
86
+ const sampler = new MeshSurfaceSampler ( currentMesh ) ;
87
+ const { weight, count = 16 , transform, instanceMesh } = options ( ) ;
88
+
89
+ if ( weight ) {
90
+ sampler . setWeightAttribute ( weight ) ;
91
+ }
92
+
93
+ sampler . build ( ) ;
94
+
95
+ const position = new Vector3 ( ) ;
96
+ const normal = new Vector3 ( ) ;
97
+ const color = new Color ( ) ;
98
+ const dummy = new Object3D ( ) ;
99
+ const instance = resolveRef ( instanceMesh ) ;
100
+
101
+ currentMesh . updateMatrixWorld ( true ) ;
102
+
103
+ for ( let i = 0 ; i < count ; i ++ ) {
104
+ sampler . sample ( position , normal , color ) ;
105
+
106
+ if ( typeof transform === 'function' ) {
107
+ transform ( { dummy, sampledMesh : currentMesh , position, normal, color } , i ) ;
108
+ } else {
109
+ dummy . position . copy ( position ) ;
89
110
}
90
111
91
- const sampler = new MeshSurfaceSampler ( currentMesh ) ;
112
+ dummy . updateMatrix ( ) ;
92
113
93
- const { weight, count = 16 , transform, instanceMesh } = options ( ) ;
94
-
95
- if ( weight ) {
96
- sampler . setWeightAttribute ( weight ) ;
114
+ if ( instance ) {
115
+ instance . setMatrixAt ( i , dummy . matrix ) ;
97
116
}
98
117
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
- const instance = resolveRef ( instanceMesh ) ;
106
-
107
- currentMesh . updateMatrixWorld ( true ) ;
108
-
109
- for ( let i = 0 ; i < count ; i ++ ) {
110
- sampler . sample ( position , normal , color ) ;
111
-
112
- if ( typeof transform === 'function' ) {
113
- transform ( { dummy, sampledMesh : currentMesh , position, normal, color } , i ) ;
114
- } else {
115
- dummy . position . copy ( position ) ;
116
- }
117
-
118
- dummy . updateMatrix ( ) ;
119
-
120
- if ( instance ) {
121
- instance . setMatrixAt ( i , dummy . matrix ) ;
122
- }
123
-
124
- dummy . matrix . toArray ( untracked ( buffer ) . array , i * 16 ) ;
125
- }
118
+ dummy . matrix . toArray ( initialBufferAttribute . array , i * 16 ) ;
119
+ }
126
120
127
- if ( instance ) {
128
- checkUpdate ( instance . instanceMatrix ) ;
129
- }
121
+ if ( instance ) {
122
+ checkUpdate ( instance . instanceMatrix ) ;
123
+ }
130
124
131
- checkUpdate ( buffer ) ;
125
+ checkUpdate ( initialBufferAttribute ) ;
132
126
133
- buffer . set (
134
- new InstancedBufferAttribute ( untracked ( buffer ) . array , untracked ( buffer ) . itemSize ) . copy ( untracked ( buffer ) ) ,
135
- ) ;
136
- } ,
137
- { allowSignalWrites : true } ,
138
- ) ;
127
+ return new InstancedBufferAttribute ( initialBufferAttribute . array , initialBufferAttribute . itemSize ) . copy (
128
+ initialBufferAttribute ,
129
+ ) ;
130
+ } ) ;
139
131
140
- return buffer . asReadonly ( ) ;
132
+ return computed ( ( ) => {
133
+ const _buffer = buffer ( ) ;
134
+ if ( ! _buffer ) return initialBufferAttribute ;
135
+ return _buffer ;
136
+ } ) ;
141
137
} ) ;
142
138
}
143
139
@@ -184,44 +180,41 @@ export class NgtsSampler {
184
180
185
181
groupRef = viewChild . required < ElementRef < Group > > ( 'group' ) ;
186
182
187
- private meshToSample = signal < Mesh | null > ( null ) ;
188
- private instancedToSample = signal < InstancedMesh | null > ( null ) ;
183
+ private sampleState = computed ( ( ) => {
184
+ const group = this . groupRef ( ) . nativeElement ;
185
+ const localState = getLocalState ( group ) ;
186
+ if ( ! localState ) return { mesh : null , instanced : null } ;
187
+
188
+ const [ mesh , instances ] = [ resolveRef ( this . mesh ( ) ) , resolveRef ( this . instances ( ) ) ] ;
189
+ const objects = localState . objects ( ) ;
190
+
191
+ return {
192
+ mesh : mesh ?? ( objects . find ( ( c ) => c . type === 'Mesh' ) as Mesh ) ,
193
+ instanced :
194
+ instances ?? ( objects . find ( ( c ) => ! ! Object . getOwnPropertyDescriptor ( c , 'instanceMatrix' ) ) as InstancedMesh ) ,
195
+ } ;
196
+ } ) ;
189
197
190
198
constructor ( ) {
191
199
extend ( { Group } ) ;
192
- const autoEffect = injectAutoEffect ( ) ;
193
200
const injector = inject ( Injector ) ;
194
201
195
202
afterNextRender ( ( ) => {
196
- autoEffect (
197
- ( ) => {
198
- const group = this . groupRef ( ) . nativeElement ;
199
- const localState = getLocalState ( group ) ;
200
- if ( ! localState ) return ;
201
-
202
- const [ mesh , instances ] = [ resolveRef ( this . mesh ( ) ) , resolveRef ( this . instances ( ) ) ] ;
203
-
204
- this . meshToSample . set ( mesh ?? ( localState . objects ( ) . find ( ( c ) => c . type === 'Mesh' ) as Mesh ) ) ;
205
- this . instancedToSample . set (
206
- instances ??
207
- ( localState
208
- . objects ( )
209
- . find ( ( c ) => ! ! Object . getOwnPropertyDescriptor ( c , 'instanceMatrix' ) ) as InstancedMesh ) ,
210
- ) ;
211
- } ,
212
- { allowSignalWrites : true } ,
213
- ) ;
203
+ const meshToSample = pick ( this . sampleState , 'mesh' ) ;
204
+ const instancedToSample = pick ( this . sampleState , 'instanced' ) ;
214
205
215
- injectSurfaceSampler (
216
- this . meshToSample ,
206
+ const sampler = injectSurfaceSampler (
207
+ meshToSample ,
217
208
( ) => ( {
218
209
count : this . options ( ) . count ,
219
210
transform : this . options ( ) . transform ,
220
211
weight : this . options ( ) . weight ,
221
- instanceMesh : this . instancedToSample ( ) ,
212
+ instanceMesh : instancedToSample ( ) ,
222
213
} ) ,
223
214
{ injector } ,
224
215
) ;
216
+
217
+ effect ( sampler , { injector } ) ;
225
218
} ) ;
226
219
}
227
220
}
0 commit comments