@@ -32,35 +32,30 @@ function isWritable(object: object, propertyName: string) {
3232function applySceneGraph ( parent : object , child : object ) {
3333 const parentMeta = getMeta ( parent )
3434 if ( parentMeta ) {
35- // Update parent's augmented children-property.
3635 parentMeta . children . add ( child )
3736 onCleanup ( ( ) => parentMeta . children . delete ( child ) )
3837 }
3938
4039 const childMeta = getMeta ( child )
4140 if ( childMeta ) {
42- // Update parent's augmented children-property.
4341 childMeta . parent = parent
4442 onCleanup ( ( ) => ( childMeta . parent = undefined ) )
4543 }
4644
4745 let attachProp = childMeta ?. props . attach
4846
49- // Attach-prop can be a callback. It returns a cleanup-function.
5047 if ( typeof attachProp === "function" ) {
51- const cleanup = attachProp ( parent , child as Meta )
48+ const cleanup = attachProp ( parent , child as Meta < object > )
5249 onCleanup ( cleanup )
5350 return
5451 }
5552
56- // Defaults for Material, BufferGeometry and Fog.
5753 if ( ! attachProp ) {
5854 if ( child instanceof Material ) attachProp = "material"
5955 else if ( child instanceof BufferGeometry ) attachProp = "geometry"
6056 else if ( child instanceof Fog ) attachProp = "fog"
6157 }
6258
63- // If an attachProp is defined, attach the child to the parent.
6459 if ( attachProp ) {
6560 let target = parent
6661 let property : string | undefined
@@ -83,12 +78,8 @@ function applySceneGraph(parent: object, child: object) {
8378 return
8479 }
8580
86- // If no attach-prop is defined, add the child to the parent.
87- if ( child instanceof Object3D && parent instanceof Object3D && ! parent . children . includes ( child ) ) {
88- parent . add ( child )
89- onCleanup ( ( ) => parent . remove ( child ) )
90- return child
91- }
81+ // Object3D children are managed by the ordering loop in useSceneGraph
82+ if ( child instanceof Object3D && parent instanceof Object3D ) return
9283
9384 console . error (
9485 "Error while connecting/attaching child: child does not have attach-props defined and is not an Object3D" ,
@@ -119,6 +110,8 @@ export const useSceneGraph = <T extends object>(
119110 props : { children ?: JSXElement | JSXElement [ ] ; onUpdate ?( event : T ) : void } ,
120111) => {
121112 const c = children ( ( ) => props . children )
113+
114+ // Per-item: metadata, attach props, events
122115 createComputed (
123116 mapArray (
124117 ( ) => c . toArray ( ) as unknown as ( Meta < object > | undefined ) [ ] ,
@@ -133,6 +126,48 @@ export const useSceneGraph = <T extends object>(
133126 } ) ,
134127 ) ,
135128 )
129+
130+ // Object3D scene graph sync: add, remove, reorder
131+ createComputed ( ( previousManagedChildren : Set < Object3D > ) => {
132+ const parent = resolve ( _parent )
133+ if ( ! ( parent instanceof Object3D ) ) {
134+ return previousManagedChildren
135+ }
136+
137+ const childArray = c . toArray ( ) as unknown as Array < object | undefined >
138+ const managedChildren = new Set < Object3D > ( )
139+
140+ for ( const child of childArray ) {
141+ if ( ! ( child instanceof Object3D ) || getMeta ( child ) ?. props . attach ) continue
142+ managedChildren . add ( child )
143+ if ( child . parent !== parent ) {
144+ parent . add ( child )
145+ }
146+ }
147+
148+ for ( const child of previousManagedChildren ) {
149+ if ( ! managedChildren . has ( child ) ) {
150+ parent . remove ( child )
151+ }
152+ }
153+
154+ // Reorder: walk parent.children, assign desired order at managed slots
155+ let childArrayIndex = 0
156+ for ( let i = 0 ; i < parent . children . length ; i ++ ) {
157+ if ( ! managedChildren . has ( parent . children [ i ] ! ) ) {
158+ continue
159+ }
160+ while ( childArrayIndex < childArray . length ) {
161+ const child = childArray [ childArrayIndex ++ ]
162+ if ( child instanceof Object3D && ! getMeta ( child ) ?. props . attach ) {
163+ parent . children [ i ] = child
164+ break
165+ }
166+ }
167+ }
168+
169+ return managedChildren
170+ } , new Set < Object3D > ( ) )
136171}
137172
138173/**********************************************************************************/
0 commit comments