UNPKG

react-native-filament

Version:

A real-time physically based 3D rendering engine for React Native

108 lines (99 loc) 3.13 kB
import { useBuffer } from './useBuffer'; import { useFilamentContext } from './useFilamentContext'; import { useDisposableResource } from './useDisposableResource'; import usePrevious from './usePrevious'; import { useWorkletEffect } from './useWorkletEffect'; import { useMemo } from 'react'; /** * The resulting filament model, or `'loading'` if not yet available. */ /** * Loads a model from the given source. * * * If you are passing in a `.glb` model or similar from your app's bundle using `require(..)`, make sure to add `glb` as an asset extension to `metro.config.js`! * If you are passing in a `{ url: ... }`, make sure the URL points directly to a `.glb` model. This can either be a web URL (`http://..`/`https://..`), a local file (`file://..`), or an native asset path (`path/to/asset.glb`) * * @worklet * @example * ```ts * const model = useModel(require('model.glb')) * ``` */ export function useModel(source, props) { const { shouldReleaseSourceData = true, addToScene = true, instanceCount } = props ?? {}; const { engine, scene, workletContext } = useFilamentContext(); const assetBuffer = useBuffer({ source: source, releaseOnUnmount: false }); // Note: the native cleanup of the asset will remove it automatically from the scene const asset = useDisposableResource(() => { if (assetBuffer == null) return; if (instanceCount === 0) { throw new Error('instanceCount must be greater than 0'); } return workletContext.runAsync(() => { 'worklet'; let loadedAsset; if (instanceCount == null || instanceCount === 1) { loadedAsset = engine.loadAsset(assetBuffer); } else { loadedAsset = engine.loadInstancedAsset(assetBuffer, instanceCount); } // After loading the asset we can release the buffer assetBuffer.release(); return loadedAsset; }); }, [assetBuffer, workletContext, engine, instanceCount]); useWorkletEffect(() => { 'worklet'; if (asset == null || !shouldReleaseSourceData) { return; } // releases CPU memory for bindings asset.releaseSourceData(); }); // Add or remove from the scene: const previousAddToScene = usePrevious(addToScene); useWorkletEffect(() => { 'worklet'; if (asset == null) return; if (addToScene) { scene.addAssetEntities(asset); } else if (!addToScene && previousAddToScene) { // Only remove when it was previously added (ie. the user set addToScene: false) scene.removeAssetEntities(asset); } }); const boundingBox = useMemo(() => { if (asset == null) return undefined; return asset.getBoundingBox(); }, [asset]); const rootEntity = useMemo(() => { if (asset == null) { return null; } return asset.getRoot(); }, [asset]); if (assetBuffer == null || asset == null || boundingBox == null || rootEntity == null) { return { state: 'loading' }; } return { state: 'loaded', asset: asset, rootEntity: rootEntity, boundingBox: boundingBox }; } //# sourceMappingURL=useModel.js.map