react-native-filament
Version:
A real-time physically based 3D rendering engine for React Native
108 lines (99 loc) • 3.13 kB
JavaScript
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