Handling context restoration in 2021

So far I see there were some threads from 2017-2018 where this seemed to work out of the box in some jsfiddle, but today I am getting a ton of errors in three.js (r109, so 2019 actually, lol) when it tries to retrieve non-existing entry from buffers WeakMap after context is restored. I tried this:

    renderer.domElement.addEventListener( 'webglcontextrestored', function( event ) {
        const updateMaterial = function( material ) {
            material.needsUpdate = true;
            for( var key in material ) if( material[key] && material[key].isTexture ) {
                material[key].needsUpdate = true;
            }
        };
        scene.traverse( function( object ) {
            if( object.geometry ) {
                for(var key in object.geometry.attributes) {
                    object.geometry.attributes[key].needsUpdate = true;
                }
                if( object.geometry.index ) {
                    object.geometry.index.needsUpdate = true;
                }
            }
            if( object.material ) {
                if( object.material.length ) {
                    object.material.forEach( updateMaterial );
                } else {
                    updateMaterial( object.material );
                }
            }
        });
        scene.backgound.needsUpdate = true;
    });

but it did not do anything useful. Does anyone have a working snippet for this?

In console was only one error. I added try/catch at scene.backgound.needsUpdate = true;

        const updateMaterial = function( material ) {
            material.needsUpdate = true;
            for( var key in material ) if( material[key] && material[key].isTexture ) {
                material[key].needsUpdate = true;
            }
        };
        scene.traverse( function( object ) {
            if( object.geometry ) {
                for(var key in object.geometry.attributes) {
                    object.geometry.attributes[key].needsUpdate = true;
                }
                if( object.geometry.index ) {
                    object.geometry.index.needsUpdate = true;
                }
            }
            if( object.material ) {
                if( object.material.length ) {
                    object.material.forEach( updateMaterial );
                } else {
                    updateMaterial( object.material );
                }
            }
        });
        try{
        scene.backgound.needsUpdate = true;
        }
        catch(e){}

I guess you dont have a texture in there, but the point is, this whole thing does not do anything, and I think it should not too.

Have textures. Version is 132dev. I checking just puting into console:

const updateMaterial = function( material ) {
.........
try{
scene.backgound.needsUpdate = true;
}
catch(e){}

no, no, try this:

ext = renderer.context.getExtension('WEBGL_lose_context')
ext.loseContext()

and then few seconds later

ext.restoreContext()

Error was:
image
Changed to
var ext = renderer.getContext().getExtension('WEBGL_lose_context');

Its working. Full code:

renderer.domElement.addEventListener( 'webglcontextrestored', function( event ) {
        const updateMaterial = function( material ) {
            material.needsUpdate = true;
            for( var key in material ) if( material[key] && material[key].isTexture ) {
                material[key].needsUpdate = true;
            }
        };
        scene.traverse( function( object ) {
            if( object.geometry ) {
                for(var key in object.geometry.attributes) {
                    object.geometry.attributes[key].needsUpdate = true;
                }
                if( object.geometry.index ) {
                    object.geometry.index.needsUpdate = true;
                }
            }
            if( object.material ) {
                if( object.material.length ) {
                    object.material.forEach( updateMaterial );
                } else {
                    updateMaterial( object.material );
                }
            }
        });
    try{
        scene.backgound.needsUpdate = true;
        }
        catch(e){}
    });

var ext=renderer.getContext().getExtension('WEBGL_lose_context');
ext.loseContext();
setTimeout("ext.restoreContext();",5000);

if that is working for you, you should be able to comment out everything in
addEventListener and it will still work, no?

I put into console changed code and ok.

var ext=renderer.getContext().getExtension('WEBGL_lose_context');
ext.loseContext();
setTimeout("ext.restoreContext();",5000);
renderer.domElement.addEventListener( 'webglcontextrestored', function( event ) {
        const updateMaterial = function( material ) {
            material.needsUpdate = true;
            for( var key in material ) if( material[key] && material[key].isTexture ) {
                material[key].needsUpdate = true;
            }
        };
        scene.traverse( function( object ) {
            if( object.geometry ) {
                for(var key in object.geometry.attributes) {
                    object.geometry.attributes[key].needsUpdate = true;
                }
                if( object.geometry.index ) {
                    object.geometry.index.needsUpdate = true;
                }
            }
            if( object.material ) {
                if( object.material.length ) {
                    object.material.forEach( updateMaterial );
                } else {
                    updateMaterial( object.material );
                }
            }
        });
    try{
        scene.backgound.needsUpdate = true;
        }
        catch(e){}
    });

so… discussing a similar issue on github Ive found that my browser is now working differently from how it did 4 years ago, so Im going to assume it is broken and confirm on another machine

1 Like

turns out this issue is unrelated, and happens under different os/browser any way… as soon as it tries to render a shadow map of some mesh, it cant find the buffer for its geometry.index

for now I will give up on debugging this and just stick with

    renderer.domElement.addEventListener( 'webglcontextlost', function() {
        location.reload();
    });