Skip to content
This repository has been archived by the owner on Feb 10, 2023. It is now read-only.

GL_INVALID_FRAMEBUFFER_OPERATION when trying to add bloom effect #78

Open
0x4a61636f62 opened this issue Apr 4, 2022 · 26 comments
Open
Labels
help wanted Extra attention is needed

Comments

@0x4a61636f62
Copy link

0x4a61636f62 commented Apr 4, 2022

Getting hundreds of the following two warnings and a huge performance drop when trying to add bloom effect with ng-effect-composer. The bloom effect never takes effect.
I have tried with different objects but got the same warning.

  • [.WebGL-000066BA002AE900] GL_INVALID_FRAMEBUFFER_OPERATION: Framebuffer is incomplete: Attachment has zero size.
  • [.WebGL-000066BA002AE900] GL_INVALID_FRAMEBUFFER_OPERATION: Draw framebuffer is incomplete

I have a queen component holding a primitive object below which I am trying to display on a landing-page.html.

queen.component.ts

import {
  ChangeDetectionStrategy,
  Component,
  Input,
} from '@angular/core';

import { NgtVector3 } from '@angular-three/core';
import { NgtGLTFLoader } from '@angular-three/soba/loaders'
import { NgtSobaOrbitControls } from '@angular-three/soba/controls';
import { Mesh, MeshStandardMaterial, Object3D, PerspectiveCamera } from 'three';

@Component({
  selector: 'queen',
  templateUrl: './queen.component.html',
  styleUrls: ['./queen.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class QueenComponent {

  @Input() public position?: NgtVector3; // imported from @angular-three/core
  public hover = false;
  public active = false;
  public queen = this._ngtGLTFLoader.load('assets/threed/queen.glb');
  public queenMaterial: MeshStandardMaterial | undefined;
  #color = '#5323ff';

  constructor(private _ngtGLTFLoader: NgtGLTFLoader) { }

  queenLoaded(object: Object3D) {
    this.queenMaterial = <MeshStandardMaterial>(<Mesh>object.getObjectByName('Queen')).material;
    this.applyColorToMaterial(this.#color);
    console.log(object);
  }

  setInitial(controls: NgtSobaOrbitControls) {
    const orbitControl = controls.controls;
    const camera = orbitControl.object as PerspectiveCamera;
    camera.zoom = 2;
    camera.position.setX(0);
    camera.position.setY(50);
    camera.position.setZ(200);
  }

  applyColorToMaterial(color: string) {
    if (this.queenMaterial) {
      this.queenMaterial.color.setHex(parseInt(color.substring(1), 16));
    }
  }

  onAnimate(mesh: THREE.Object3D) {
    mesh.rotation.y = mesh.rotation.x += 0.01;
}
}

queen.component.html

<ngt-canvas>
  <ngt-spot-light [position]="[50, 50, 50]"></ngt-spot-light>
  <ngt-spot-light [position]="[-50, -50, -50]"></ngt-spot-light>

  <ngt-directional-light
      [position]="[0, 1, 2]"
      color="white"
  ></ngt-directional-light>

  <ngt-primitive
  (animateReady)="onAnimate($event.object)"
  (ready)="queenLoaded($event)"
  *ngIf="queen | async as queen"
  [object]="queen.scene">
</ngt-primitive>

<ngt-soba-orbit-controls
#controls="ngtSobaOrbitControls"
(ready)="setInitial(controls)"
[target]="[0, 0, 0]"
>

</ngt-soba-orbit-controls>

<ngt-effect-composer>
    <ngt-bloom></ngt-bloom>
</ngt-effect-composer>

</ngt-canvas>

landing-page.html

<queen></queen>

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 5, 2022

My understanding is that ngt-primitive is used to wrap an underly THREE object3d.

Have you tried loading into ngt-mesh or ngt-group instead of ngt-primitive?

This Example shows using ngt-mesh

@0x4a61636f62
Copy link
Author

Thank you IRobot1. Do you mean to wrap the primitive inside a ngt-group? If so, that does not work.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 5, 2022

No. I was suggesting something like this if queen was a single mesh

<ngt-mesh
  (animateReady)="onAnimate($event.object)"
  (ready)="queenLoaded($event)"
  *ngIf="queen | async as queen"
  [geometry]="queen.geometry"
  [material]="queen.material">
</ngt-mesh>

Can you share 'assets/threed/queen.glb'?

I've confirmed that using the following code in a different scene, does not result in the warnings you reported.

<ngt-effect-composer>
    <ngt-bloom></ngt-bloom>
</ngt-effect-composer>

@0x4a61636f62
Copy link
Author

Hi IRobot, thank you for your help.

I have uploaded queen.glb HERE.

@nartc
Copy link
Owner

nartc commented Apr 5, 2022

Hi all, I've been pretty busy at work and some personal life stuffs. AngularThree is still being maintained but it's a little slow for now. Thank you.

@0x4a61636f62
Copy link
Author

Hi Nartc, it happens to the best of us. Hope you get time to give NGT some love soon. Again, thanks for this great library.

@0x4a61636f62
Copy link
Author

0x4a61636f62 commented Apr 6, 2022

Hi @IRobot1, @nartc to test out the solution suggested by IRobot1 I need to figure out how to bind the geometry and material properties from the queen object with the ngt-mesh selector as suggested. But the ngt-mesh does not seem to have these properties, i.e., Can't bind to 'geometry' since it isn't a known property of 'ngt-mesh'.

Any help is much appreciated.

Also, wondering if this is the correct way to assign these properties in my queen.component.ts:

  public queen = this._ngtGLTFLoader.load('assets/threed/queen.glb');
  public queenMaterial: MeshPhongMaterial | undefined;
  public queenGeometry: BufferGeometry | undefined;
  #color = '#5323ff';

  constructor(private _ngtGLTFLoader: NgtGLTFLoader) { }

  queenLoaded(object: Object3D) {
    this.queenMaterial = <MeshPhongMaterial>(<Mesh>object.getObjectByName('Queen')).material;
    this.queenGeometry = <BufferGeometry>(<Mesh>object.getObjectByName('Queen')).geometry;
    console.log('Geometry: ', this.queenGeometry)
    console.log('Material: ', this.queenMaterial)
    console.log(object);
  }

@nartc
Copy link
Owner

nartc commented Apr 6, 2022

@99js if you try to console log the data of queen, you'll see that it has materials and geometries on it already

public queen = this._ngtGLTFLoader.load('assets/threed/queen.glb).pipe(
   tap(data => {
      console.log(data); // <-- check here
   })
)

@0x4a61636f62
Copy link
Author

@nartc Thank you. After a few tries, I was able to create the same example using NGT group and mesh. I created a new MeshStandardMaterial and used the geometry from my Blender object. Everything works fine, except the bloom effect is still throwing the same warnings and is not working from a performance perspective.

Would it be worth trying to create the bloom effect in Blender and try to include it as a new mesh in the NGT group somehow? I started learning everything about 3D just the other day and have never worked on this before so please excuse my ignorance.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 7, 2022

You were pretty close. The following code runs without the warnings and animated the model

image

<div style="height:100vh">
  <ngt-canvas>
    <ngt-spot-light [position]="[50, 50, 50]"></ngt-spot-light>
    <ngt-spot-light [position]="[-50, -50, -50]"></ngt-spot-light>

    <ngt-directional-light [position]="[0, 1, 2]"
                           color="white"></ngt-directional-light>

    <ngt-mesh *ngIf="mesh" (animateReady)="onAnimate($event.object)"
              [material]="mesh.material"
              [geometry]="mesh.geometry">
    </ngt-mesh>

    <ngt-soba-orbit-controls #controls="ngtSobaOrbitControls"
                             (ready)="setInitial(controls)"
                             [target]="[0, 0, 0]">

    </ngt-soba-orbit-controls>

    <ngt-effect-composer>
      <ngt-bloom></ngt-bloom>
    </ngt-effect-composer>

  </ngt-canvas>
</div>
import {
  Component,
  Input,
} from '@angular/core';

import { NgtVector3 } from '@angular-three/core';
import { NgtGLTFLoader } from '@angular-three/soba/loaders'
import { NgtSobaOrbitControls } from '@angular-three/soba/controls';
import { Mesh, MeshStandardMaterial, PerspectiveCamera } from 'three';

@Component({
  selector: 'queen',
  templateUrl: './queen.component.html',
})
export class QueenComponent {
  @Input() public position?: NgtVector3; // imported from @angular-three/core

  public hover = false;
  public active = false;
  public queenMaterial: MeshStandardMaterial | undefined;
  #color = '#5323ff';
  public mesh!: Mesh;

  constructor(private _ngtGLTFLoader: NgtGLTFLoader) {

    const s = this._ngtGLTFLoader.load('assets/queen.glb').subscribe(next => {
      const mesh = <Mesh>next.scene.children[0];
      this.mesh = mesh;
      (<MeshStandardMaterial>this.mesh.material).color.setHex(parseInt(this.#color.substring(1), 16))
    },
      () => { },
      () => { s.unsubscribe(); }
    );

  }

  setInitial(controls: NgtSobaOrbitControls) {
    const orbitControl = controls.controls;
    const camera = orbitControl.object as PerspectiveCamera;
    camera.zoom = 2;
    camera.position.setX(0);
    camera.position.setY(50);
    camera.position.setZ(200);
  }

  onAnimate(mesh: THREE.Object3D) {
    mesh.rotation.y = mesh.rotation.x += 0.01;
  }
}

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 7, 2022

If I remove ngt-bloom it looks like this
image

If I remove the ngt-effect-composer, it looks like this
image

@0x4a61636f62
Copy link
Author

Thanks a lot, @IRobot1It looks somewhat similar to what I did but clearly I'm still missing something. I'll go over your code to see what the issue might be.

This is what I did (queen has been replaced by knight and don't mind the terrible code formatting):


import { CommonModule } from '@angular/common';
import {
    NgtGLTFLoader,
} from '@angular-three/soba/loaders';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import * as THREE from 'three';
import { tap } from 'rxjs';
import { BufferGeometry, Mesh, MeshBasicMaterial, MeshStandardMaterial, PerspectiveCamera } from 'three';
import { NgtSobaOrbitControls } from '@angular-three/soba/controls';

@Component({
    selector: 'knight',
    templateUrl: './knight.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush,
})

export class KnightComponent {
  public knightMaterial = new THREE.MeshPhongMaterial();
  public knightGeometry: BufferGeometry | undefined;
  #color = '#5323ff';

  constructor(private gltfLoader: NgtGLTFLoader) {}

    knight$ = this.gltfLoader.load('assets/threed/knight.glb').pipe(
      tap(data => {
        // console.log(data.scene);
        const mesh = <Mesh>data.scene.children[0];
        // this.knightMaterial = mesh.material;
        console.log(this.knightMaterial);
        this.knightGeometry = mesh.geometry;
     })
    );

    onAnimate(object: THREE.Object3D) {
      object.rotation.z += 0.01;
    }

    applyColorToMaterial(color: string) {
      if (this.knightMaterial) {
        this.knightMaterial.color.setHex(parseInt(color.substring(1), 16));
      }
    }

    setInitial(controls: NgtSobaOrbitControls) {
      const orbitControl = controls.controls;
      const camera = orbitControl.object as PerspectiveCamera;
      // camera.zoom = 4;
      camera.position.setX(0);
      camera.position.setY(10);
      camera.position.setZ(0);
      camera.rotateZ(0);
    }

    onReady(group: THREE.Group) {
        this.applyColorToMaterial(this.#color);
        // group.rotation.y = 0;
        // group.rotation.x = Math.PI / 2;
    }
}

<ngt-canvas
>
<ngt-spot-light [position]="[10, 10, 10]"></ngt-spot-light>
<ngt-spot-light [position]="[-10, -10, -10]"></ngt-spot-light>
<ngt-ambient-light></ngt-ambient-light>
<ngt-stats></ngt-stats>
<ng-container *ngIf="knight$ | async as knight">
  <!-- <ngt-soba-center [position]="[5, 5, 10]"> -->
  <ngt-group
      (ready)="onReady($event)"
      [dispose]="null"
      (animateReady)="onAnimate($event.object)"
  >
  <ngt-mesh
    [castShadow]="true"
    [receiveShadow]="true"
    [material]="knightMaterial"
    [geometry]="knightGeometry"
    >
  </ngt-mesh>
  </ngt-group>
<!-- </ngt-soba-center> -->
</ng-container>
<ngt-soba-orbit-controls
#controls="ngtSobaOrbitControls"
(ready)="setInitial(controls)"
[target]="[0, 0, 0]"
>
</ngt-soba-orbit-controls>
<!-- <ngt-effect-composer>
    <ngt-bloom></ngt-bloom>
    <ngt-noise [options]="{ premultiply: true }"></ngt-noise>
</ngt-effect-composer> -->
</ngt-canvas>
<ngt-soba-loader></ngt-soba-loader>

@0x4a61636f62
Copy link
Author

@IRobot1 I ran your code, but I still get the same warnings. Being new to Angular I do not know all the features and configurations, but I wonder if there might be some configuration issues on my local.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 7, 2022

Could be. Can you share your github repo? Perhaps you can give me temporary access.

I occassionally forget to include a module in the app that results in warnings or failures only at runtime. I would start by checking that. ng3 is very modular and requires a lot of modules to be imported so its easy to miss one. Most are caught at compile time, but some fail at runtime with not very obvious errors.

@0x4a61636f62
Copy link
Author

0x4a61636f62 commented Apr 9, 2022

Thanks a lot for your help @IRobot1 !

I have created a private repository and made you a collaborator. The project includes all the packages from the original project. Let me know if you are facing problems accessing the repository.

image

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

Thanks. I have access and can repeat your warnings. I'll start investigation.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

It has something to do with putting ng3 in your website module. When I remove the website module and route and reference the queen directly from app.module, it works without warnings.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

If I replace lazy loading, export the landing page and reference the landing page directly, the warnings come back and nothing is displayed.

const routes: Routes = [
  {
    path: '', component: LandingPageComponent,
  //  loadChildren: () =>
  //    import('./modules/website/website.module').then((m) => m.WebsiteModule),
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

At the moment, my recommendation is to avoid using modules and put all your ng3 components in the main app module.

That's a pain, but seems to be the only solution at the moment.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

I'll publish a repeat case so that @nartc can investigate.

Without this getting fixed, it won't be possible for anyone to publish reusable libraries that includes ng3.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

A simpler repeat case is not showing the same problem. Now, I'm stumped why its failing in your project. I'll keep looking.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

@nartc I have a repeat case now on 2 different branches of a simple template project. Clone to review

postprocessing branch is just an app. When ng3/postprocessing is added, it works as expected.

route+module+postprocessing branch demonstrates the warnings as originally reported by @99js

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 9, 2022

I have another branch where lazy loading is removed. The test component is referenced directly from the main app route.

The warnings still appear, however, there are fewer of them. This makes be think its related to loading modules from a route.

So the underly problem appears to be when using routes+modules.

I confirmed using post processing from a module directly has no warnings

@0x4a61636f62
Copy link
Author

0x4a61636f62 commented Apr 9, 2022

Thank you very much @IRobot1. I'll be honest and say that I am new to programming and learnt the basics of Github just the other day.

What you did with creating a repository and different branches for different cases is something I can do to contribute to the Ng3 in the future. However, at the moment, as I am learning both Javascript, Angular and Ng3 at the same time, trying to fix these issues on my own is a bit over my head I'm afraid.

Maybe in the coming months or so I will have gotten enough understanding to do it myself and contribute to the repository in a more tangible way. In the meantime, I am very thankful for yours and @nartc help.

As you say, being able to create reusable Ng3 components is a must feature as having everything in the App root is untenable.

@IRobot1
Copy link
Contributor

IRobot1 commented Apr 10, 2022

@99js That's a steep learning curve. That's how I felt 5 years ago when I started Angular development. There's honestly a lot I still don't know. I still struggle to decipher the code @nartc is writing.

I have a branch showing that having re-usable components in a module does work, just not when accessed from a route.

@0x4a61636f62
Copy link
Author

@IRobot1 I started my journey with Javascript and Angular in January this year indeed it has been a really steep learning curve. But I am happy that I am starting to get the basics down but still have a mountain to climb.

@nartc
Copy link
Owner

nartc commented May 3, 2022

I've seen this as well but not sure how to fix it. If I put a long enough delay (500ms) on the EffectComposer's render, then the error's gone. So there must be some racing condition somewhere but I can't tell what it is because I don't know what generates the INVALID warnings :(

@nartc nartc added the help wanted Extra attention is needed label May 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants