如何使用expo-three在Expo React Native应用中加载渲染本地.obj格式3D模型
问题排查与修复方案
现存问题梳理
- 缺失
GLView组件引入,该组件是Expo下3D渲染的核心依赖,需从expo-gl包导入 - 未配置Expo打包规则,默认不会识别.obj后缀的静态资源,会导致资源加载失败
- 未给模型设置可见材质,OBJLoader加载的模型默认材质在当前弱光环境下几乎不可见
timeout变量未声明,运行时会抛出未定义错误- 无加载异常捕获逻辑,无法定位是资源加载失败还是渲染逻辑问题
修复步骤
1. 安装缺失依赖
执行命令安装必要包:npm install expo-gl expo-three three expo-asset
2. 配置app.json支持.obj资源
在项目根目录的app.json中,给expo字段添加如下配置,让打包工具识别.obj格式资源:
{ "expo": { "packagerOpts": { "assetExts": ["obj", "mtl", "png", "jpg"] }, "assetBundlePatterns": [ "**/*" ] } }
如果你的模型附带.mtl材质文件和纹理图,也需要把对应后缀加到assetExts中。
3. 修正代码逻辑
下面是可直接运行的完整代码:
import { Renderer } from 'expo-three'; import * as React from 'react'; import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; import { AmbientLight, Fog, GridHelper, PerspectiveCamera, PointLight, Scene, SpotLight, MeshStandardMaterial } from 'three'; import { Asset } from 'expo-asset'; import { GLView } from 'expo-gl'; export default function ThreeDPhytosaur() { let timeout = null; React.useEffect(() => { return () => { if (timeout) cancelAnimationFrame(timeout); } }, []); return ( <GLView style={{ flex: 1 }} onContextCreate={async (gl) => { try { const { drawingBufferWidth: width, drawingBufferHeight: height } = gl; const sceneColor = 0x6ad6f0; 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(); scene.fog = new Fog(sceneColor, 1, 10000); scene.add(new GridHelper(10, 10)); // 调高环境光亮度,确保模型可见 const ambientLight = new AmbientLight(0xffffff, 1.2); scene.add(ambientLight); const pointLight = new PointLight(0xffffff, 2, 1000, 1); pointLight.position.set(0, 200, 200); scene.add(pointLight); const spotLight = new SpotLight(0xffffff, 0.5); spotLight.position.set(0, 500, 100); spotLight.lookAt(scene.position); scene.add(spotLight); const asset = Asset.fromModule(model['phytosaur']); await asset.downloadAsync(); const objectLoader = new OBJLoader(); const object = await objectLoader.loadAsync(asset.uri); // 给所有网格加测试材质,方便确认是否渲染成功 object.traverse((child) => { if (child.isMesh) { child.material = new MeshStandardMaterial({ color: 0x2196F3, roughness: 0.5 }); } }); // 根据你的模型尺寸调整缩放,太小可以改大到0.1、1测试 object.scale.set(0.025, 0.025, 0.025); object.position.set(0, 0, 0); scene.add(object); camera.lookAt(object.position); const render = () => { timeout = requestAnimationFrame(render); // 加个缓慢旋转动画,确认模型在正常渲染 object.rotation.y += 0.01; renderer.render(scene, camera); gl.endFrameEXP(); }; render(); } catch (e) { console.log('加载错误:', e); } }} /> ); } const model = { 'phytosaur': require('../assets/phytosaur.obj'), };
4. 调试提示
如果还是看不到模型,按以下顺序排查:
- 看控制台有没有报错,确认资源路径正确、模型文件没有损坏
- 把模型缩放值调大,比如改成1、10,很多.obj模型本身尺寸很小,缩放过度会看不到
- 把相机位置往后移,比如改成
camera.position.set(0, 0, 20),避免模型在视锥近截面外 - 移除GridHelper,避免网格挡住模型
内容的提问来源于stack exchange,提问作者MonicaM
相关产品推荐
相关产品推荐

