Error message when setting a sampler2d parameter

Hey all,

I’ve picked up my project for the first time in a long time and the API’s shifted a bit.

A shader that previously worked is now triggering an error:

Shader [Shader Id 133 shader-proc] requires texture sampler [noise] which has not been set, while rendering [Pass:RenderPassShadowDirectional-Light | SHADOW Light FACE 0 | FlameConeExtended]

I’m setting the parameter whilst programmatically generating the material, and as mentioned this approach worked previously.

I’ve seen discussion on this forum that some of the API updates may have caused errors that only show for the first render of the material, but I’d like to know what I can do to ensure I’ve using my custom shader materials properly.

Any and all input appreciated.

Hmm, I’m not aware of any changes here that changed the behaviour. We added this error message (when using the debug engine only) where before we had no message and possibly incorrect behaviour / using this material property from some previous material that set it up.

Try putting a breakpoint to where the message is printed, and inspect the material and similar.

From what I can tell the sampler2d is being set correctly, but that’s from logging the material out. I’ll try again with a breakpoint - hopefully there’ll be something more helpful :+1:

One thing I notice is that the texture has the _needsUpload property set to true - could this be the cause of the issue?

Currently I’m creating a new material and using material.setParameter() with the appropriate resource. Here’s the full material generation function in case it helps:

    getFireVertexMaterial(colour, vertShad, fragShad, name){
        if(this.fireMaterials[name + 'Vertex'+colour]){
            return this.fireMaterials[name + 'Vertex'+colour];
        }
        var dither = this.app.assets.find("dither8x8.fs").resource;
        var luma = this.app.assets.find("getluma.fs").resource;
        
        
        
        var ditherFunctions = `
        varying float distToOrigin;
        uniform vec4 uScreenSize;
        varying vec3 uVU;
        float scale = 2.0;
        ${luma}
        ${dither}
        `;

        this.noiseRef.resource.upload();
        
        var material = new pc.Material();
        material.setParameter('noise', this.noiseRef.resource);
        console.log('noise ref set', this.noiseRef, material);
        material.setParameter('uTime', 0);
        material.setParameter('yRot', 0.0);
        material.setParameter('matColour', colour === 'white' ? [1.0, 1.0, 1.0] : [0.0, 0.0, 0.0]);
        material.shader = this.createShader(vertShad, ditherFunctions + '\n' + fragShad);
        material.blendType = pc.BLEND_NORMAL;

        material.update();

        console.log('Flamethrower:', material, this.noiseRef);
        
        this.fireMaterials[name + 'Vertex'+colour] = material;
            
        return material;
    }

My previously exported works fine but for some reason since the engine update it no longer seems to be reading the asset correctly. This function is called to modify materials on first use and store them in a global namespace - so they should only get generated once.

Looking at the generated material it appears to have the parameters set correctly, but perhaps I’m looking at the wrong area. Is there a preferred way to set a sampler2d programmatically from the asset library? I’m afraid I’m a bit lost at the moment as to what could be causing this…

log out this.noiseRef.resource and not just this.noiseRef to make sure it’s loaded at that time.

Maybe try to set up a small repro of this? I don’t see anything obviously problematic in your code.

Here’s the output of noiseref.resource, in case you can spot anything:

_addressU: 1
_addressV: 1
_addressW: 0
_anisotropy: 1
_arrayLength: 0
_compareFunc: 1
_compareOnRead: false
_compressed: false
_cubemap: false
_depth: 1
_flipY: false
_format: 7
_gpuSize: 1280000
_height: 2000
_invalid: false
_isRenderTarget: false
_levels: Array [ ImageBitmap ]
_levelsUpdated: Array [ false ]
_lockedLevel: -1
_magFilter: 1
_minFilter: 5
_mipmaps: false
_mipmapsUploaded: false
_needsMipmapsUpload: false
_needsUpload: false
_premultiplyAlpha: false
_storage: false
_volume: false
_width: 160
device: Object { backBufferFormat: 6, backBufferAntialias: false, isWebGPU: false, … }
fixCubemapSeams: false
id: 33
impl: Object { _glTarget: 3553, _glFormat: 6408, _glInternalFormat: 32856, … }
name: "noisetexture.png"
profilerHint: 2
projection: "none"
renderVersionDirty: 0
type: "default"

Otherwise I guess my next stop is to, as you suggest, set up a mini-version of this problem and see if I still run into it.

Thanks for your help so far!

1 Like

Ok, so I have created about as reduced a test case as I possibly can and I still seem to be getting issues, you can find the example here:

https://playcanvas.com/project/1187515/overview/sampler2d-material-test

And the main body of code here:

    initialize() {
        this.gd = this.app.graphicsDevice;
        const model = this.app.root.findByName("Box");
        const material = new pc.Material();
        const vertShader = this.app.assets.find("samplertest.vs").resource;
        const fragShader = this.app.assets.find("samplertest.fs").resource;
        const noiseRef = this.app.assets.find("test.png");
        const shader =  this.createShader(vertShader,fragShader,'testmat-sampler');
        material.shader = shader;
        material.setParameter('noise', noiseRef.resource);
        model.render.material = material;
    },
    createShader: function(vertexShader, fragmentShader, name) {
        var gd = this.gd;
        var finalFragment = "precision " + gd.precision + " float;\n" + fragmentShader;
        var shaderDefinition = {
            name,
            attributes: {
                aPosition: pc.SEMANTIC_POSITION,
                aUv0: pc.SEMANTIC_TEXCOORD0,
                aNormal: pc.SEMANTIC_NORMAL
            },
            vshader: vertexShader,
            fshader: finalFragment
        };
        return new pc.Shader(gd, shaderDefinition);
    }
});

I’m still getting the same error. Really feeling a bit stuck on this one, and and all advice appreciated.

I think it is something to do with the engine trying to render a shadow map with your shader and cannot find noise texture sampler. Try disabling shadow casts for the box. @mvaligursky can probably give a more educated answer.

2 Likes

Thanks, that was indeed the cause!