nartc / angular-three

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

Cannot update flipY after load texture with NgtTextureLoader #76

Closed manhnd98 closed 2 years ago

manhnd98 commented 2 years ago

So I created a cube and texture with Blender and used ngt-primitive to render it.

portalModel$ = this._textureLoader.load('assets/baked-cube.jpg').pipe(
        switchMap((texture) => {
            const bakedTexture = texture;
            bakedTexture.flipY = false; // --> not working
            return this._gltfLoader.load('assets/cube.glb').pipe(
                map((gltf) => {
                    const bakedMesh = gltf.scene.children[0];
                    if (bakedMesh) {
                        (bakedMesh as any).material =
                            new THREE.MeshBasicMaterial({
                                map: bakedTexture,
                            });
                    }
                    return gltf;
                })
            );
        })
    );

angular-three

After reading the code, I think we have to update flipY = false before call the initTexture function.

// texture-loader.ts
tap((textures: THREE.Texture | THREE.Texture[]) => {
                const renderer = this.canvasStore.get((s) => s.renderer);
                if (renderer) {
                    (Array.isArray(textures) ? textures : [textures])
                        .map((texture) => {
                            texture.flipY = false; // update flipY = false here
                            return texture;
                        })
                        .forEach(renderer.initTexture.bind(renderer));
                }
            }),

Do we have any solutions for this issue?

IRobot1 commented 2 years ago

I have a simple component that loads a texture into a plane.

import { NgtLoader, NgtVector3 } from "@angular-three/core";
import { Input } from "@angular/core";
import { Component } from "@angular/core";
import { DoubleSide, FrontSide,  MeshBasicMaterialParameters, Texture, TextureLoader } from "three";

@Component({
  selector: 'simple-texture',
  template: `
<ngt-mesh [name]="name" [position]="position" [scale]="scale">
  <ngt-plane-geometry></ngt-plane-geometry>
  <ngt-mesh-basic-material [parameters]="parameters"></ngt-mesh-basic-material>
  <ngt-arrow-helper></ngt-arrow-helper>
</ngt-mesh>`
})
export class SimpleTextureComponent {
  @Input() name = 'simple-texture'
  @Input() position = [0, 0, 0] as NgtVector3;
  @Input() scale = [1, 1, 1] as NgtVector3;
  @Input() color = 'white';
  @Input() doublesided = false;

  @Input() set url(newvalue: string) {
    const s = this.loader.use(TextureLoader, newvalue).subscribe(next => {
      next.flipY = false;
      this.texture = next;
    },
      () => { },
      () => { s.unsubscribe(); }
    );
  }

  texture!: Texture;

  get parameters(): MeshBasicMaterialParameters {
    const p: MeshBasicMaterialParameters = {
      color: this.color,
      side: this.doublesided ? DoubleSide : FrontSide
    }
    // to avoid THREE warning if map is undefined
    if (this.texture) {
      p.map = this.texture;
    }
    return p;
  }

  constructor(private loader: NgtLoader) { }
}

This results in an image that is up-side down. When flipY is true (default), the image looks correct.

image

Here's the code to render the picture frame

  <ngt-canvas [camera]="{ position: [0, 0, 2], fov: 45 }"
              [scene]="{ background: 'lightblue' | color }">
    <ngt-ambient-light></ngt-ambient-light>

    <!--picture frame-->
    <simple-texture [position]="[0, 0.5, -1]" [scale]="[1.28*2.1, 2.1,2]" [doublesided]="true" [color]="'black'" ></simple-texture>
    <simple-texture [position]="[0, 0.5, -0.99]" [scale]="[1.28*2,2,2]" [url]="'assets/Canestra_di_frutta.jpg'" ></simple-texture>

    <ngt-soba-orbit-controls></ngt-soba-orbit-controls>
  </ngt-canvas>
manhnd98 commented 2 years ago

I have used the same workaround, but I think the TextureLoaderService should support this issue, right?

IRobot1 commented 2 years ago

flipY is true by default and results in an image that looks good. I think that's the right default.