@@ -7,10 +7,10 @@ import type { Color3 } from "core/Maths";
7
7
import { Color4 , Matrix } from "core/Maths" ;
8
8
import type { AbstractMesh } from "core/Meshes" ;
9
9
import { CreateSphere } from "core/Meshes" ;
10
- import type { Observer } from "core/Misc" ;
11
10
import type { Attractor } from "core/Particles" ;
12
11
import type { Scene } from "core/scene" ;
13
- import { useCallback , useEffect , useRef , useState , type FunctionComponent } from "react" ;
12
+ import { useCallback , useEffect , useState } from "react" ;
13
+ import type { FunctionComponent } from "react" ;
14
14
import { SyncedSliderInput } from "shared-ui-components/fluent/primitives/syncedSlider" ;
15
15
import { ToggleButton } from "shared-ui-components/fluent/primitives/toggleButton" ;
16
16
import { useAsyncResource , useResource } from "../../../hooks/resourceHooks" ;
@@ -46,15 +46,14 @@ const CreateImpostor = (id: number, scene: Scene, attractor: Attractor, initialS
46
46
return impostor ;
47
47
} ;
48
48
49
- async function CreateTextRendererAsync ( scene : Scene , impostor : AbstractMesh , index : number , color : Color3 ) {
49
+ async function CreateTextRendererAsync ( id : number , scene : Scene , impostor : AbstractMesh , color : Color3 ) {
50
50
const sdfFontDefinition = await ( await fetch ( "https://assets.babylonjs.com/fonts/roboto-regular.json" ) ) . text ( ) ;
51
51
const fontAsset = new FontAsset ( sdfFontDefinition , "https://assets.babylonjs.com/fonts/roboto-regular.png" ) ;
52
52
53
53
const textRenderer = await TextRenderer . CreateTextRendererAsync ( fontAsset , scene . getEngine ( ) ) ;
54
- textRenderer . addParagraph ( "#" + index , { } , Matrix . Scaling ( 0.5 , 0.5 , 0.5 ) . multiply ( Matrix . Translation ( 0 , 1 , 0 ) ) ) ;
54
+ textRenderer . addParagraph ( "#" + id , { } , Matrix . Scaling ( 0.5 , 0.5 , 0.5 ) . multiply ( Matrix . Translation ( 0 , 1 , 0 ) ) ) ;
55
55
textRenderer . isBillboard = true ;
56
56
textRenderer . color = Color4 . FromColor3 ( color , 1.0 ) ;
57
- textRenderer . render ( scene . getViewMatrix ( ) , scene . getProjectionMatrix ( ) ) ;
58
57
textRenderer . parent = impostor ;
59
58
return textRenderer ;
60
59
}
@@ -65,33 +64,32 @@ async function CreateTextRendererAsync(scene: Scene, impostor: AbstractMesh, ind
65
64
* @returns
66
65
*/
67
66
export const AttractorComponent : FunctionComponent < AttractorProps > = ( props ) => {
68
- const { attractor, id, impostorScale, impostorMaterial, scene } = props ;
67
+ const { attractor, id, impostorScale, impostorMaterial, impostorColor , scene, onControl , isControlled } = props ;
69
68
const classes = useAttractorStyles ( ) ;
70
69
const [ shown , setShown ] = useState ( true ) ;
71
70
72
- // Create observer and cleanup on unmount (we can't use useResource since Observer is not an IDisposable)
73
- const sceneOnAfterRenderObserverRef = useRef < Observer < Scene > > ( ) ;
74
- useEffect ( ( ) => ( ) => sceneOnAfterRenderObserverRef . current ?. remove ( ) , [ ] ) ;
75
-
76
71
// We only want to recreate the impostor mesh and associated if id, scene, or attractor/impostor changes
77
72
const impostor = useResource ( useCallback ( ( ) => CreateImpostor ( id , scene , attractor , impostorScale , impostorMaterial ) , [ id , scene , attractor ] ) ) ;
78
- const label = useAsyncResource ( useCallback ( async ( ) => await CreateTextRendererAsync ( scene , impostor , id , props . impostorColor ) , [ scene , impostor , id ] ) ) ;
73
+ const label = useAsyncResource ( useCallback ( async ( ) => await CreateTextRendererAsync ( id , scene , impostor , impostorColor ) , [ id , scene , impostor ] ) ) ;
79
74
80
75
// If impostor, color, or label change, recreate the observer function so that it isnt hooked to old state
81
76
useEffect ( ( ) => {
82
- sceneOnAfterRenderObserverRef . current ?. remove ( ) ;
83
- sceneOnAfterRenderObserverRef . current = scene . onAfterRenderObservable . add ( ( ) => {
77
+ const onAfterRender = scene . onAfterRenderObservable . add ( ( ) => {
84
78
attractor . position . copyFrom ( impostor . position ) ;
85
79
if ( label ) {
86
- label . color = Color4 . FromColor3 ( props . impostorColor ) ;
80
+ label . color = Color4 . FromColor3 ( impostorColor ) ;
87
81
label . render ( scene . getViewMatrix ( ) , scene . getProjectionMatrix ( ) ) ;
88
82
}
89
83
} ) ;
90
- } , [ impostor , label , props . impostorColor ] ) ;
84
+ return ( ) => {
85
+ onAfterRender . remove ( ) ;
86
+ } ;
87
+ } , [ impostor , scene , label , impostorColor ] ) ;
91
88
89
+ // If impostor or impostorScale change, update impostor scaling
92
90
useEffect ( ( ) => {
93
91
impostor . scaling . setAll ( impostorScale ) ;
94
- } , [ impostorScale ] ) ;
92
+ } , [ impostor , impostorScale ] ) ;
95
93
96
94
return (
97
95
< div className = { classes . container } >
@@ -109,8 +107,8 @@ export const AttractorComponent: FunctionComponent<AttractorProps> = (props) =>
109
107
< ToggleButton
110
108
title = "Add / remove position gizmo from particle attractor"
111
109
enabledIcon = { ArrowMoveFilled }
112
- value = { props . isControlled ( impostor ) }
113
- onChange = { ( control : boolean ) => props . onControl ( control ? impostor : undefined ) }
110
+ value = { isControlled ( impostor ) }
111
+ onChange = { ( control : boolean ) => onControl ( control ? impostor : undefined ) }
114
112
/>
115
113
</ div >
116
114
) ;
0 commit comments