React Native Expo加载.glb模型报readAsArrayBuffer未实现解决方法
问题背景
- 项目需求:React Native 应用内展示3D虚拟形象
- 报错场景:
- 从
three/examples/jsm/loaders/GLTFLoader引入GLTFLoader加载.glb格式模型时,触发FileReader.readAsArrayBuffer is not implemented error报错 - 改用
ExpoTHREE.loadAsync方法加载模型时复现相同错误
- 从
- 诉求:获取可正常加载.glb模型到应用内的落地方案
现有项目代码
import { ExpoWebGLRenderingContext, GLView } from "expo-gl"; import ExpoTHREE, { Renderer, TextureLoader } from "expo-three"; import { Asset } from "expo-asset"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import * as React from "react"; import { AmbientLight, BoxBufferGeometry, Fog, GridHelper, Mesh, MeshStandardMaterial, PerspectiveCamera, PointLight, Scene, SpotLight, } from "three"; export default function App() { let timeout; React.useEffect(() => { // 组件卸载时清除动画循环 return () => clearTimeout(timeout); }, []); return ( <GLView style={{ flex: 1 }} onContextCreate={async (gl) => { try { const { drawingBufferWidth: width, drawingBufferHeight: height } = gl; const sceneColor = 0x6ad6f0; // 创建无DOM元素依赖的WebGLRenderer const renderer = new Renderer({ gl }); renderer.setSize(width, height); renderer.setClearColor(sceneColor); const camera = new PerspectiveCamera(70, width / height, 0.01, 1000); camera.position.set(2, 5, 5); const scene = new Scene(); //! 以下加载逻辑无法运行 // const asset = Asset.fromModule(require("./assets/avatar.glb")); // await asset.downloadAsync(); // const loader = new GLTFLoader(); // loader.load(asset.localUri, (group) => { // console.log(group); // // scene.add(group.scene) // }); function update() {} // 启动动画循环 const render = () => { timeout = requestAnimationFrame(render); update(); renderer.render(scene, camera); gl.endFrameEXP(); }; render(); } catch (error) { console.log(error); } }} /> ); }
项目依赖配置
{ "dependencies": { "@react-three/fiber": "^7.0.29", "base64-arraybuffer": "^1.0.2", "expo": "~45.0.0", "expo-file-system": "~14.0.0", "expo-gl": "~11.3.0", "expo-splash-screen": "~0.15.1", "expo-status-bar": "~1.3.0", "expo-three": "^6.1.0", "react": "^17.0.2", "react-dom": "17.0.2", "react-native": "0.68.2", "react-native-dotenv": "^3.3.1", "react-native-unimodules": "^0.14.10", "react-native-web": "0.17.7", "three": "^0.141.0" } }
可行解决方案
报错根因:React Native运行环境没有实现浏览器原生的FileReader API,GLTFLoader的load方法默认走浏览器环境的文件拉取、读取逻辑,直接调用就会触发该错误。
按以下步骤修改即可正常加载:
- 跳过GLTFLoader自带的文件加载逻辑,手动读取本地模型文件转成ArrayBuffer,再交给GLTFLoader解析。你项目中已经安装了
expo-file-system和base64-arraybuffer依赖,不需要额外装包。 - 替换原有注释掉的模型加载代码,参考实现如下:
// 顶部新增引入 import * as FileSystem from 'expo-file-system'; import { decode } from 'base64-arraybuffer'; // 替换onContextCreate内注释的加载逻辑 const asset = Asset.fromModule(require("./assets/avatar.glb")); await asset.downloadAsync(); // 读取本地文件为base64格式 const modelBase64 = await FileSystem.readAsStringAsync(asset.localUri, { encoding: FileSystem.EncodingType.Base64 }); // 转成GLTFLoader可识别的ArrayBuffer const modelArrayBuffer = decode(modelBase64); const loader = new GLTFLoader(); // 直接解析ArrayBuffer,不调用load方法传文件路径 loader.parse( modelArrayBuffer, '', (gltf) => { console.log('模型加载完成'); // 把模型加入场景 scene.add(gltf.scene); // 按需调整模型位置、缩放、旋转参数 gltf.scene.position.set(0, 0, 0); gltf.scene.scale.set(1, 1, 1); }, (err) => { console.log('模型解析失败', err); } );
注意事项
- 禁止直接调用GLTFLoader的
load方法传本地文件uri,该方法强依赖浏览器环境API,React Native环境无法兼容 - 如果开发环境热更新后加载失败,重编译一次APP即可
- 模型材质、纹理如果加载异常,检查glb文件是否把纹理打包在内,未打包的纹理需要用相同逻辑单独读取后赋值给材质
内容的提问来源于stack exchange,提问作者caslawter
相关产品推荐
相关产品推荐

