I started to study custom shaders. I wanted to re-use my custom shader instance on different materials in order to vary the uniforms on the different materials, as I think that will be the most efficient. I managed to make a script that does this but the way I keep a reference to the shader in a property of the global script class var seems not ideal. Is there a better way than that?
Updated project with suggested structure from Leonidas:
https://playcanvas.com/project/920189/overview/shaderquestions
https://playcanvas.com/editor/scene/1403602
Hi @Kulodo133,
It’s good that you are thinking in a more object oriented way.
Here is how I reworked your project. I created a global shader-prepare.js
script on root, that’s responsible for generating the shader:
var ShaderPrepare = pc.createScript('shaderPrepare');
ShaderPrepare.attributes.add('materialAsset', {
type: 'asset',
assetType: 'material'
});
// initialize code called once per entity
ShaderPrepare.prototype.initialize = function () {
const fshader = this.app.assets.find('shader-1.frag').resource;
const vshader = this.app.assets.find('shader-1.vert').resource;
const shaderDefinition = {
attributes: {
vertex_position: pc.SEMANTIC_POSITION,
vertex_normal: pc.SEMANTIC_NORMAL,
aUv0: pc.SEMANTIC_TEXCOORD0
},
vshader: vshader,
fshader: fshader
};
const shader = new pc.Shader(this.app.graphicsDevice, shaderDefinition);
this.material = new pc.Material();
this.material.shader = shader;
// --- events
this.app.on('ShaderPrepare:applyMaterial', function(meshInstance){
meshInstance.material = this.material;
}, this);
};
Then on each object I communicate in your shader-1.js
script using an event with that master script, to get that single material applied.
Instead of adding the parameter on the material, I apply it to each mesh instance:
var Shader1 = pc.createScript('shader1');
Shader1.attributes.add('blue', {
title: 'Blueness',
type: 'number',
default: 0.0,
description: 'Blueness'
});
Shader1.prototype.initialize = function() {
const meshInstance = this.entity.render.meshInstances[0];
this.entity.render.renderStyle = pc.RENDERSTYLE_WIREFRAME;
this.app.fire('ShaderPrepare:applyMaterial', meshInstance);
// set uniforms
meshInstance.setParameter('uBlue', this.blue);
this.on('attr:blue', function (value, prev) {
meshInstance.setParameter('uBlue', this.blue);
});
};
Here is the updated project:
https://playcanvas.com/editor/scene/1403683
2 Likes
Ah , I didn’t know that the setParameter could be set on the meshInstance, the examples I’d seen had set it on the material. That’s great so I don’t need to multiple materials. And good idea to keep the shader creation separate - that was exactly the kind of help I was after. Thanks that is a great help 
1 Like
Looks great, especially the water ripple! Thanks for sharing!
1 Like
can you send me the script for those neon shaders? it would help with a new visual for trigo run!
The code is in the linked project.
figured it out :), may i ask if you know how to make a 2d lava shader for my game trigo run?
I recommend finding a visual example of how you want that to look first. For example search for lava on shader toy might give you some ideas. Better to start a new thread for this.
1 Like