nartc / angular-three

🧊 THREE.js integration for Angular 🧊
https://angular-three.netlify.app/
MIT License
306 stars 26 forks source link

[Bug?/Feature] Missing loader objects #133

Closed short-circuit closed 2 years ago

short-circuit commented 2 years ago

Currently only the GTLF Loader is available. Can't find any information about any of the other loaders from three-stdlib neither in documentation nor in code. These loaders are all featured on the Three.js site: https://threejs.org/examples/?q=loader

How would one go implementing these? Right now NgtLoader is not loading correctly if the file format is different from GTLF.

The Documentation is not clear and is missing a working example with correct paths for imports.

IRobot1 commented 2 years ago

Here's an example of a texture loader

  constructor(
    private loader: NgtLoader,
  ) {
    this.loader.use(TextureLoader, 'assets/uv_grid_opengl.jpg').subscribe(next => {
      this.texture = next;
    });
  }

or FBXLoader

  constructor(private loader: NgtLoader) { }
  @Input() set url(newvalue: string) {
    const s = this.loader.use(FBXLoader, newvalue).subscribe(next => {
      const mesh = <Mesh>next.children[0];
      this.mesh = mesh;
    },
      () => { },
      () => { s.unsubscribe(); }
    );
  }

or loading from two files

  constructor(private loader: NgtLoader) { }
  @Input() set url(newvalue: string) {
    const geometry = this.loader.use(OBJLoader, newvalue);
    const material = this.loader.use(MTLLoader, newvalue.replace('.obj', '.mtl'));

    const s = forkJoin([geometry, material]).subscribe(next => {
      next[1].preload()
      const materials: Array<Material> = [];
      for (let key in next[1].materials) {
        materials.push(next[1].materials[key]);
      }
      this.mesh = <Mesh>next[0].children[0];
      this.mesh.material = materials[0];
      this.loaded.emit(this.mesh);
    },
      () => { },
      () => { s.unsubscribe(); }
    );
  }

Hope this helps
short-circuit commented 2 years ago

Ok, I got it working by doing the following:

import { NgtLoader, NgtVector3 } from '@angular-three/core';
import { Component, Input } from '@angular/core';
import { Mesh, MeshBasicMaterialParameters } from 'three';
import { AMFLoader, ThreeMFLoader, STLLoader } from 'three-stdlib';
import * as THREE from 'three';

@Component({
...
@Input() set url(newvalue: string) {
    const re = /(?:\.([^.]+))?$/;
    const ext = re.exec(newvalue);
    if (ext?.length) {
      switch (ext[1]) {
        case '3mf':
          let tmf = this.loader.use(ThreeMFLoader, newvalue).subscribe(next => {
            let mesh = next.children[0];
            while (!mesh.hasOwnProperty("geometry")) {
              mesh = mesh.children[0];
            }
            this.stdmesh = <Mesh>mesh;
          }, () => { }, () => { tmf.unsubscribe() });
          break;

        case 'amf':
          let amf = this.loader.use(AMFLoader, newvalue).subscribe(next => {
            let mesh = next.children[0];
            while (!mesh.hasOwnProperty("geometry")) {
              mesh = mesh.children[0];
            }
            this.stdmesh = <Mesh>mesh;
          }, () => { }, () => { amf.unsubscribe() });
          break;

        case 'stl':
          let stl = this.loader.use(STLLoader, newvalue).subscribe(geometry => {
            let mesh = geometry;
            this.stdmesh = new THREE.Mesh(mesh);
          }, () => { }, () => { stl.unsubscribe() });
          break;

        default:
          break;
      }
    }
  }
...
}

Would be nice to have the file types directly integrated/wrapped into angular-three itself, so that all the other ThreeJS dependent imports can be removed. Or maybe I am missing the information on where to find them 😅.

EDIT: fixed unsubscribe parenthesis.

IRobot1 commented 2 years ago

Glad you got it working. Wrapping in a library wouldn't simplify your code in any way. The file types are coming from three-stdlib.

You can replace THREE. references to use 'three' import. I noticed unsubscribe is missing () at end.

short-circuit commented 2 years ago

Hey @IRobot1, Thank you for the correction and you are probably right. Does this mean, though, that I can and should mix and match properties, functions, types, etc. from angular-three to/from ThreeJS?

For example, there is no clear way to attach/detach transformation controls in angular-three. Should I go the ThreeJS way in this situation?

IRobot1 commented 2 years ago

Its fine to mix and match. When using three directly, you're responsible for object cleanup. I find there usually is a way to do the equivalent in NGT, its not always obvious without a working example. If you have example code doing something in threejs, I'm always up for the challenge to find a way to do it in NGT. We can move that into repo Discussion area.

If you're happy with answer above, please close issue.