Wondering what’s next for npm?Check out our public roadmap! »

    expo-three
    TypeScript icon, indicating that this package has built-in type declarations

    5.7.0 • Public • Published

    Welcome to Expo & Three.JS 👋

    Tools for using three.js to create universal 3D experiences | Try it in the browser!

    GitHub Actions status

    Twitter: expo Medium: exposition

    This package bridges Three.js to Expo GL - a package which provides a WebGL interface for native OpenGL-ES in React. Largely this helps with abstracting the DOM parts away from Three.js.

    AR was moved to expo-three-ar in expo-three@5.0.0

    Quick Start

    Create a universal React project with expo-three setup:

    npx create-react-native-app -t with-three

    For a more declarative interface, you can use this package with react-three-fiber. You can bootstrap that with:

    npx create-react-native-app -t with-react-three-fiber

    Installation

    In expo-three@5.0.0 Three.js is a peer dependency

    yarn add three expo-three expo-gl

    Usage

    Import the library into your project file:

    import { Renderer } from 'expo-three';

    Get a global instance of three.js from expo-three:

    import { THREE } from 'expo-three';

    🚨 You'll need to use a physical device as the iOS Simulators and Android emulators do not work well with Three.js + EXGL.

    Due to some issues with the Metro bundler you may need to manually define the global instance of Three.js. This is important because three.js doesn't fully use ECMAScript but rather mutates a single global instance of THREE with side-effects.

    global.THREE = global.THREE || THREE;

    Creating a Renderer

    Given a gl from a GLView, return a THREE.WebGLRenderer that draws to it.

    import * as React from 'react';
    import { ExpoWebGLRenderingContext, GLView } from 'expo-gl';
    import { Renderer } from 'expo-three';
    
    export default function App() {
      return (
        <GLView
          style={{ flex: 1 }}
          onContextCreate={(gl: ExpoWebGLRenderingContext) => {
            // Create a WebGLRenderer without a DOM element
            const renderer = new Renderer({ gl });
            renderer.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);
          }}
        />
      );
    }

    Loading assets

    The Metro bundler cannot load arbitrary file types like (.obj, .mtl, .dae, etc..). In order to support them you must create a ./metro.config.js in your project root, and add the file extensions you want to support.

    metro.config.js

    module.exports = {
      resolver: {
        assetExts: ['db', 'mp3', 'ttf', 'obj', 'png', 'jpg'],
      },
    };

    All assets require a local URI to be loaded. You can resolve a local URI with expo-asset.

    import { Asset } from 'expo-asset';
    
    // Create an Asset from a resource
    const asset = Asset.fromModule(require('./image.png'));
    
    await asset.downloadAsync();
    
    // This is the local URI
    const uri = asset.localUri;

    Loading a texture

    After you have an asset loaded, you can use it to create a Three.js Texture. expo-three provides a helper utility that can resolve the asset internally and make other modifications to support a wider variety of images:

    import { TextureLoader } from 'expo-three';
    
    // This texture will be immediately ready but it'll load asynchronously
    const texture = new TextureLoader().load(require('./img.png'));

    Optionally, you can create a texture from the local URI manually (this may not work for most image types):

    import { TextureLoader } from 'three';
    import { Asset } from 'expo-asset';
    
    // Create an Asset from a resource
    const asset = Asset.fromModule(require('./img.png'));
    
    await asset.downloadAsync();
    // This texture will be immediately ready but it'll load asynchronously
    const texture = new TextureLoader().load(asset.localUri);

    Loading an obj model

    Be sure to add support for whatever model extension you wish to load to your metro.config.js, then you can load a model using the local URI:

    // Import from jsm for smaller bundles and faster apps
    import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
    import { Asset } from 'expo-asset';
    
    const asset = Asset.fromModule(require('./model.obj'));
    await asset.downloadAsync();
    
    const loader = new OBJLoader();
    loader.load(asset.localUri, group => {
      // Model loaded...
    });

    ExpoTHREE.loadAsync()

    A function that will asynchronously load files based on their extension.

    Notice: Remember to update your metro.config.js to bundle obscure file types!

    metro.config.js

    module.exports = {
      resolver: {
        assetExts: ['db', 'mp3', 'ttf', 'obj', 'png', 'jpg'],
      },
    };

    Props

    Property Type Description
    resource PossibleAsset The asset that will be parsed asynchornously
    onProgress (xhr) => void A function that is called with an xhr event
    assetProvider () => Promise<Expo.Asset> A function that is called whenever an unknown asset is requested
    PossibleAsset Format

    export type PossibleAsset = Expo.Asset | number | string | AssetFormat;

    type PossibleAsset = number | string | Expo.Asset;
    • number: Static file reference require('./model.*')
    • Expo.Asset: Expo.Asset
    • string: A uri path to an asset

    Returns

    This returns many different things, based on the input file. For a more predictable return value you should use one of the more specific model loaders.

    Example

    const texture = await ExpoTHREE.loadAsync(
      'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'
    );

    Loaders

    loadAsync(assetReference, onProgress, onAssetRequested)

    A universal loader that can be used to load images, models, scenes, and animations. Optionally more specific loaders are provided with less complexity.

    // A THREE.Texture from a static resource.
    const texture = await ExpoTHREE.loadAsync(require('./icon.png'));
    const obj = await ExpoTHREE.loadAsync(
      [require('./cartman.obj'), require('./cartman.mtl')],
      null,
      imageName => resources[imageName]
    );
    const { scene } = await ExpoTHREE.loadAsync(
      resources['./kenny.dae'],
      onProgress,
      resources
    );

    loadObjAsync({ asset, mtlAsset, materials, onAssetRequested, onMtlAssetRequested })

    🚨 Deprecated: Load OBJ files manually with the JS module three/examples/jsm/loaders/OBJLoader

    Props

    • asset: a obj model reference that will be evaluated using AssetUtils.resolveAsync
    • mtlAsset: an optional prop that will be loaded using loadMtlAsync()
    • onAssetRequested: A callback that is used to evaluate urls found within the asset and optionally the mtlAsset. You can also just pass in a dictionary of key values if you know the assets required ahead of time.
    • materials: Optionally you can provide an array of materials returned from loadMtlAsync()
    • onMtlAssetRequested: If provided this will be used to request assets in loadMtlAsync()

    This function is used as a more direct method to loading a .obj model. You should use this function to debug when your model has a corrupted format.

    const mesh = await loadObjAsync({ asset: 'https://www.members.com/chef.obj' });

    loadTextureAsync({ asset })

    🚨 Deprecated: Load textures manually with the JS module from three

    Props

    • asset: an Expo.Asset that could be evaluated using AssetUtils.resolveAsync if localUri is missing or the asset hasn't been downloaded yet.

    This function is used as a more direct method to loading an image into a texture. You should use this function to debug when your image is using an odd extension like .bmp.

    const texture = await loadTextureAsync({ asset: require('./image.png') });

    loadMtlAsync({ asset, onAssetRequested })

    🚨 Deprecated: Load MTL files manually with the JS module three/examples/jsm/loaders/MTLLoader

    Props

    • asset: a mtl material reference that will be evaluated using AssetUtils.resolveAsync
    • onAssetRequested: A callback that is used to evaluate urls found within the asset, optionally you can just pass in a dictionary of key values if you know the assets required ahead of time.
    const materials = await loadMtlAsync({
      asset: require('chef.mtl'),
      onAssetRequested: modelAssets,
    });

    loadDaeAsync({ asset, onAssetRequested, onProgress })

    🚨 Deprecated: Load DAE files manually with the JS module three/examples/jsm/loaders/ColladaLoader

    Props

    • asset: a reference to a dae scene that will be evaluated using AssetUtils.resolveAsync
    • onAssetRequested: A callback that is used to evaluate urls found within the asset, optionally you can just pass in a dictionary of key values if you know the assets required ahead of time.
    • onProgress: An experimental callback used to track loading progress.
    const { scene } = await loadDaeAsync({
      asset: require('chef.dae'),
      onAssetRequested: modelAssets,
      onProgress: () => {},
    });

    ExpoTHREE.utils

    These are Three.js utilities that aren't required for using Three.js with Expo.

    ExpoTHREE.utils.alignMesh()

    Props

    type Axis = {
      x?: number,
      y?: number,
      z?: number,
    };
    Property Type Description
    mesh &THREE.Mesh The mesh that will be manipulated
    axis ?Axis Set the relative center axis

    Example

    ExpoTHREE.utils.alignMesh(mesh, { x: 0.0, y: 0.5 });

    ExpoTHREE.utils.scaleLongestSideToSize()

    Props

    Property Type Description
    mesh &THREE.Mesh The mesh that will be manipulated
    size number The size that the longest side of the mesh will be scaled to

    Example

    ExpoTHREE.utils.scaleLongestSideToSize(mesh, 3.2);

    ExpoTHREE.utils.computeMeshNormals()

    Used for smoothing imported geometry, specifically when imported from .obj models.

    Props

    Property Type Description
    mesh &THREE.Mesh The mutable (inout) mesh that will be manipulated

    Example

    ExpoTHREE.utils.computeMeshNormals(mesh);

    THREE Extensions

    suppressMetroWarnings

    A function that suppresses EXGL compatibility warnings and logs them instead. By default this is enabled on native because it can cause the Metro development server to slow down significantly. You will need to import the ExpoTHREE.THREE global instance to use this. By default this function will be activated on import.

    • shouldSuppress: boolean
    import { THREE } from 'expo-three';
    THREE.suppressMetroWarnings();

    Links

    Somewhat out of date

    🤝 Contributing

    Contributions, issues and feature requests are welcome!
    Feel free to check issues page.

    Show your support

    Give a ⭐️ if this project helped you!

    📝 License

    Copyright © 2019 650 Industries.
    This project is MIT licensed.

    Install

    npm i expo-three

    DownloadsWeekly Downloads

    1,289

    Version

    5.7.0

    License

    MIT

    Unpacked Size

    86.6 kB

    Total Files

    72

    Last publish

    Collaborators

    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar