DNIWE

Structs as uniform type (in fragment shader)

Recommended Posts

Hello.

I'm making example filter with custom fragment shader. This is what I have in terms of shader code so far:

//fragShader
struct SomeInfo
{
    vec4 color;
};
uniform SomeInfo c;

void main()
{
    gl_FragColor = c.color;
}

The idea is to (eventually) make c into an array of Infos, which would be then operated on by the shader.

What I'm struggling with is the definition of filter:

  • how do I declare the uniform to be of type SomeInfo in Js code?

I assume in plain WebGL, I'd have to bind uniform location (of c's property) by calling gl.getUniformLocation(program, "c.color") and create a uniform with appropriate gl.uniform4f(location, /* bunch of values*/),

but can I do something similar via the existing filters means? 

Relevant part of my Js code looks like this:

//Define base filter class for our future shaders/filters
PIXI.filters.CustomFilterBase = class CustomFilterBase extends PIXI.Filter
{
	constructor({ vertexSrc = null, fragmentSrc = null, uniforms = {}, enabled = true, debug = false, name = null } = {})
	{
		if(debug && fragmentSrc !== null)
		{
			fragmentSrc = "#define DEBUG \r\n" + fragmentSrc;
		}
		//Add dimensions for scaling
		uniforms.dimensions = { type: 'vec2', value: { x: 0.0, y: 0.0 } };
		super(vertexSrc, fragmentSrc, uniforms);
		name ? this._name = name : this._name = "CustomFilterBase";
		this.autoFit = false;
		this.enabled = enabled;
	}
	apply(filterManager, input, output)
	{
		this.uniforms.dimensions.x = input.sourceFrame.width;
		this.uniforms.dimensions.y = input.sourceFrame.height;
		// draw the filter...
		filterManager.applyFilter(this, input, output);
	}
}

//Shader for prototyping and testing
PIXI.filters.TestFilter = class TestFilter extends PIXI.filters.CustomFilterBase
{
	constructor()
	{
		let fragmentSrc = document.getElementById('fragShader').innerHTML;
		let uniforms =
		{
			//What do I do here?!
			c:
			{
				type: 'vec4', //Judging by GLSL_SINGLE_SETTERS, only GLSL's primitives are recognized
				value: new Float32Array([0.0, 1.0, 0.0, 1.0]) 
			}
		};
		super({ vertexSrc: null, fragmentSrc: fragmentSrc, uniforms: uniforms, name: 'testfilter' });
	}
}

(using pixijs v4.8.7)

The expected result is green screen, as it is if I declare c as vec4 in shader code, but alas the screen is black, hinting on c's value being default constructed / not properly assigned

Any help is appreciated,

cheers!

P.S. I tried to find similar cases from this forum and stackoverflow,  but it seems that few people use structs in GLSL code.

P.P.S. If it is of any help, I found that PIXI.glCore.shader removes specific characters from uniform's name (which looks like a hotfix rather than a feature)

and that in fact one of iterations uniformData's name is 'c.color'. 

/**
 * Extracts the uniforms
 * @class
 * @memberof PIXI.glCore.shader
 * @param gl {WebGLRenderingContext} The current WebGL rendering context
 * @param program {WebGLProgram} The shader program to get the uniforms from
 * @return uniforms {Object}
 */
var extractUniforms = function(gl, program)
{
	var uniforms = {};

    var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);

    for (var i = 0; i < totalUniforms; i++)
    {
    	var uniformData = gl.getActiveUniform(program, i);
    	var name = uniformData.name.replace(/\[.*?\]/, ""); //<----- Here it is!!
        var type = mapType(gl, uniformData.type );

    	uniforms[name] = {
    		type:type,
    		size:uniformData.size,
    		location:gl.getUniformLocation(program, name),
    		value:defaultValue(type, uniformData.size)
    	};
    }

	return uniforms;
};

 

Share this post


Link to post
Share on other sites

PixiJS philosophy allows to use webgl hacks when you really know what are you doing and how it affects PixiJS state.

You can hack "apply" function of the filter or "applyFilter" function of FilterManager: bind the shader there and assign your uniforms :)

How filterManager handles it https://github.com/pixijs/pixi.js/blob/v4.x/src/core/renderers/webgl/managers/FilterManager.js#L242

How filter calls filterManager: https://github.com/pixijs/pixi.js/blob/v4.x/src/filters/displacement/DisplacementFilter.js#L64

It looks like "syncUniforms" is the best place to apply the hack: shader is already bound.

Just in case if you need whats inside GLShader: https://github.com/pixijs/pixi-gl-core/blob/master/src/GLShader.js#L40

var oldSyncUniforms = renderer.filterManager.syncUniforms;
renderer.filterManager.syncUniforms = function(shader, filter) {
    oldSyncUniforms.call(this, shader, filter);
    if (filter.syncUniforms) {
        filter.syncUniforms(shader);
    }
}

myFilter.syncUniforms = function(shader) {
    var gl = shader.gl;
    gl.uniform1f(...);
}

 

Share this post


Link to post
Share on other sites

struct don't have location so you can't set them directly in code. What has location are the struct properties so in your case you can set the uniform for "c.color". This is a valid GLSL syntax for setting unifroms.

Share this post


Link to post
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...

  • Recently Browsing   0 members

    No registered users viewing this page.