expo / expo-three

Utilities for using THREE.js on Expo
MIT License
738 stars 89 forks source link

Unable to load .gltf with image textures (neither with embedded .png nor with split files) #159

Open AlanKeiss opened 4 years ago

AlanKeiss commented 4 years ago

Hello, When resources are embedded in gltf, i am facing the issue https://github.com/expo/expo-three/issues/144 . Otherwise when .png and .bin are not in .gltf I am not able to load the bin file.

If someone is able to load this gltf with textures in react-native https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/WaterBottle/glTF I would love to know how.

Thank you

cuddeford commented 4 years ago

Did you find a solution to this?

ikebastuz commented 3 years ago

We are trying to load gltf with png images and bin-geometries inside.

We succeeded it partially making this:

ExpoTextureLoader.js

import { AsyncStorage } from 'react-native';
import { TextureLoader, THREE } from 'expo-three';
import AssetUtils from 'expo-asset-utils';
import { Platform } from '@unimodules/core';

export default class ExpoTextureLoader extends TextureLoader {
  load(asset, onLoad, onProgress, onError) {
    if (!asset) {
      throw new Error('ExpoTHREE.TextureLoader.load(): Cannot parse a null asset');
    }

    let texture = new THREE.Texture();

    const loader = new THREE.ImageLoader(this.manager);
    loader.setCrossOrigin(this.crossOrigin);
    loader.setPath(this.path);

    (async () => {
      const cached = JSON.parse(await AsyncStorage.getItem(asset));
      // const cached = false;

      const nativeAsset = cached
        ? await AssetUtils.resolveAsync(cached)
        : await AssetUtils.resolveAsync(asset);

      // TODO: add hash control to update image cache
      if (!cached) {
        console.log('caching asset', asset);
        await AsyncStorage.setItem(asset, JSON.stringify(nativeAsset));
      }

      function parseAsset(image) {
        texture.image = image;

        // texture.format = THREE.RGBAFormat;
        texture.needsUpdate = true;

        if (onLoad !== undefined) {
          onLoad(texture);
        }
      }

      if (Platform.OS === 'web') {
        loader.load(
          nativeAsset.localUri,
          (image) => {
            parseAsset(image);
          },
          onProgress,
          onError,
        );
      } else {
        texture.isDataTexture = true; // Forces passing to `gl.texImage2D(...)` verbatim
        texture.minFilter = THREE.LinearFilter; // Pass-through non-power-of-two

        parseAsset({
          data: nativeAsset,
          width: nativeAsset.width,
          height: nativeAsset.height,
        });
      }
    })();

    return texture;
  }
}

GLTFLoader.js

Replaced Loader inside

import TextureLoader from '../ExpoTextureLoader';

The problem is textures are somehow broken. They should be black-white, thats fine. But out-of-the-box they are striped/pixelated.

Tweaking texture format from ExpoTextureLoader we can achieve some result, but nothing satisfying (like this)

texture.format = THREE.RGBAFormat;

All RGBAs: Screenshot_2020-10-05-18-55-08-176_com marble

NB: Since GLTF looses bumpMap from blender we decided to keep it inside normalMap;

Untouched, seems like normalMap breaks something: photo_2020-10-06 18 16 30

normalMap disabled: photo_2020-10-06 18 16 29

bumpmap taken from normal map, normal map disabled: photo_2020-10-06 18 16 28

all maps except main texture are disabled: photo_2020-10-06 18 28 09

More or less ok, but what is the point of having only main texture map?

So we think that there is something whether with format, type, encoding or something else, we don't know yet. Maybe you have any ideas?