试图加载obj&在React Native中使用Three.js的mtl文件

时间:2018-05-05 13:31:23

标签: react-native three.js

主要目标:将从Maya导出的动画模型加载到React Native应用中 导出的文件: obj,mtl& png文件

我在我的React Native项目中设置了https://github.com/react-community/react-native-webgl,它运行正常。

现在,当我尝试使用MTLLoader加载MTL文件时,我收到以下错误:

Can't find variable: document

显然,MTLLoader正在调用TextureLoader,它在内部调用一些带有'文件'参考。那可能是什么解决方案?

以下是我正在使用的两个文件:

three.js所

const THREE = require("three");
global.THREE = THREE;
if (!window.addEventListener)
    window.addEventListener = () => { };
// require("three/examples/js/renderers/Projector");
require("three/examples/js/loaders/MTLLoader");
require("three/examples/js/loaders/OBJLoader");
export default THREE;

ThreeView.js

import React, { Component } from "react";
import { StyleSheet, View } from "react-native";
import { WebGLView } from "react-native-webgl";
import THREE from "./three";
import { image } from "src/res/image";

export default class ThreeView extends Component {
    requestId: *;
    componentWillUnmount() {
    cancelAnimationFrame(this.requestId);
}
onContextCreate = (gl: WebGLRenderingContext) => {
    const rngl = gl.getExtension("RN");

    const { drawingBufferWidth: width, drawingBufferHeight: height } = gl;
    const renderer = new THREE.WebGLRenderer({
        canvas: {
            width,
            height,
            style: {},
            addEventListener: () => { },
            removeEventListener: () => { },
            clientHeight: height
        },
        context: gl
    });
    renderer.setSize(width, height);
    renderer.setClearColor(0xffffff, 1);

    let camera, scene;
    let cube;

    function init() {
        camera = new THREE.PerspectiveCamera(75, width / height, 1, 1100);
        camera.position.y = 150;
        camera.position.z = 500;
        scene = new THREE.Scene();

        var mtlLoader = new THREE.MTLLoader();
        mtlLoader.load('female-croupier-2013-03-26.mtl', function (materials) {
            materials.preload();

            var objLoader = new THREE.OBJLoader();
            objLoader.setMaterials(materials);
            objLoader.load('female-croupier-2013-03-26.obj', function (object) {
                scene.add(object);
            }, onLoading, onErrorLoading);
        }, onLoading, onErrorLoading);
    }
    const onLoading = (xhr) => {
        console.log((xhr.loaded / xhr.total * 100) + '% loaded');
    };
    const onErrorLoading = (error) => {
        console.log('An error happened', error);
    };
    const animate = () => {
        this.requestId = requestAnimationFrame(animate);
        renderer.render(scene, camera);

        // cube.rotation.y += 0.05;

        gl.flush();
        rngl.endFrame();
    };

    init();
    animate();
};
render() {
    return (
        <View style={styles.container}>
            <WebGLView
                style={styles.webglView}
                onContextCreate={this.onContextCreate}
            />
        </View>
    );
}
}

const styles = StyleSheet.create({
container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center"
},
webglView: {
    width: 300,
    height: 300
}
});

4 个答案:

答案 0 :(得分:4)

正如其他人所说的那样,这个错误是由于三个人试图使用来自浏览器的功能而导致的,而本机没有这种功能。

我已经通过猴子修补纹理加载器以在react-native-webgl中使用加载器来加载纹理(这是你得到错误的阶段)。在你的init函数中添加它(最好在顶部附近)。

//make sure you have defined renderer and rngl

/*

const renderer = new THREE.WebGLRenderer(...)

const rngl = gl.getExtension("RN");

*/

const loadTexture = async function(url, onLoad, onProgress, onError) {
      let textureObject = new THREE.Texture();
      console.log("loading",url,'with fancy texture loader');
      let properties = renderer.properties.get(textureObject);


      var texture = await rngl.loadTexture({yflip: false, image: url});

      /*
      rngl.loadTexture({ image: url })
        .then(({ texture }) => {
        */
          console.log("Texture [" + url + "] Loaded!")
          texture.needsUpdate = true;
          properties.__webglTexture = texture;
          properties.__webglInit = true;
          console.log(texture);
              
          
          if (onLoad !== undefined) {
            //console.warn('loaded tex', texture);
            onLoad(textureObject);
          }
          
  
      //});

    
      return textureObject;
  
  }
  
  THREE.TextureLoader.prototype.load = loadTexture;   

这解决了加载纹理的问题,我可以看到它们在Charles中加载但是它们仍然没有在模型上渲染,所以我已经过了那个点。从技术上讲,这是一个正确的答案,但是一旦你实施它就会被卡住。我希望你能回复一下,告诉我你已经进一步了。

答案 1 :(得分:1)

我有类似的设置并遇到了同样的问题。我的选择是切换到JSONLoader,它不需要在react-native中呈现文档。所以,我只是将我的模型加载到Blender中,带有一个3-js插件,然后将其导出为json。只需查看向Blender添加3-js adon的过程

https://www.youtube.com/watch?v=mqjwgTAGQRY

一切顺利

答案 2 :(得分:1)

这可能会让你更接近:

GLTF格式支持嵌入纹理图像(作为base64)。如果您的资产管道允许,您可以转换为GLTF,然后加载到三个/ react-native。

我必须为“decodeUriComponent”和“atob”提供一些“窗口”polyfill,因为GLTFLoader使用FileLoader来解析base64:

我已经成功加载了嵌入式缓冲区,但您需要更多的polyfill来加载纹理。 TextureLoader使用ImageLoader,它使用document.createElementNS

答案 3 :(得分:1)

您正在使用使用TextureLoader的MTLLoader,而TextureLoader使用ImageLoader。 图像加载器使用document.createElementNS()函数。

我要做的就是直接调用THREEjs TextureLoader:

<view extends linear layout>
    <child-view extends relative layout> 
        <some content>
        <relative-layout>
            <progressbar> (align text view right, match parent)
            <textview> (align parent right, wrap content) <- there's i have to make some changes
        <relative-layout>
    <child-view>
    <...>
<view>

((使用纹理检查Texture documentation

然后我使用了来自React native的Image类(而不是THREEjs Image,它需要构造DOM)将其作为属性提供给Texture:

let texture = new THREE.Texture(
     url //URL = a base 64 JPEG string in this case     
     );

然后最终将纹理映射到目标材质上:

import { Image } from 'react-native';

var img = new Image(128, 128);
img.src = url;
texture.normal = img;

react native documentation中,它将说明如何使用react native图像元素,它支持base64编码的JPEG。

也许有一种方法可以让您选择需要TextureLoader的零件,并用此答案替换该零件。让我知道结果如何。

旁注,我尚未尝试在我的webGLView中显示此内容,但在日志中它看起来像普通的threejs对象,值得尝试