A library that provides GLView that acts as an OpenGL ES render target and provides GLContext. Useful for rendering 2D and 3D graphics.
expo-gl
provides a View
that acts as an OpenGL ES render target, useful for rendering 2D and 3D graphics. On mounting, an OpenGL ES context is created. Its drawing buffer is presented as the contents of the View
every frame.
Android Device | Android Emulator | iOS Device | iOS Simulator | Web |
---|---|---|---|---|
-
npx expo install expo-gl
If you're installing this in a bare React Native app, you should also follow these additional installation instructions.
import React from 'react';
import { View } from 'react-native';
import { GLView } from 'expo-gl';
export default function App() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<GLView style={{ width: 300, height: 300 }} onContextCreate={onContextCreate} />
</View>
);
}
function onContextCreate(gl) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 1, 1, 1);
// Create vertex shader (shape & position)
const vert = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(
vert,
`
void main(void) {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 150.0;
}
`
);
gl.compileShader(vert);
// Create fragment shader (color)
const frag = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(
frag,
`
void main(void) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
`
);
gl.compileShader(frag);
// Link together into a program
const program = gl.createProgram();
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
gl.useProgram(program);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
gl.flush();
gl.endFrameEXP();
}
Since the WebGL API is quite low-level, it can be helpful to use higher-level graphics APIs rendering through a GLView
underneath. The following libraries integrate popular graphics APIs:
Any WebGL-supporting library that expects a WebGLRenderingContext could be used. Some times such libraries assume a web JavaScript context (such as assuming document
). Usually this is for resource loading or event handling, with the main rendering logic still only using pure WebGL. So these libraries can usually still be used with a couple workarounds. The Expo-specific integrations above include workarounds for some popular libraries.
To use this API inside Reanimated worklet, you need to pass the GL context ID to the worklet and recreate the GL object like in the example below.
import React from 'react';
import { View } from 'react-native';
import { runOnUI } from 'react-native-reanimated';
import { GLView } from 'expo-gl';
function render(gl) {
'worklet';
// add your WebGL code here
}
function onContextCreate(gl) {
runOnUI((contextId: number) => {
'worklet';
const gl = GLView.getWorkletContext(contextId);
render(gl);
})(gl.contextId);
}
export default function App() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<GLView style={{ width: 300, height: 300 }} onContextCreate={onContextCreate} />
</View>
);
}
For more in-depth example on how to use expo-gl
with Reanimated and Gesture Handler you can check this example.
Worklet runtime is imposing some limitations on the code that runs inside it, so if you have existing WebGL code, it'll likely require some modifications to run inside a worklet thread.
'worklet'
added at the start.expo-assets
you can just pass asset object returned by Asset.fromModule
or from hook useAssets
to the runOnUI
function.requestAnimationFrame
, APIs like setTimeout
are not supported.Check Reanimated documentation to learn more.
This API does not function as intended with remote debugging enabled. The React Native debugger runs JavaScript on your computer, not the mobile device. GLView requires synchronous native calls that are not supported in Chrome.
import { GLView } from 'expo-gl';
GLView
Type: React.Component<GLViewProps>
A component that acts as an OpenGL render target
nativeRef_EXPERIMENTAL
Optional • Type: (callback: ComponentOrHandle) => any
A ref callback for the native GLView
onContextCreate
Type: (gl: ExpoWebGLRenderingContext) => void
Called when the OpenGL context is created, with the context object as a parameter. The context object has an API mirroring WebGL's WebGLRenderingContext.
destroyContextAsync(exgl)
Name | Type | Description |
---|---|---|
exgl (optional) | number | ExpoWebGLRenderingContext | - |
Returns
Promise<boolean>
takeSnapshotAsync(exgl, options)
Name | Type | Description |
---|---|---|
exgl (optional) | number | ExpoWebGLRenderingContext | - |
options (optional) | SnapshotOptions | - |
Returns
createCameraTextureAsync(cameraRefOrHandle)
Name | Type | Description |
---|---|---|
cameraRefOrHandle | ComponentOrHandle | - |
Returns
ExpoWebGLRenderingContext
Extends: WebGL2RenderingContext
ExpoWebGLRenderingContext Methods
ExpoWebGLRenderingContext Properties
Name | Type | Description |
---|---|---|
contextId | number | - |
ComponentOrHandle
Acceptable values are: null
, number
, Component<any, any>
, ComponentClass<any>
.
GLSnapshot
Name | Type | Description |
---|---|---|
height | number | - |
localUri | string | - |
uri | string | Blob | null | - |
width | number | - |
SnapshotOptions
Name | Type | Description |
---|---|---|
compress (optional) | number | - |
flip (optional) | boolean | - |
format (optional) | 'jpeg' | 'png' | - |
framebuffer (optional) | WebGLFramebuffer | - |
rect (optional) | {
height: number,
width: number,
x: number,
y: number
} | - |
SurfaceCreateEvent
Name | Type | Description |
---|---|---|
nativeEvent | {
exglCtxId: number
} | - |
GLLoggingOption
GLLoggingOption Values
GET_ERRORS
GLLoggingOption.GET_ERRORS = 2
Calls gl.getError()
after each other method call and prints an error if any is returned.
This option has a significant impact on the performance as this method is blocking.
RESOLVE_CONSTANTS
GLLoggingOption.RESOLVE_CONSTANTS = 4
Resolves parameters of type number
to their constant names.
TRUNCATE_STRINGS
GLLoggingOption.TRUNCATE_STRINGS = 8
When this option is enabled, long strings will be truncated. It's useful if your shaders are really big and logging them significantly reduces performance.
ALL
GLLoggingOption.ALL = 15
Enables all other options. It implies GET_ERRORS
so be aware of the slowdown.
Once the component is mounted and the OpenGL ES context has been created, the gl
object received through the onContextCreate
prop becomes the interface to the OpenGL ES context, providing a WebGL API. It resembles a WebGL2RenderingContext in the WebGL 2 spec.
Some older Android devices may not support WebGL2 features. To check whether the device supports WebGL2 it's recommended to use gl instanceof WebGL2RenderingContext
.
An additional method gl.endFrameEXP()
is present, which notifies the context that the current frame is ready to present. This is similar to a 'swap buffers' API call in other OpenGL platforms.
The following WebGL2RenderingContext methods are currently unimplemented:
getFramebufferAttachmentParameter()
getRenderbufferParameter()
compressedTexImage2D()
compressedTexSubImage2D()
getTexParameter()
getUniform()
getVertexAttrib()
getVertexAttribOffset()
getBufferSubData()
getInternalformatParameter()
renderbufferStorageMultisample()
compressedTexImage3D()
compressedTexSubImage3D()
fenceSync()
isSync()
deleteSync()
clientWaitSync()
waitSync()
getSyncParameter()
getActiveUniformBlockParameter()
The pixels
argument of texImage2D()
must be null
, an ArrayBuffer
with pixel data, or an object of the form { localUri }
where localUri
is the file://
URI of an image in the device's file system. Thus, an Asset
object is used once .downloadAsync()
has been called on it (and completed) to fetch the resource.
For efficiency reasons, the current implementations of the methods don't perform type or bounds checking on their arguments. So, passing invalid arguments may cause a native crash. There are plans to update the API to perform argument checking in upcoming SDK versions.
Currently, the priority for error checking is low since engines generally don't rely on the OpenGL API to perform argument checking; otherwise, checks performed by the underlying OpenGL ES implementation are often sufficient.