Execute callback after model is ready in r3f

Hello,

In my R3F app I am loading a gltf model with animations. Once this is fully loaded, I want to calculate its bounding box. Unfortunately, it is currently the case that the bounding box is calculated too early and is therefore incorrect.

I am currently working around this as follows:

useEffect(() => {
    setTimeout(() => getBoundingBox(), 0)
}, [])

But this is not really a solution for me. Is there a way to execute the function as soon as the model is really fully loaded?

It makes no difference whether I use useEffect or useLayoutEffect.

Best

There is the onAfterRender property on meshes (including skinned meshes), maybe you could choose some mesh in your component rendering your gltf (if you are using gltfjsx to componentize your model which I guess you’re doing – if not it’s definitely worth it) and pass it some handler to calculate the bb, perhaps via a ref, from there.

useLayoutEffect fires before paint (threejs render), useEffect after. you can calculate bounds in uLE and apply it before paint so you dont get FOUC but beware that worldmatrices werent updated by three yet, so: ref.current.updateWorldMatrix(true, true). you do not need timeouts and hacks like that. it’s just the world matrix you’re clashing against.

is this for centering?

Thank you, updating the world matrix before calculating the bounding box solved it! :slight_smile:

No, I want to place different models next to each other. For centering I use your Bounds component :+1:

Sure, I use gltf2jsx. It seems that onAfterRender is called after each render but I will play around with it. Maybe it will fit my needs.

@drcmda:
I use rendering on demand, but have partial problems with it. When I load a new model or change the material, the scene is rendered while the scene is still “working”. That is, you see the model appear, but on it first receives the material and the position is adjusted. Of course, I want to show the finished scene first. In BabylonJs there is a function scene.executeWhenReady(). Is there the possibility to achieve something similar?

Another problem is when I play an animation, it is of course not visible when rendering on demand. My idea for this was to call invalidate(60) for example. Unfortunately the animation does not run smoothly with this and jumps.

Can you please give me some advice on this?

1 Like

im asking because drei has a center component, it’s perfect from placing objects next to one another. it was broken for a long time but i just got around fixing it: Text3D alignment - CodeSandbox

type Props = JSX.IntrinsicElements['group'] & {
  top?: boolean
  right?: boolean
  bottom?: boolean
  left?: boolean
}
<Center top left>
  <mesh />
</Center>

there is also a new bbanchor component that allows you to place content along the positive or negative axis of a targets bounds. GitHub - pmndrs/drei: 🥉 useful helpers for react-three-fiber

see it in action here: object gizmo controls - CodeSandbox

@drcmda this may be worthy of a separate topic but I would like to ask here for the sake of confluence, is it possible to use Center with spring animations for placing multiple objects one relative to another? maybe by assigning some ref to the center component you can base offsets off?

glad you found a way to make it work!