Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 1x 6x 6x 6x 4x 2x 2x 2x 2x 2x 2x 6x | import { useLayoutEffect, useState } from 'react';
import { useApp } from '@playcanvas/react/hooks';
import { Entity } from 'playcanvas';
import { adoptSceneCamera } from './camera-adoption';
/**
* Keeps the walkthrough's rig holding a camera for as long as the viewer is mounted, adopting the
* scene's own when the viewer wasn't given one. See {@link adoptSceneCamera} for why.
*
* @param rig - The `camera-root` entity, or null before it exists.
* @param ownCamera - The entity the viewer mounts its own camera on, or null before it exists.
* @returns The adopted camera, or null when the viewer brought one of its own. Held as state so the
* viewer re-renders and re-points everything that addresses the camera at the entity now carrying
* it.
*/
export const useAdoptedCamera = (rig: Entity | null, ownCamera: Entity | null): Entity | null => {
const app = useApp();
const [adopted, setAdopted] = useState<Entity | null>(null);
// A layout effect, so that the camera is handed back before the rig it was parented into is
// destroyed. `@playcanvas/react`'s Entity destroys its entity in a layout effect's teardown, and
// destroying an entity destroys its children — so a release deferred to a passive effect runs
// after the host's camera has already been destroyed along with the walkthrough, leaving the host
// scene with no camera to render through at all.
//
// The rig is a child of the viewer, and React tears an unmounting tree's layout effects down from
// the top, so this runs first.
useLayoutEffect(() => {
if (!rig || !ownCamera) {
return;
}
// Both entities are state set from refs, so this runs a commit after the child that mounts the
// camera component: a viewer that was given a camera is recognised as owning one rather than
// adopted on top of.
const adoption = adoptSceneCamera(app.root, rig, ownCamera);
setAdopted(adoption?.camera ?? null);
return () => {
adoption?.release();
setAdopted(null);
};
}, [app, rig, ownCamera]);
return adopted;
};
export default useAdoptedCamera;
|