Cannot read property 'cull' of null

Hi all,

Sorry for reviving this old thread, but I’m seeing a similar issue currently in my project but in a different function of the engine.

Was wondering if anyone here might be able to point me in the right direction for how to solve this. It’s happening on the latest stable release (1.39) and was happening on the previous release as well (1.38.4). Those are the only two engine versions we’ve been working with.

This is the error that is thrown:

playcanvas-stable.js:22098 Uncaught TypeError: Cannot read property 'cull' of null
    at ForwardRenderer.setCullMode (playcanvas-stable.js:22098)
    at ForwardRenderer.renderForward (playcanvas-stable.js:22273)
    at ForwardRenderer.renderComposition (playcanvas-stable.js:23205)
    at Application.render (playcanvas-stable.js:66055)
    at playcanvas-stable.js:66763

Our project is set up of multiple scenes, and this error happens when switching between scenes roughly 8 times, and can get it to happen consistently.

1 Like

this is the line causing the issue:

        device.setCullMode(material.cull);

and that means a material on some mesh instance is null … perhaps something related to the scene switching and release of resources?

2 Likes

This is good info I appreciate it, I will continue to dig and and see if I can find the culprit.

We have some scripts that work with the layers a little bit, do you think there’s a possibility that something is being held onto between scene switches there?

1 Like

it’s possible some mesh instances are deleted but not removed from layers or something like that, and so when the engine tries to render them, it fails.

1 Like

Alright I have an update on this and wondering if anyone here might be able to shed a bit more light. We have a script that runs in 3 out of 5 of our scenes. In that script we copy over the meshes from the world layer into our own custom layer like so:

this.layerRefraction.addMeshInstances(this.layerWorld.opaqueMeshInstances);

When this works fine, the resulting array of meshes is 7 in length.

When it fails, there are 10 items in:
this.layerRefraction.opaqueMeshInstances

The 3 MeshInstances that are different all have their node property set as an Entity with the name: "Untitled" and their materials are of course null which is causing the error.

Whereas the rest of the MeshInstances all have their node properties set as GraphNode with names that should appear in the scene.

Hopefully these details make sense, and maybe shed some more light on what might be happening.

1 Like

Are you removing the meshinstances from layerRefraction when the scene is ‘unloaded’?

Are the 3 meshinstances pc.Entities or pc.GraphNodes?

Is there anyway you could create a public reproducible of this issue?

1 Like

also, you are adding mesh instances to those layers … are you removing them as well?

1 Like

Yep so in the destroy of our script we’re doing the following:

this.on('destroy', function() {
    self.doDestroy();
});
Refraction.prototype.doDestroy = function() {
    console.log( "REFRACT Destroy" );
    
    this.app.graphicsDevice.off("resizecanvas");
    // this.app.graphicsDevice.scope.resolve('texture_screen').setValue( undefined );

    if ( this.layerRefraction ) {
        this.layerRefraction.clearMeshInstances();
        this.layerRefraction.clearCameras();
        this.layerRefraction.clearLights();
        // this.layerRefraction = null;
    }

    if ( this.renderTarget ) {
        this.renderTarget.destroy();
        this.renderTarget = undefined;
    }    

    if ( this.layerWorld ) {
        
        if ( this.layerWorld.renderTarget ) this.layerWorld.renderTarget.destroy();
        
        this.layerWorld.renderTarget = undefined;
    }
    
    if ( this.layerSkybox ) {
        
        if ( this.layerSkybox.renderTarget ) this.layerSkybox.renderTarget.destroy();
        
        this.layerSkybox.renderTarget = undefined;
    }
    
    console.log( "Destroyed MESHES", this.layerRefraction.opaqueMeshInstances );
};

And to answer your question, yes I can confirm the 3 MeshInstances are pc.Entities

Screen Shot 2021-02-11 at 2.34.04 PM

If it helps, we are more or less using the refraction script from this public project:
https://playcanvas.com/editor/scene/686823

With our slightly modified destroy code.

And then we are doing this for our scene switching:

var oldHierarchy = this.app.root.findByName(oldScene);
oldHierarchy.destroy();

self.app.scenes.loadSceneHierarchy(scene.url, function (err, parent) {
            if (!err) {

                self.app.scenes.loadSceneSettings(scene.url, function (err) {
                    if (!err) {

                        self.app.fire('sceneChangeSuccess');
                        callback();

                    } else {
                        console.error( err );
                    }
                });
                // callback();
            } else {
                console.error( err );
            }
});

Which has been slightly adapted from the PlayCanvas example here:

https://playcanvas.com/editor/scene/475211

Odd that they are untitled? Do you create entities at run time? Might be worth use specific entity name when creating so it’s easier to narrow down when/what they are.

Updated my answer above with a bit more info. But yes I thought it was strange these were entities with no names.

I just double checked and we aren’t adding any Entities programmatically either, so not sure why/how these suddenly appear. The weirdest part is that it doesn’t happen every time, it still only happens intermittently.

If they were graph nodes, I could explain it. Untitled is the default name for creating an Entity if a name isn’t supplied.

Do you think somehow in the scene switching code that it’s possible some phantom entities are lingering and being reattached to the hierarchy?

You could walk through the parent hierarchy to see what it is attached to if anything?

Without a reproducible it’s really difficult to tell. Is there any reparenting done in the app? Is it possible that an Entity isn’t part of hierarchy because it is created or unparented to something?

The print graph function may help from my dev tools: https://github.com/yaustar/yaustar.github.io/tree/master/playcanvas-devtools

Ok thanks, I’ll take a look and see if I can print out the hierarchy.

I don’t believe we’re reparenting anything, but I’ll check that as well.

Ok so the print graph might be onto something here, unless I’m interpreting things wrongly. I’ve attached a piece of the printed graph and the same setup as reflected in the scene editor, it looks like there are “untitled” entities coming out of primitives in the scene that have been disabled?

Screen Shot 2021-02-11 at 3.09.56 PM Screen Shot 2021-02-11 at 3.10.03 PM

Those that are Untitled are node graph objects with the mesh. Not pc.Entities :sweat_smile:

It’s the strangest thing. Anyway I’ve managed to hack together a fix.

When copying the MeshInstances from the world layer into our custom layer, I’m checking to see if the mesh instance has a material or not, and also if the name is “Untitled” as we don’t purposefully add any “Untitled” enitities to our scene.

I noticed last night that I could loop through and the Entities that are named “Untitled” actually have a material set at the time of copying them into our custom layer. It’s only at some point after that these entities materials are set to null. I’m not sure why or how that is happening, but regardless, this hack will do the job for our purposes.

Refraction.prototype.addMeshes = function() {
    
    var oMeshes = [];
    
    for ( var i=0; i < this.layerWorld.opaqueMeshInstances.length; i++ ) {
        
        if ( this.layerWorld.opaqueMeshInstances[i].material !== null &&
             this.layerWorld.opaqueMeshInstances[i].node.name !== "Untitled" ) {
            
            console.log( "ADD", this.layerWorld.opaqueMeshInstances[i], this.layerWorld.opaqueMeshInstances[i].material );
            
            oMeshes.push( this.layerWorld.opaqueMeshInstances[i] );
        }
    }
    
    this.layerRefraction.addMeshInstances( oMeshes );
    
    var tMeshes = [];
    
    for ( var j=0; j < this.layerWorld.transparentMeshInstances.length; j++ ) {
        
        if ( this.layerWorld.transparentMeshInstances[j].material !== null &&
             this.layerWorld.transparentMeshInstances[j].node.name !== "Untitled" ) {
            tMeshes.push( this.layerWorld.transparentMeshInstances[j] );
        }
    }
    
    this.layerRefraction.addMeshInstances( tMeshes );
};
1 Like

Question for you though? Why do those primitives add their materials to the scene as MeshInstances with the name “Untitled” and not the name given to the material in the editor?

MeshInstances do not have names … the name you check is meshInstance.node.name … which is either Entity, or GraphNode (so a part of the hierarchy) - so there are some of these with name Untitled. These could have been added from code maybe? And not from the scene in the editor. Maybe if you use batching, those were created as batches and similar as well.