-2

i am trying to update a stateful variable cameraPosition using Typescript, React and Babylonjs.

this is the code snipped:

  const camera = scene?.cameras[0];
  const prevPositionRef = useRef<Nullable<Vector3>>(null);
  
  
  const [cameraPosition, setCameraPosition] = useState<Vector3>(
    new Vector3(0, 0, 0)
  );

  useEffect(() => {
    if (camera) {
      const onAfterInput = () => {
        if (
          !prevPositionRef.current ||
          !prevPositionRef.current.equals(camera.position)
        ) {
          console.log("change") //also logs every changed frame!

          setCameraPosition(camera.position); // does not set the position (or does it?!)

          prevPositionRef.current = camera.position.clone();
        }
      };

      camera.onAfterCheckInputsObservable.add(() => {
        // it correctly triggers every frame
        onAfterInput();
      });

      return () => {
        camera.onAfterCheckInputsObservable.removeCallback(() => {
          onAfterInput();
        });
      };
    }
  }, [camera]);

 console.log(cameraPosition) // does not log position!?

i even tried to listen to changes of cameraPosition by doing this:

  useEffect(() => {
    console.log("cameraPosition updated:", cameraPosition);
  }, [cameraPosition]);

but no success.

there are 2 console.log() positions: the first one does log on every frame when the camera was changed correctly. the second one does not log the cameraPosition. and i just cannot figure out why. it seems the algorithm does not even realize that the cameraPosition changed.

What am i doing wrong here? i want to use cameraPosition in other components too.

any help would be great!

Thanks a lot!

Hannes F
  • 339
  • 2
  • 11

1 Answers1

0

The value of cameraPosition is already camera.position, so when you try and set the new state it compares camera.position with camera.position and correctly decides no update is needed, so no rerender is triggered.

If you want to rerender when the camera position changes, you can change:

setCameraPosition(camera.position)

to

setCameraPosition(camera.position.clone())

However, you don't want to rerender your components every frame, since that is bad for performance. You should try and find an alternate solution to your problem - perhaps run your logic in onAfterInput instead of going through React?

  • yes - the performance is just straight out terrible. I could try to get the logic in `onAfterInput` but if i need the value in other components, how would i do that? – Hannes F Aug 08 '23 at 12:21
  • can you not just use `scene?.cameras[0]?.position` in each of the components? Or if you specifically need it after an input update, move this logic to a custom hook – Samuel Newman Aug 08 '23 at 13:31