You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native中用Three.js加载图片纹理?解决TextureLoader兼容问题

我之前在React Native里用Three.js处理3D纹理的时候也遇到过这个问题,核心原因就是Three.js原生的TextureLoader依赖浏览器环境的document和DOM canvas对象,而React Native没有这些浏览器特有的API,所以直接用肯定会报错。下面给你几个可行的解决方案,按推荐程度排序:

解决方案1:使用Expo生态的expo-three(推荐Expo项目)

如果你用Expo开发,expo-three是官方维护的适配库,它已经帮你处理了React Native和Three.js的环境兼容,包括纹理加载的问题。

步骤:

  1. 安装依赖
expo install expo-three three
  1. 加载纹理并应用到3D模型
    下面是一个完整的示例,加载本地图片作为立方体纹理:
import React, { useEffect, useRef } from 'react';
import { View } from 'react-native';
import { GLView } from 'expo-gl';
import * as THREE from 'three';
import { loadAsync } from 'expo-three';

export default function App() {
  const glViewRef = useRef(null);

  useEffect(() => {
    if (!glViewRef.current) return;

    const initScene = async (gl) => {
      // 初始化Three.js核心对象
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(
        75,
        gl.drawingBufferWidth / gl.drawingBufferHeight,
        0.1,
        1000
      );
      const renderer = new THREE.WebGLRenderer({ gl });
      renderer.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);

      // 加载本地纹理:用expo-three的loadAsync替代原生TextureLoader
      const texture = await loadAsync(require('./assets/texture.png'));
      texture.needsUpdate = true; // 确保纹理被Three.js正确识别

      // 创建带纹理的立方体
      const geometry = new THREE.BoxGeometry(1, 1, 1);
      const material = new THREE.MeshBasicMaterial({ map: texture });
      const cube = new THREE.Mesh(geometry, material);
      scene.add(cube);

      camera.position.z = 5;

      // 动画循环
      const animate = () => {
        requestAnimationFrame(animate);
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        renderer.render(scene, camera);
        gl.endFrameEXP(); // 必须调用这个方法结束Expo GL帧
      };
      animate();

      // 组件卸载时清理资源
      return () => {
        renderer.dispose();
      };
    };

    glViewRef.current.onContextCreate = initScene;
  }, []);

  return (
    <View style={{ flex: 1 }}>
      <GLView ref={glViewRef} style={{ flex: 1 }} />
    </View>
  );
}

如果要加载网络图片,直接把require('./assets/texture.png')换成图片URL即可,比如'https://example.com/your-texture.png'。

解决方案2:使用react-native-three(纯React Native项目)

如果你没有用Expo,react-native-three是专门为React Native打造的Three.js封装库,它提供了JSX风格的组件,让纹理加载变得更简单。

步骤:

  1. 安装依赖
npm install react-native-three three @react-native-community/image-editor
# 或者用yarn
yarn add react-native-three three @react-native-community/image-editor
  1. 快速实现纹理加载
    下面是一个极简示例,用JSX组件直接渲染带纹理的立方体:
import React from 'react';
import { View } from 'react-native';
import { Canvas, Mesh, BoxGeometry, MeshBasicMaterial, Texture } from 'react-native-three';

export default function App() {
  return (
    <View style={{ flex: 1 }}>
      <Canvas>
        <Mesh>
          <BoxGeometry args={[1, 1, 1]} />
          <MeshBasicMaterial>
            {/* 直接通过source属性传入本地或网络图片 */}
            <Texture source={require('./assets/texture.png')} />
          </MeshBasicMaterial>
        </Mesh>
      </Canvas>
    </View>
  );
}

这个库会自动处理RN环境下的图片加载和纹理转换,不需要手动处理WebGL上下文的细节。

手动适配方案(不推荐,适合自定义需求)

如果你不想依赖封装库,也可以手动通过React Native的Image API获取图片数据,再转换成Three.js纹理:

  1. 用Image.getSize获取图片尺寸,然后用Image.resolveAssetSource获取图片的URI
  2. 创建一个THREE.Texture,并将图片数据传入(通常需要转成ArrayBuffer或base64)
  3. 在WebGL上下文中手动更新纹理

不过这种方法需要处理很多底层细节,容易出问题,除非你有特殊的自定义需求,否则更推荐前面两种方案。

注意事项:

  • 本地图片路径要正确,React Native中require的资源必须是静态资源,不能用动态路径
  • 加载网络图片时,确保图片服务器允许跨域访问(RN本身没有浏览器的跨域限制,但有些服务器会限制Referer)
  • 加载完成后记得设置texture.needsUpdate = true,确保Three.js更新纹理缓存

内容的提问来源于stack exchange,提问作者M.Kumaran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:35:13