Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React-three-fiber compatibility #2

Closed
LeoPapais opened this issue Jul 11, 2022 · 5 comments
Closed

React-three-fiber compatibility #2

LeoPapais opened this issue Jul 11, 2022 · 5 comments

Comments

@LeoPapais
Copy link

Hi there,

Thanks for making this package available, I'm sure that it helps many people out there. I'm currently using R3F to use ThreeJS in a React webpage, so in order to use your package with the useLoader hook, one needs to have the UsdzLoader function names just like the other loaders (for instance, the ObjLoader).

I tried to make a fork to test the changes and create a PR, but I'm facing some issues building it correctly, as the build command throws the following errors:

three-usdz-loader git:(main) ✗ npm run build

> three-usdz-loader@1.0.7 build
> tsc

src/ThreeJsRenderDelegate.d.ts:4:43 - error TS2503: Cannot find namespace 'THREE'.

4   constructor(inputFile: string, usdRoot: THREE.Group);
                                            ~~~~~

src/USDZInstance.ts:12:16 - error TS2503: Cannot find namespace 'THREE'.

12   targetGroup: THREE.Group;
                  ~~~~~

src/USDZInstance.ts:12:16 - error TS4031: Public property 'targetGroup' of exported class has or is using private name 'THREE'.

12   targetGroup: THREE.Group;
                  ~~~~~

src/USDZInstance.ts:23:18 - error TS2503: Cannot find namespace 'THREE'.

23     targetGroup: THREE.Group,
                    ~~~~~

src/USDZInstance.ts:23:18 - error TS4063: Parameter 'targetGroup' of constructor from exported class has or is using private name 'THREE'.

23     targetGroup: THREE.Group,
                    ~~~~~

src/USDZInstance.ts:38:15 - error TS2503: Cannot find namespace 'THREE'.

38   getGroup(): THREE.Group {
                 ~~~~~

src/USDZInstance.ts:38:15 - error TS4055: Return type of public method from exported class has or is using private name 'THREE'.

38   getGroup(): THREE.Group {
                 ~~~~~

src/USDZLoader.ts:72:43 - error TS2503: Cannot find namespace 'THREE'.

72   async loadFile(file: File, targetGroup: THREE.Group): Promise<USDZInstance> {
                                             ~~~~~

src/USDZLoader.ts:72:43 - error TS4073: Parameter 'targetGroup' of public method from exported class has or is using private name 'THREE'.

72   async loadFile(file: File, targetGroup: THREE.Group): Promise<USDZInstance> {
                                             ~~~~~

src/USDZLoader.ts:115:18 - error TS2503: Cannot find namespace 'THREE'.

115     targetGroup: THREE.Group,
                     ~~~~~


Found 10 errors.

Do you have any insights on how to solve this issue? Or even patching an R3F-compatible version?

Thanks in advance!

@ponahoum
Copy link
Owner

@LeoPapais strange that you cannot build. I pulled your fork and ran npm build without error. The resulting package being in /lib. My node version is 16.15.0, not sure it changes anything, but we never know...

In any case, I'm not very familiar with R3F but I'll take a look at it this week end!

@DennisSmolek
Copy link

Stupid question, did you npm install the three types?

if you’re using a r3f typescript setup make sure the usage lines up as sometimes the semantics are different depending on weird stuff like if you use an external type vs from three core, which on, If you use import * as THREE etc..

@skarone
Copy link

skarone commented Jul 14, 2022

Hi All, I'm also interested in this feature.
From what I saw the problem is that the USDZLoader needs a load method
Here is a snippet of what I think it could work.. but I never did any web dev or javascript..

USDZLoader.prototype.load = function (url, onLoad, onProgress, onError) {
        var scope = this;
        var loader = new THREE.FileLoader();
        loader.load(url, function (data) {
            try {
                onLoad(this.loadUsdFileFromArrayBuffer(this.usdModule, url, data));
            } catch ( e ) {
                if ( onError ) {
                    onError( e );
                } else {
                    console.error( e );
                }
                scope.manager.itemError( url );
            }
        }, onProgress, onError );
    };

At least this is what I see that three\examples\js\loaders\OBJLoader.js is doing.
Maybe is possible to take advantage of the THREE.FileLoader, as I'm showing on the snippet.
Another thing that I'm getting is this error: THREE.TextureLoader() is not a constructor..
Another thing is that this is returning a USDInstance object, and it should create and return the THREE.Group

@LeoPapais
Copy link
Author

@DennisSmolek thanks, I forgot to install the @types/three before coming here!

After installing the missing types, I kept working on a React component to wrap this loader. Something like that:


function createResource(promise) {
  let status = 'pending'
  let result = promise.then(
    resolved => {
      status = 'success'
      result = resolved
    },
    rejected => {
      status = 'error'
      result = rejected
    },
  )
  return {
    read() {
      if (status === 'pending') throw result
      if (status === 'error') throw result
      if (status === 'success') return result
      throw new Error('This should be impossible')
    },
  }
}

function UsdzLoader() {
  const [state, setState] = useState(null)
  const loader = new USDZLoader();

  const group = useRef()

  useEffect(() => {
    fetch('/Room_2022_07_06_18_18.usdz')
      .then(async res => {
        const data = await res.blob()
        const file = new File([data], 'room.usdz')
        setState(createResource(loader.loadFile(file, group.current)))
      })
  }, [group])
  if (state) state.read()
  return <group ref={group}></group>
}

I know it's incomplete, but it crashes with the following message:

Uncaught TypeError: THREE.TextureLoader is not a constructor
    at new TextureRegistry (ThreeJsRenderDelegate.js:9:1)
    at new RenderDelegateInterface (ThreeJsRenderDelegate.js:378:1)
    at USDZLoader.loadUsdFileFromArrayBuffer (USDZLoader.js:188:1)
    at USDZLoader.<anonymous> (USDZLoader.js:160:1)

I'm not sure what's going on here 🤔

@DennisSmolek
Copy link

So the custom progress is clever!

From what I can tell the flow makes logical sense and it actually IS a constructor and the usage in RenderDelegate looks correct.

have you tried the example vanilla code and then just passing it as a primitive yet?

Instead of trying to move all the logic into your hook all at once, get it to work more generically then port the functions over.

My guess is something is either firing way early (because… React) and it’s before Three is loaded thus TextureLoader doesn’t exist, thus it isn’t a constructor,

or..

Something else in the stack has failed and/or corrupted the Three global object, and what you’re seeing is just the error that finally gets thrown.

I would add a bunch of annoying console logs at each stage, it seems you’re getting all the way to loadFile Which (as I said ^) is either awesome, or something broke and is firing too fast..
The logging will let you in on the loop a bit better..

do you have a sandbox?

are you on the Pmndrs discord?

@ponahoum ponahoum closed this as completed Jul 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants