Why my Scene objects turn black?

I followed this tutorial (03. Physically Based Rendering (PBR) Materials in BabylonJS - YouTube) but I am using Reactjs and TypeScript and I noticed when I add some textures the objects in my scene turn black and become unstable and I don’t know why.
Attached is the result when adding the textures in CreateAsphalt() method and even if I count only the first texture the result isn’t good.
This is the current output:

This is the expected output from the youtube tutorial:

This is my code:

export class PBR {
    scene: Scene;
    engine:Engine;

    constructor(private canvas: HTMLCanvasElement) {
        this.engine = new Engine(this.canvas, true);
        this.scene = this.CreateScene();
        this.CreateEnvironment();
        this.engine.runRenderLoop(()=>{
            this.scene.render();
        });
    }
    CreateScene(): Scene {
        const scene = new Scene(this.engine);
        const camera = new FreeCamera("camera", new Vector3(0,1,-5), this.scene);
        camera.attachControl();
        camera.speed = 0.25;

        const hemiLight = new HemisphericLight("hemiLight",new Vector3(0,1,0),this.scene);
        hemiLight.intensity = 0.0;

        const envTex = CubeTexture.CreateFromPrefilteredData("./environment/sky.env", scene);
        scene.environmentTexture = envTex;
        scene.createDefaultSkybox(envTex, true);

        return scene;
    }
    CreateEnvironment(): void {
        const ground = MeshBuilder.CreateGround("ground", { width:10, height:10 }, this.scene);
        const ball = MeshBuilder.CreateSphere("ball", {diameter:1}, this.scene);
        ball.position = new Vector3(0,1,0);
        ground.material = this.CreateAsphalt();
    }
    CreateAsphalt(): PBRMaterial {
        const pbr = new PBRMaterial("pbr", this.scene);
        // The problem happens when adding these textures
        pbr.albedoTexture = new Texture("./textures/asphalt/asphalt_diff.jpg", this.scene);
        pbr.bumpTexture = new Texture("./textures/asphalt/asphalt_nor.jpg", this.scene);
        pbr.roughness = 1; 



        return pbr;
    }
}

Looks like your textures are not loading. do you see any errors in the console ? or the network tab of your browser ?

Possibly because you’re using this.scene to create camera and lights before that property is assigned?

Try using just scene (without this) as you’ve done when creating envTex.

No there are no errors in the console.
When I run the server for the first time it gives good results as expected but when I refresh the problem appears.

Still not working

Looks more like an issue in your react integration as it happens only on refresh. You could have a look at how @brianzinn implemented GitHub - brianzinn/react-babylonjs: React for Babylon 3D engine to inspire yourself ?

Hard to say without the accompanying react code. It may be a StrictMode thing in React 18.

I suggest adding the scene inspector and a few logs to track lifecycles or if you can share a codesandbox. For example, I hope your new PBR(canvasRef.current) is not being called on each react render in the component that creates it. You can limit that with a useEffect and an empty dependency array.

edit: another thing is you are using a relative ref (./environment/... instead of /environment/...) on the environment texture, so if you are navigating with react-router that can stop working, but you would see that in the network tab. That was suggested by @sebavan in original reply, but I didn’t see a confirmation from you that was not the case :smile: .

edit: also-- how do you dispose() - are you sure it’s one scene on the canvas?

Your hemiLight intensity is set to 0

1 Like

Here is my App.tsx code.

import { PBR } from "./BabylonExamples/PBR";

function App() {
  useEffect(() => {
    // Update the document title using the browser API
    const canvas = document.querySelector('canvas')!;

    //create instance of the class as follows
    new PBR(canvas);
  },[]); 
  return (
    <div className="App">
      <h3>
        Babylon Examples
      </h3>
      <canvas className="babylon-canvas"></canvas>
    </div>
  );
}

export default App;

I removed the strictMode and the case now is that the first run the scene becomes somehow noisy but when I refresh I get the desired output.

On first run:

When I refresh:

edit: Noticed that sometimes when the problem happens this appears in the console:
image

Can you change that to this:

useEffect(() => {
    // Update the document title using the browser API
    const canvas = document.querySelector('canvas')!;

    //create instance of the class as follows
    const pbr = new PBR(canvas);
    return () => {
      pbr.engine.dispose();
    }
  },[]);

You should keep StrictMode - it’s designed to help you detect issues with your code.

2 Likes

This seems to be the answer. Thank you!

Glad that solves it for you. You might get some ideas from here (this is where the engine is disposed on component umount that you were missing) - you can remove event listeners in here (ie: if you resize your window your scene can get blurry), etc:
babylonjs-hook/babylonjs-hook.tsx at master · brianzinn/babylonjs-hook (github.com)

It’s a good idea to create your own canvas and use a ref, since the query selector you are using is on the entire document. If you have only one canvas is OK though.

Cheers.