Website not working in Chrome

I have made a website with Three.js and Blender. Everything works great in Safari, but it breaks when I open it up in Google Chrome. Do you have any idea why this is? Please let me know if code is needed.

Safari:

Google Chrome:

These are the errors being showed in the console. I suppose ‘256’ is how many textueres ord meshes I have in my .glb file.

1 Like

Judging by the error, somewhere in your shader code, you are trying to write into the texture that you’re reading at the same time, which you can not do.

1 Like

Is it perhaps in this code? Or am I looking the wrong place? It is where I add the .glb file

setModel() {
    this.actualRoom.children.forEach((child) => {
      child.castShadow = true;

      if (child instanceof THREE.Group) {
        child.children.forEach((groupChild) => {
          groupChild.castShadow = true
          groupChild.material.toneMapped = false
        })
      }

      //Set tonemapp to neon lights
      if (child.name === "About_Text" || child.name === "Alexander_Text") {
        child.material.toneMapped = false
      }

      //Set up Brick Wall
      if (child.name === "Painted_Wall001") {
        child.material.map.rotation = 90 * Math.PI / 180
        child.material.map.repeat.set(1.7, 1.7)
      }    
    });

    this.scene.add(this.actualRoom)
    this.actualRoom.scale.set(100, 100, 100)
    this.actualRoom.position.z = 0
  }

Or is it perhaps my renderer that is not set up correctly? I use both an UnrealBloomRenderer and a CSS3DRenderer, so I hope that is not the reason that it fails.

setRenderer() {
    THREE.ColorManagement.enabled = false

    //WebGLRenderer
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.physicallyCorrectLight = true
    this.renderer.outputColorSpace = THREE.SRGBColorSpace
    this.renderer.toneMapping = THREE.ReinhardToneMapping
    this.renderer.toneMappingExposure = 1
    this.renderer.shadowMap.enabled = true
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
    this.renderer.setClearColor( 0xf111ff, 0 )
    this.renderer.setSize(this.sizes.width, this.sizes.height)
    this.renderer.setPixelRatio(this.sizes.pixelRatio)
    document.querySelector('.experince-canvas').appendChild( this.renderer.domElement )
    
    //CSS3DRenderer
    this.css3DRenderer = new CSS3DRenderer();
    this.css3DRenderer.setSize( this.sizes.width, this.sizes.height );
    this.css3DRenderer.domElement.style.position = 'absolute';
    this.css3DRenderer.domElement.style.top = '0px';
    
    document.querySelector('.html-canvas').appendChild( this.css3DRenderer.domElement );


    //Unreal Bloom
    this.target = new THREE.WebGLRenderTarget(this.sizes.width, this.sizes.height, {
      type: THREE.HalfFloatType,
      format: THREE.RGBAFormat,
      colorSpace: THREE.SRGBColorSpace,
    })
    this.target.samples = 8

    this.renderScene = new RenderPass(this.scene, this.camera.perspectiveCamera)
    this.bloomPass = new UnrealBloomPass( new THREE.Vector2(this.sizes.width, this.sizes.height), 1, 1.5, 1 )
    this.bloomPass.renderToScreen = true
    this.composer = new EffectComposer(this.renderer, this.target)

    this.composer.setSize(this.sizes.width, this.sizes.height)
    this.composer.addPass( this.renderScene )
    this.composer.addPass( this.bloomPass)
  }

  resize() {
    this.renderer.setSize(this.sizes.width, this.sizes.height)
    this.css3DRenderer.setSize(this.sizes.width, this.sizes.height)
    this.renderer.setPixelRatio(this.sizes.pixelRatio)
    this.composer.setSize(this.sizes.width, this.sizes.height)
  }

  update() {
      this.composer.render()
      this.css3DRenderer.render(this.scene, this.camera.perspectiveCamera)
  }

Update: I have figured out that the error comes from the UnrealBloomPass. I have tried fixing it for a couple of hours now, but I can’t seem to figure it out. Anybody got any ideas?

It’s hard to tell without seeing your code in action. Normally you would create a simplified live example of your code showing the error and put it somewhere like codepen or jsfiddle for everyone to check out.

In general, a pass would take an image as an input (existing image/texture/target) and create another image as an output (you need to provide an empty target/texture for that). This error might happen either in JavaScript, if you provide the input target as the output, or in the shader code, if it’s custom, it might try to write to the input.

The problem is chrome memory bug, have u tried the Opera GX threejs runs efficiently on it. For heavy assets such backed textures and high poly Opera GX is the browser to go.

That is not true. The error is very explicit in telling you exactly what is wrong. A postprocessing effect is reading & writing to the same framebuffer in a single render-iteration. That should never happen.

If it’s the unreal bloom pass, try chaning the order of effects or swapping the input/output buffer (needsSwap set to true from the top of my head, but correct me if I’m wrong).

2 Likes

I have managed to make the Google Chrome look like the Safari one, by swapping the order I add the “this.bloomPass” and “this.renderScene” to the “this.composer”. However, I still get the same error in the console.

This is my updated renderer code:

export default class Renderer {
  constructor() {
    this.experience = new Experience()
    this.sizes = this.experience.sizes
    this.scene = this.experience.scene
    this.canvas = this.experience.canvas
    this.camera = this.experience.camera

    this.setRenderer()
  }

  setRenderer() {
    THREE.ColorManagement.enabled = false

    //WebGLRenderer
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.physicallyCorrectLight = true
    this.renderer.outputColorSpace = THREE.SRGBColorSpace
    this.renderer.toneMapping = THREE.ReinhardToneMapping
    this.renderer.toneMappingExposure = 1
    this.renderer.shadowMap.enabled = true
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
    this.renderer.setClearColor( 0xf111ff, 0 )
    this.renderer.setSize(this.sizes.width, this.sizes.height)
    this.renderer.setPixelRatio(this.sizes.pixelRatio)
    document.querySelector('.experince-canvas').appendChild( this.renderer.domElement )
    
    //CSS3DRenderer
    this.css3DRenderer = new CSS3DRenderer();
    this.css3DRenderer.setSize( this.sizes.width, this.sizes.height );
    this.css3DRenderer.domElement.style.position = 'absolute';
    this.css3DRenderer.domElement.style.top = '0px';
    document.querySelector('.html-canvas').appendChild( this.css3DRenderer.domElement );

    //Unreal Bloom
    this.target = new THREE.WebGLRenderTarget(this.sizes.width, this.sizes.height, {
      type: THREE.HalfFloatType,
      format: THREE.RGBAFormat,
      colorSpace: THREE.SRGBColorSpace,
    })
    this.target.samples = 8

    this.renderScene = new RenderPass(this.scene, this.camera.perspectiveCamera)
    this.bloomPass = new UnrealBloomPass( new THREE.Vector2(this.sizes.width, this.sizes.height), 0.3, 1, 1 )
    this.bloomPass.renderToScreen = true
    this.bloomPass.needsSwap = true //Is this correct?
    this.composer = new EffectComposer(this.renderer, this.target)

    this.composer.needsSwap = true //Is this correct?
    this.composer.addPass( this.bloomPass ) // I swaped this
    this.composer.addPass( this.renderScene ) // With this, to make the google chrome look correct, but still with errors
    this.composer.setSize(this.sizes.width, this.sizes.height)
  }

  resize() {
    this.renderer.setSize(this.sizes.width, this.sizes.height)
    this.css3DRenderer.setSize(this.sizes.width, this.sizes.height)
    this.renderer.setPixelRatio(this.sizes.pixelRatio)
    this.composer.setSize(this.sizes.width, this.sizes.height)
  }

  update() {
    this.css3DRenderer.render(this.scene, this.camera.perspectiveCamera)
    this.composer.render()
  }
}

I am not sure I understand what you mean here. How am I supposed to do this? I have tried to add “needsSwap” to the code, but it does not help.

Update: I noticed that this actually tuns off the UnrealBloomPass, so this did not seem to work either… I am quite lost now.

Just to be sure, are you referring to Safari and Chrome running on an iOS device (e.g. iPhone or iPad) or on a Windows device? My problems usually work the other way - my program works fine on Windows Chrome, but not on iOS Safari. For example, the most recent iOS upgrade broke some things that had been running fine.

RenderPass should come before anything else. So what you had before was just fine.

Are you maybe using the texture of your custom WebGLRenderTarget as a material map somewhere?

Also, does the original Unreal Bloom example work correctly for you?

I am using a MacBook Pro. It works on Safari, but it does not work on Google Chrome.

Could the code “this.actualRoom.scale.set” have anything to do with my problem? Because when I remove it, it works. But that is not optimal, since I need it to be scaled 100 times.

//this.actual room is my .glb file from Blender whihc is being displayed in Three.js
setModel() {
    this.actualRoom.children.forEach((child) => {
      child.castShadow = true;

      if (child instanceof THREE.Group) {
        child.children.forEach((groupChild) => {
          groupChild.castShadow = true
          groupChild.material.toneMapped = false
        })
      }
    });

    this.scene.add(this.actualRoom)
    // this.actualRoom.scale.set(100, 100, 100) //When I remove this the error does not show. Why?
    this.actualRoom.position.z = 0
  }

Update: Never mind, it did not show the error because the view wasn’t in the camera’s perspective. Since it was so small, the camera did not detect it. So I will try something else.

I’m not quite sure what you mean by this. Do you mean if I can open the link and watch the Three.js scene?

Ok. I’m sorry for sending such a long message, but I can’t seem to figure out how to set up a CodePen, because my .glb file can not be used in CodePen.

The following is all of my JavaScript/Three.js code. I personaly think the problem lies within the Renderer or Room Class.

My code is split up into classes, to make it more manageable. I really hope someone can help, because I am going nuts.

Could there be a problem within my .glb file? Is it because I have set up my blender file incorrectly perhaps, or handled the texture files wrong?

export default class Experience {
  static instance
  constructor(canvas) {
    if (Experience.instance) {
      return Experience.instance
    }
    Experience.instance = this;
    this.canvas = canvas;
    this.scene = new THREE.Scene() //I set up my scene here
    this.time = new Time() //I set up time here for animations
    this.sizes = new Sizes() //I set up sizes here
    this.camera = new Camera() //I set up the camera here
    this.renderer = new Renderer() //I set up my renderer here

    this.recources = new Resources() //I get the blender file from here
    this.world = new World() //I set the view here, where I load the blender file 

    this.sizes.on("resize", ()=> {
      this.resize();
    })

    this.time.on("update", ()=> {
      this.update();
    })

  }

  resize() {
    this.camera.resize()
    this.renderer.resize()
    this.world.room.resize()
  }

  update() {
    this.camera.update()
    this.renderer.update()

    if (this.world.room !== undefined) {
      this.world.room.update()
    }
  }
}


//I don't think this is the problem
export default class Sizes extends EventEmitter {
  constructor() {
    super()
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.aspect = this.width/this.height
    this.pixelRatio = Math.min(window.devicePixelRatio, 2)

    window.addEventListener("resize",()=> {
      this.width = window.innerWidth;
      this.height = window.innerHeight;
      this.aspect = this.width/this.height
      this.pixelRatio = Math.min(window.devicePixelRatio, 2)
      this.emit("resize");
    })
  }
}

//This is not the problem either
export default class Time extends EventEmitter {
  constructor() {
    super()
    this.start = Date.now()
    this.current = this.start
    this.elapsed = 0 //Time since start
    this.delta = 16 //Time between each frame

    this.update()
  }

  update() {
    const currentTime = Date.now()
    this.delta = currentTime - this.current
    this.current = currentTime
    this.elapsed = this.current - this.start

    this.emit("update");
    window.requestAnimationFrame(() => this.update())
  }
}

//This is not the problem either I think
export default class Camera {
  constructor() {
    this.experience = new Experience()
    this.sizes = this.experience.sizes
    this.scene = this.experience.scene
    this.canvas = this.experience.canvas

    this.createPerspectiveCamera();
  }
  
  createPerspectiveCamera() {
    this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.sizes.aspect, 0.1, 10000)
    this.scene.add(this.perspectiveCamera)

    this.perspectiveCamera.rotation.set(0 * Math.PI / 180, -50 * Math.PI / 180, 0 * Math.PI / 180)
    this.perspectiveCamera.position.set(-950, 500, 600)
  }

  resize() {
    //Updating Perpective Camera on Resize
    this.perspectiveCamera.aspect = this.sizes.aspect
    this.perspectiveCamera.updateProjectionMatrix()
  }
}


//I have a feeling the problem is withing here or the next couple of classes
export default class Renderer {
  constructor() {
    this.experience = new Experience()
    this.sizes = this.experience.sizes
    this.scene = this.experience.scene
    this.canvas = this.experience.canvas
    this.camera = this.experience.camera

    this.setRenderer()
  }

  setRenderer() {
    THREE.ColorManagement.enabled = false

    //WebGLRenderer
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.physicallyCorrectLight = true
    this.renderer.outputColorSpace = THREE.SRGBColorSpace
    this.renderer.toneMapping = THREE.ReinhardToneMapping
    this.renderer.toneMappingExposure = 1
    this.renderer.shadowMap.enabled = true
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
    this.renderer.setClearColor( 0xf111ff, 0 )
    this.renderer.setSize(this.sizes.width, this.sizes.height)
    this.renderer.setPixelRatio(this.sizes.pixelRatio)
    document.querySelector('.experince-canvas').appendChild( this.renderer.domElement )
    
    //CSS3DRenderer
    this.css3DRenderer = new CSS3DRenderer();
    this.css3DRenderer.setSize( this.sizes.width, this.sizes.height );
    this.css3DRenderer.domElement.style.position = 'absolute';
    this.css3DRenderer.domElement.style.top = '0px';
    document.querySelector('.html-canvas').appendChild( this.css3DRenderer.domElement );

    //Unreal Bloom
    this.target = new THREE.WebGLRenderTarget(this.sizes.width, this.sizes.height, {
      type: THREE.HalfFloatType,
      format: THREE.RGBAFormat,
      colorSpace: THREE.SRGBColorSpace,
    })
    this.target.samples = 8

    this.renderScene = new RenderPass(this.scene, this.camera.perspectiveCamera)
    this.bloomPass = new UnrealBloomPass( new THREE.Vector2(this.sizes.width, this.sizes.height), 1, 1.5, 1 )
    this.bloomPass.renderToScreen = true
    this.composer = new EffectComposer(this.renderer, this.target)
    
    this.composer.setSize(this.sizes.width, this.sizes.height)
    this.composer.addPass( this.renderScene )
    // this.composer.addPass( this.bloomPass )
  }

  resize() {
    this.renderer.setSize(this.sizes.width, this.sizes.height)
    this.css3DRenderer.setSize(this.sizes.width, this.sizes.height)
    this.renderer.setPixelRatio(this.sizes.pixelRatio)
    this.composer.setSize(this.sizes.width, this.sizes.height)
  }

  update() {
    this.composer.render()
    this.css3DRenderer.render(this.scene, this.camera.perspectiveCamera)
  }
}

//I load in the .glb (Blender) file here
export default class Resources extends EventEmitter {
  constructor(assets) {
      super()
      this.experience = new Experience()

      this.assets = ["/models/Arcade Room 38.glb"]
      
      this.items = {}
      this.queue = this.assets.length
      this.loaded = 0

     this.setLoaders();
     this.startLoading();
  }

  setLoaders() {
    this.loaders = {} //This makes it easier to load more files. Even though I only load one file now
    this.loaders.gltfLoader = new GLTFLoader()
    this.loaders.dracoLoader = new DRACOLoader()
    this.loaders.dracoLoader.setDecoderPath("/draco/")
    this.loaders.gltfLoader.setDRACOLoader(this.loaders.dracoLoader)
  }

  startLoading() {
    for(const asset of this.assets) {
      this.loaders.gltfLoader.load(asset.path, (file) => {
        this.singleAssetLoaded(asset, file)
      },
      (xhr) => {
          console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
      }
      );
    }
  }

  singleAssetLoaded(asset, file) {
    this.items[asset.name] = file;
    this.loaded++

    if (this.loaded === this.queue) {
      this.emit("ready") 
    }
  }
}

//The World file that contains the Enviorenment and Room class
export default class World {
  constructor() {
    this.experience = new Experience()
    this.recources = this.experience.recources

    this.recources.on("ready", () => {
      this.environment = new Environment()
      this.room = new Room()
    })
  }
}

//Environment with controling of the lights
export default class Environment {
  constructor() {
    this.experience = new Experience()
    this.scene = this.experience.scene
    this.resoruces = this.experience.recources

    this.setLight()
    this.setLFloorLampLight()
  }

  setLight() {
    //Fan Lights
    for(let i = 0; i < 4; i++) {
      this.pointLight = new THREE.PointLight(0xffea90, 2, 1300)
      this.pointLight.castShadow = true
      this.pointLight.position.set(300 - (i < 2 ? 1120 : 0), 790, (i % 2 === 1 ? -210 : 700))
      this.scene.add(this.pointLight)
    }
  }

  setLFloorLampLight() {
    for(let i = 0; i < 2; i++) {
      this.lampLight = new THREE.PointLight(0xffea90, 1.3, 1000)
      this.pointLight.castShadow = true
      this.lampLight.position.set(i === 0 ? 1100 : 890, 400, i === 0 ? 490 : -710)
      this.scene.add(this.lampLight)
    }
  }
}

//Room Class, I also think the problem is in this Class
export default class Room {
  constructor() {
    this.experience = new Experience()
    this.scene = this.experience.scene
    this.resoruces = this.experience.recources
    this.room = this.resoruces.items.room
    this.actualRoom = this.room.scene

    this.setModel()

    //Raycast
    this.INTERSECTED = null;
    this.raycaster = new THREE.Raycaster();
  }
  
  setModel() {
    this.scene.add(this.actualRoom)
    this.actualRoom.scale.set(100, 100, 100)
    this.actualRoom.position.z = 0
  }
}

Try CodeSandbox instead :smile:

I don’t see anything wrong with your code perse. However, since the problem does go away if the model is out of view, that does give a hunch that there is some material used in your model that is using a framebuffer. Is there a mirror or something like that maybe?

Anyhow, without a live example, this is really hard to debug.


I’m not quite sure what you mean by this. Do you mean if I can open the link and watch the Three.js scene?

Yes. Does that example give similar errors in the console? If not, then its safe to assume UnrealBloom isn’t the problem on your device.

Here you go: (I hope I have set it up correctly, it is my first time using CodeSandbox)

I can’t see the error here however. So that annoys me quite a bit.

It does not. Not in Safari or Chrome

Is there a way to check for that? Because I’m not quite sure what framebuffer means.

Without a reproducible sample, all we can do is speculate :frowning:

Alright, I have seemed to fix one of the problems.
I found out that in my Blender model, I had set the “emmesiveIntensity” to another number than 1 for some of the meshes. So by setting that to 1, it removed the “Feedback loop formed between Framebuffer and active Texture” error from the console.

However, now when I add UnrealBloomPass to the project, my website looks like the image below again. Why does UnrealBloomPass cause this only in Google Chrome? When nothing gets displayed in the console. I hope you can help.