CZauX Posted December 8, 2016 Share Posted December 8, 2016 function QuantizeFilter() { var vertexShader = null; //Doesn't actually quantize, just testing. var fragmentShader = [ 'precision mediump float;', '', 'varying vec2 vTextureCoord;', '', 'uniform vec4 dimensions;', //This is the variable. 'uniform vec3 palette[3];', 'uniform sampler2D uSampler;', '', 'void main(void)', '{', ' gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);', '}' ].join('\n'); var uniforms = { dimensions: { type: '4fv', value: new Float32Array([0, 0, 0, 0]) }, palette: { type: '3fv', value: [ [255.0, 255.0, 255.0], [200.0, 200.0, 200.0], [0.0, 0.0, 0.0] ] } }; PIXI.AbstractFilter.call(this, vertexShader, fragmentShader, uniforms ); } QuantizeFilter.prototype = Object.create(PIXI.AbstractFilter.prototype); QuantizeFilter.prototype.constructor = QuantizeFilter; Object.defineProperties(QuantizeFilter.prototype, { palette: { get: function() { return this.uniforms.palette.value; }, set: function(value) { this.uniforms.palette.value = value; } } }); Custom (test) filter for Pixi.js V4 I'd like to make the 'uniform vec3 palette[3];' array size, size to the 'palette' uniform input. So I could set palette to 256 or so arrays of colors and the uniform will size appropriately: 'uniform vec3 palette[256];' Hypothetically, I've thought of just making the string in javascript, and prepending it to the fragment shader text, but I don't know of a way to do that. Any help is appreciated, ty. Quote Link to comment Share on other sites More sharing options...
Exca Posted December 8, 2016 Share Posted December 8, 2016 You could do it for example by changing a value in the string to: "uniform vec3 palette[%%PALETTE_SIZE%%]" and then just using your fragment shader like this: fragmentShader = fragmentShader.replace("%%PALETTE_SIZE%%", sizeOfPalette); The identifier can be anything you like as long as it doesn't repeat in the string in any other context. Keep in mind that you need to know the size of the palette when the shader is generated. If you need to change it during runtime then this solution would require recompiling the shader. Quote Link to comment Share on other sites More sharing options...
CZauX Posted December 8, 2016 Author Share Posted December 8, 2016 5 hours ago, Exca said: You could do it for example by changing a value in the string to: "uniform vec3 palette[%%PALETTE_SIZE%%]" and then just using your fragment shader like this: fragmentShader = fragmentShader.replace("%%PALETTE_SIZE%%", sizeOfPalette); The identifier can be anything you like as long as it doesn't repeat in the string in any other context. Keep in mind that you need to know the size of the palette when the shader is generated. If you need to change it during runtime then this solution would require recompiling the shader. Doing that replacement only work on compilation with the default value, as you pointed out. How would I recompile the shader after I've modified the uniform value? var filter = new QuantizeFilter(); filter.palette = colors; bunny.filters = [filter]; Thats how I'm using it, colors is just a longer array. Quote Link to comment Share on other sites More sharing options...
Exca Posted December 9, 2016 Share Posted December 9, 2016 If you create new QuantizeFilter when colors changes that should work I think. Unless pixi has some kind of system that caches shaders. If your colors changes rapidly then this is a bad idea as it would cause plenty of performance issues. Other way how you could do it is to have an array of maximum size of colors and another uniform telling how many values the shader should read. Then in shader you could do something like: const int MAX_SIZE = 200; uniform vec3 palette[MAX_SIZE]; uniform int amount; for(int i = 0; i < MAX_SIZE; i++) { if(i >= amount) break; //Do something. } Quote Link to comment Share on other sites More sharing options...
bubamara Posted December 9, 2016 Share Posted December 9, 2016 just a thought : what about encoding palette into texture which can be varying ? Quote Link to comment Share on other sites More sharing options...
CZauX Posted December 9, 2016 Author Share Posted December 9, 2016 I've found a way around this by just using Require and Browserify, and executing the filter function manually, along with passing the color palette to it. pixi.js bunny example: let colors = [ [0,0,0], [100,100,100], [150,150,150], [255,255,255] ]; var QuantizeFilter = require('./filters/quantize/QuantizeFilter'); var filter = new QuantizeFilter(colors); bunny.filters = [filter]; Filter: var glslify = require('glslify'); /** * * @class * @param colorPalette {array} array of 3 element array for colors * */ function QuantizeFilter(colorPalette) { let DefaultColors = [ [0,0,0], [100,100,100], [150,150,150], [255,255,255] ]; console.log(DefaultColors[0][1]); colorPalette = colorPalette || DefaultColors; var Palette = ''; for(let i = 0; i < colorPalette.length; i++) { Palette += `COLOR_PALETTE[${i}] = vec3(${colorPalette[i][0]}.0, ${colorPalette[i][1]}.0, ${colorPalette[i][2]}.0);\n\t`; } PIXI.Filter.call(this, // vertex shader // vertex shader glslify('./outline.vert'), // fragment shader glslify('./quantize.frag') .replace(/%%COLOR_PALETTE_SIZE%%/gi, colorPalette.length) .replace(/%%COLOR_PALETTE_HERE%%/gi, Palette) ); } QuantizeFilter.prototype = Object.create(PIXI.Filter.prototype); QuantizeFilter.prototype.constructor = QuantizeFilter; module.exports = QuantizeFilter; Fragment Shader: https://gist.github.com/Cyken-Zeraux/5798fda4a7d39f3d022cbf69b6c4c728 Vector Shader: attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; uniform mat3 projectionMatrix; varying vec2 vTextureCoord; void main(void){ gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); vTextureCoord = aTextureCoord; } Its actually not possible to pass a sizable palette to the shader with Uniforms because the maximum is 1024. Meaning, a 512 color palette is not supported. Neither arrays of vec3's (3fv) or three arrays, one of each color (1i), works. So, I've had to hardcode the pallete values into the main loop. #Solved. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.