Jump to content

Set Uniform array size from filter configuration


CZauX
 Share

Recommended Posts

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.

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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.
}

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...