I am trying to convert the most basic ShaderToy shader (https://www.shadertoy.com/new) to use with PixiJS v4.5.5. What I am getting is a completely still background:
The background is supposed to move and blend between colors just like in the ShaderToy example. I am not getting any errors in the console.
My code:
let width = window.innerWidth;
let height = window.innerHeight;
let app = new PIXI.Application(width, height);
document.body.appendChild(app.view);
let shaderFrag = `
precision mediump float;
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform float iTime; // shader playback time (in seconds)
void main() {
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = gl_FragCoord.xy/iResolution.xy;
// Time varying pixel color
vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
// Output to screen
gl_FragColor = vec4(col,1.0);
}
`;
let container = new PIXI.Container();
container.filterArea = app.screen;
app.stage.addChild(container);
let filter = new PIXI.Filter(null, shaderFrag);
filter.uniforms.iResolution = [width, height, 1.0];
filter.uniforms.iTime = 1.0;
container.filters = [filter];
// Animate the filter
app.ticker.add(function(delta) {
filter.uniforms.iTime += 0.1;
});
What could be the issue here?
PS: the exact same shader code works perfectly with Three.js.
You are facing a bug in PixiJS.
See Comments in shader can comment out lines of code #5048
I debugged the code and investigated, that PixiJs (version 4.8.2) is parsing the fragment shader file, to find the uniforms.
See the original code, which I copied from the library:
function extractUniformsFromString(string)
{
const maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea|filterClamp)$');
const uniforms = {};
let nameSplit;
// clean the lines a little - remove extra spaces / tabs etc
// then split along ';'
const lines = string.replace(/\s+/g, ' ').split(/\s*;\s*/);
// loop through..
for (let i = 0; i < lines.length; i++)
{
const line = lines[i].trim();
if (line.indexOf('uniform') > -1)
{
const splitLine = line.split(' ');
const type = splitLine[1];
let name = splitLine[2];
let size = 1;
if (name.indexOf('[') > -1)
{
// array!
nameSplit = name.split(/\[|]/);
name = nameSplit[0];
size *= Number(nameSplit[1]);
}
if (!name.match(maskRegex))
{
uniforms[name] = {
value: defaultValue(type, size),
name,
type,
};
}
}
}
return uniforms;
}
If there is a line comment before the declaration of the uniform, as in your fragment shader before iTime
, then the uniform can not be found.
This causes that the automatic synchronisation mechanism of PixiJS breaks down and the value of the uniform is not set.
The workaround is simple, just remove the comments after the uniforms:
precision mediump float;
uniform vec3 iResolution;
uniform float iTime;
....
See the Example:
let width = window.innerWidth;
let height = window.innerHeight;
let app = new PIXI.Application(width, height);
document.body.appendChild(app.view);
let shaderFrag = `
precision mediump float;
uniform vec3 iResolution;
uniform float iTime;
void main() {
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = gl_FragCoord.xy/iResolution.xy;
// Time varying pixel color
vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
// Output to screen
gl_FragColor = vec4(col,1.0);
}
`;
let container = new PIXI.Container();
container.filterArea = app.screen;
app.stage.addChild(container);
let filter = new PIXI.Filter(null, shaderFrag);
filter.uniforms.iResolution = [width, height, 1.0];
filter.uniforms.iTime = [1.0];
container.filters = [filter];
app.ticker.add(function(delta) {
filter.uniforms.iTime[0] += 0.1;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script>