1import { ExpoWebGLRenderingContext, GLView } from 'expo-gl'; 2import { Renderer, TextureLoader } from 'expo-three'; 3import * as React from 'react'; 4import { LayoutChangeEvent, PixelRatio, StyleSheet, View } from 'react-native'; 5import { PerspectiveCamera, Scene, Sprite, SpriteMaterial } from 'three'; 6 7export default function GLThreeSprite() { 8 const animationFrameId = React.useRef(-1); 9 const gl = React.useRef<null | ExpoWebGLRenderingContext>(null); 10 const camera = React.useRef<null | PerspectiveCamera>(null); 11 const scene = React.useRef<null | Scene>(null); 12 const renderer = React.useRef<null | Renderer>(null); 13 14 React.useEffect(() => { 15 return () => { 16 if (animationFrameId.current >= 0) { 17 cancelAnimationFrame(animationFrameId.current); 18 } 19 }; 20 }, []); 21 22 const animate = React.useCallback(() => { 23 animationFrameId.current = requestAnimationFrame(animate); 24 25 if (renderer.current && scene.current && camera.current) 26 renderer.current.render(scene.current, camera.current); 27 28 if (gl.current) { 29 gl.current.endFrameEXP(); 30 } 31 }, []); 32 33 React.useEffect(() => { 34 if (animationFrameId.current) { 35 cancelAnimationFrame(animationFrameId.current); 36 animate(); 37 } 38 }, [animate]); 39 40 const onLayout = React.useCallback(({ nativeEvent: { layout } }: LayoutChangeEvent) => { 41 if (camera.current) { 42 camera.current.aspect = layout.width / layout.height; 43 camera.current.updateProjectionMatrix(); 44 } 45 if (renderer.current) { 46 const scale = PixelRatio.get(); 47 renderer.current.setSize(layout.width * scale, layout.height * scale); 48 } 49 }, []); 50 51 const onContextCreate = React.useCallback( 52 async (context: ExpoWebGLRenderingContext) => { 53 gl.current = context; 54 scene.current = new Scene(); 55 camera.current = new PerspectiveCamera( 56 75, 57 gl.current.drawingBufferWidth / gl.current.drawingBufferHeight, 58 0.1, 59 1000 60 ); 61 62 renderer.current = new Renderer({ gl: gl.current }); 63 renderer.current.setSize(gl.current.drawingBufferWidth, gl.current.drawingBufferHeight); 64 renderer.current.setClearColor(0xffffff); 65 66 const spriteMaterial = new SpriteMaterial({ 67 map: new TextureLoader().load(require('../../../assets/images/nikki.png')), 68 color: 0xffffff, 69 }); 70 const sprite = new Sprite(spriteMaterial); 71 scene.current.add(sprite); 72 73 camera.current.position.z = 3; 74 75 animate(); 76 renderer.current.render(scene.current, camera.current); 77 gl.current.endFrameEXP(); 78 }, 79 [animate] 80 ); 81 82 return ( 83 <View style={styles.flex}> 84 <GLView style={styles.flex} onLayout={onLayout} onContextCreate={onContextCreate} /> 85 </View> 86 ); 87} 88 89GLThreeSprite.title = 'three.js sprite rendering'; 90 91const styles = StyleSheet.create({ 92 flex: { 93 flex: 1, 94 }, 95}); 96