Assigning a custom material to UI Element

I’m sure this is just a stupid thing I’m missing, but have spend such a long time trying to figure out what i’m doing wrong.

I’m trying to create a custom material using a custom shader and attaching it to a UI element. I have boiled the code down to the bare minimum in this project

But the UI element just stops rendering, any takers on why this is happening ?

var Test = pc.createScript('test');

Test.prototype.initialize = function(){
    let material = new pc.Material();
    material.setShader(this.createShader());
    material.update();
    
    this.entity.element.material = material;
};

Test.prototype.createShader = function(){
    var shaderDefinition = {
        attributes: {
            aPosition: pc.SEMANTIC_POSITION
        },
        vshader: [
            "attribute vec3 aPosition;",
            "",
            "void main(void)",
            "{",
            "    gl_Position = vec4(aPosition, 1.0);",
            "}"
        ].join("\n"),
        fshader: [
            "precision " + this.app.graphicsDevice.precision + " float;",
            "",
            "void main(void)",
            "{",
            "    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);",
            "}"
        ].join("\n")
    };

    var shader = new pc.Shader(this.app.graphicsDevice, shaderDefinition);
    return shader;
};

Please see this thread for the bug: UI Elements are not being rendered after cloning material - #4 by yaustar

We have someone looking into this and so far the workaround is to do something like what thread had said or what has been mentioned in the ticket: https://github.com/playcanvas/engine/issues/3534#issuecomment-933679816

1 Like

Thank you so much! Not sure why my Google skills did not find those solutions. Sorry for the inconvenience.

Hmm even updating the code to what is recommended in those links will result in a transparent/non rendering object.

var Test = pc.createScript('test');

Test.prototype.initialize = function(){
    let material = new pc.Material();
    material.setShader(this.createShader());
    this.entity.element.opacity = 0.9;
    this.entity.element.opacity = 1;
    this.entity.element.color = new pc.Color(0, 0, 0);
    this.entity.element.color = new pc.Color(1, 1, 1);
    material.update(); 
    
    this.entity.element.material = material;
};

Test.prototype.createShader = function(){
    var shaderDefinition = {
        attributes: {
            aPosition: pc.SEMANTIC_POSITION
        },
        vshader: [
            "attribute vec3 aPosition;",
            "",
            "void main(void)",
            "{",
            "    gl_Position = vec4(aPosition, 1.0);",
            "}"
        ].join("\n"),
        fshader: [
            "precision " + this.app.graphicsDevice.precision + " float;",
            "",
            "void main(void)",
            "{",
            "    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);",
            "}"
        ].join("\n")
    };

    var shader = new pc.Shader(this.app.graphicsDevice, shaderDefinition);
    return shader;
};

@jpaulo Will you be able to help here please?

I’d suggest to capture a frame using original material using Spector JS, and then compare the shader it uses to your shader.

This issue does not seem to be related to UI Elements are not being rendered after cloning material because it’s a brand new material and shader, rather than a clone of the element’s default material. Best to start with @mvaligursky 's suggestion.

So when using Spector JS I can see that the element where I created a new material is not even a drawcall, this leads me to believe that the vertex shader is wrong and the object is rendered out of view frustum.

Witch makes sense as I’m using a standard mapping that is supposed to work on the 3D objects, and not necessarily the UI objects. Will keep digging.

1 Like

Might be worth testing without the shader to double check that the other code and material is working/rendering?

I have a “befor and after” side by side to ensure things are still rendering.

Cloning the shader code from the old material into the new one still results in the new one not rendering. And still not even getting a draw call trying to render it

If it’s not even a render call that means something on CPU side decided it’s not something that needs to be rendered - so it’s likely not related to the shader.

Then I’m out of ideas :frowning:

@Mads_Nielsen did you change the project since last time you posted this? I’ve just opened the linked scene (https://playcanvas.com/editor/scene/1244945) and could not reproduce the issue. Also by inspecting with SpectreJS I did see both left and right image elements as 2 separate draw calls.

Could also be that a recent deployment fixed the issue.

I am using Chrome 94.0.4606.71 on MacOS 11.6.

Yes sorry i changed the project for this Disabling Image Element removes Material Data - #6 by Mads_Nielsen, I thought i cloned it but apparently not, that is my bad.

I know this is a few months old, but in case this is still an open issue or someone else finds this: We’ve recently added a new UI Example in our Examples Browser that showcases how to setup a custom shader on a UI Element: PlayCanvas Examples

4 Likes

Nice, this is quite cool!