Hot reloading shader code?

I’m using hot reload as described here and it works great: https://developer.playcanvas.com/en/user-manual/scripting/hot-reloading/

But is there a way to trigger a hot-reload on a script when any of the attached shader files change? Right now what I need to do is change the shader, then go to the JS script, make some trivial change and save in order to trigger a reload.

Hi @OmarShehata,

You can subscribe to the asset load event, each time that you edit/update any shader asset that event will fire. So you just reapply the shader to any materials using it.

Here is the Plasma Shader Chunk tutorial updated to use this “hot-reload for shader” method:

pc.script.attribute('materials', 'asset', [], {
    type: 'material'
});
pc.script.attribute('shader', 'asset', [], {
    type: 'shader',
    max: 1
});

var Plasma = pc.createScript('plasma');

Plasma.attributes.add('materials', {type: 'asset', array: true});
Plasma.attributes.add('shader', {type: 'asset'});

Plasma.prototype.initialize = function () {
    // get the shader asset
    var fs = this.shader.resource;

    // update all the materials with the chunk
    for (var i = 0; i < this.materials.length; i++) {
        var material = this.materials[i].resource;
        material.chunks.emissiveConstPS = fs;
        // Force the shader generator to generate UV processing code
        material.diffuseMap = new pc.Texture(this.app.graphicsDevice, {
            width: 1,
            height: 1,
            format: pc.PIXELFORMAT_R8_G8_B8
        });
        material.setParameter('iGlobalTime', 0);
        material.update();
    }

    this.time = 0;
    
    this.shader.on('load', function(){
        
        this.applyShader();
        
    }, this);
};

Plasma.prototype.update = function (dt) {
    // update the time uniform in the new shader chunk
    this.time += dt;
    for (var i = 0; i < this.materials.length; i++) {
        var material = this.materials[i].resource;
        material.setParameter('iGlobalTime', this.time);
    }
};

Plasma.prototype.applyShader = function () {
    
    var fs = this.shader.resource;
    
    for (var i = 0; i < this.materials.length; i++) {
        var material = this.materials[i].resource;
        material.chunks.emissiveConstPS = fs;
        material.update();
    }
};

3 Likes

Thank you so much @Leonidas! This is already saving me so much time :smile:

1 Like