Skip to content

expo/expo-three

Repository files navigation

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 bridgesThree.jstoExpo 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 toexpo-three-arin[email protected]

Quick Start

Create a universal React project withexpo-threesetup:

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

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

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

Installation

In[email protected]and higher, Three.js is apeer 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 ofthree.jsfromexpo-three:

import{THREE}from'expo-three';

🚨 You'll need touse a physical deviceas the iOS Simulators and Android emulators do not work well with Three.js + EXGL.

Due to some issues with theMetro bundleryou 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 ofTHREEwith side-effects.

global.THREE=global.THREE||THREE;

Creating a Renderer

Given aglfrom aGLView,return a THREE.WebGLRenderer that draws to it.

import*asReactfrom'react';
import{ExpoWebGLRenderingContext,GLView}from'expo-gl';
import{Renderer}from'expo-three';

exportdefaultfunctionApp(){
return(
<GLView
style={{flex:1}}
onContextCreate={(gl:ExpoWebGLRenderingContext)=>{
// Create a WebGLRenderer without a DOM element
constrenderer=newRenderer({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.jsin 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 withexpo-asset.

import{Asset}from'expo-asset';

// Create an Asset from a local resource
const[{localUri}]=awaitAsset.loadAsync(require('./image.png'));

Loading a texture

After you have an asset loaded, you can use it to create a Three.js Texture.expo-threeprovides 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
consttexture=newTextureLoader().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[{localUri}]=awaitAsset.loadAsync(require('./img.png'));

// This texture will be immediately ready but it'll load asynchronously
consttexture=newTextureLoader().load(localUri);

Loading an obj model

Be sure to add support for whatever model extension you wish to load to yourmetro.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[{localUri}]=awaitAsset.loadAsync(require('./model.obj'));

constloader=newOBJLoader();
loader.load(localUri,group=>{
// Model loaded...
});

ExpoTHREE.loadAsync()

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

Notice:Remember to update yourmetro.config.jsto 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;

typePossibleAsset=number|string|Expo.Asset;
  • number:Static file referencerequire('./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

consttexture=awaitExpoTHREE.loadAsync(
'https:// google /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.
consttexture=awaitExpoTHREE.loadAsync(require('./icon.png'));
constobj=awaitExpoTHREE.loadAsync(
[require('./cartman.obj'),require('./cartman.mtl')],
null,
imageName=>resources[imageName]
);
const{scene}=awaitExpoTHREE.loadAsync(
resources['./kenny.dae'],
onProgress,
resources
);

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

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

Props

  • asset:aobjmodel reference that will be evaluated usingAssetUtils.resolveAsync
  • mtlAsset:an optional prop that will be loaded usingloadMtlAsync()
  • onAssetRequested:A callback that is used to evaluate urls found within theassetand optionally themtlAsset.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 fromloadMtlAsync()
  • onMtlAssetRequested:If provided this will be used to request assets inloadMtlAsync()

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

constmesh=awaitloadObjAsync({asset:'https:// members /chef.obj'});

loadTextureAsync({ asset })

🚨Deprecated:Load textures manually with the JS module fromthree

Props

  • asset:anExpo.Assetthat could be evaluated usingAssetUtils.resolveAsynciflocalUriis 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.

consttexture=awaitloadTextureAsync({asset:require('./image.png')});

loadMtlAsync({ asset, onAssetRequested })

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

Props

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

loadDaeAsync({ asset, onAssetRequested, onProgress })

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

Props

  • asset:a reference to adaescene that will be evaluated usingAssetUtils.resolveAsync
  • onAssetRequested:A callback that is used to evaluate urls found within theasset,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}=awaitloadDaeAsync({
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

typeAxis={
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 puteMeshNormals()

Used for smoothing imported geometry, specifically when imported from.objmodels.

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 theExpoTHREE.THREEglobal instance to use this. By default this function will be activated on import.

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

Running the example app

Clone the repo andcd expo-threethen run:

yarn
yarn build
#CMD+C to exit build watch mode
cdexample
npx expo prebuild
npx expo run:android#or npx expo run:ios

⛓ Links

Somewhat out of date

🤝 Contributing

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

Show your support

Give a ⭐️ if this project helped you!

📝 License

Copyright © 2019-2022650 Industries.
This project isMITlicensed.