Jump to content

Getting original texture in between the filters as a uniform for the next filter


pokrishka
 Share

Recommended Posts

Hi there guys.

Say I want to make a filter that does something to original texture after it was blurred with Blur filter. Here's the PIXI blur filter:

BlurFilter.prototype.applyFilter = function (renderer, input, output)
{
    var renderTarget = renderer.filterManager.getRenderTarget(true);

    this.blurXFilter.applyFilter(renderer, input, renderTarget);
    this.blurYFilter.applyFilter(renderer, renderTarget, output);

    renderer.filterManager.returnRenderTarget(renderTarget);
};

Is there a way for me to store original input texture and use it as a uniform for my filter, kinda like that:

this.myFilter.originalTexture = input.texture;

this.blurXFilter.applyFilter(renderer, input, renderTarget);
this.blurYFilter.applyFilter(renderer, renderTarget, renderTargetTemp);

this.myFilter.applyFilter(renderer, renderTargetTemp, output);

I tried getting input.texture however input.texture is an empty WebGLTexture object at that point.

Link to comment
Share on other sites

Well, once it works lol :) So far I'm trying to get efficient glow filter. Current custom PIXI glow filter is rather slow since it does quite a lot of computation per each pixel. Blur, on the other hand, is very well optimized and mixing blurred data with real data will allow for calculating both outter and inner glow without having to go around each pixel over set distance in all directions, with precision defined by arbitrary "quality" parameter.

Link to comment
Share on other sites

The reason you can't use it in the way you have there is because the uniform is looking for a PIXI.Texture object (which PIXI.RenderTexture also inherits from). And the value you are assigning there is a PIXI.RenderTarget. You might be able to create a RenderTexture object, and manually assign the `.textureBuffer` data to that render target:

https://github.com/pixijs/pixi.js/blob/5d385885324e97369fd29b686e9e90eb4cefd14a/src/core/textures/RenderTexture.js#L133-L134

Then assign that RenderTexture to your uniform value, and that may work. You may also need to also manually call `.syncUniforms` since you are changing uniform values mid-render:

https://github.com/pixijs/pixi.js/blob/5d385885324e97369fd29b686e9e90eb4cefd14a/src/core/renderers/webgl/shaders/Shader.js#L469

That might work?

This would be a first-class feature if WebGL had multiple render targets, but as it is there is only 1 target and X inputs. And we expected that extra inputs would be setup as uniforms beforehand. This case wasn't really considered, so that's our fault!

 

Link to comment
Share on other sites

Ok since this proved to be harder than I thought I figured I'd give a try to a different approach which would be to combine 2 filters instead of making a single one:

This combination does the job:

var blurFilter = new PIXI.filters.BlurFilter();
var tintFilter = new TintFilter();
tintFilter.originalTexture = shape.texture;
shape.filters = [blurFilter, tintFilter];

Here how the resulting glow looks like once we use original texture values to colorize blurred version (both outter and inner glow present):

correct.JPG

However that only happens when the renderer size is the same as texture, when it's larger this is what I get:

wrong.JPG

How do I limit this uniform to the size of the Sprite being filtered?

Here's the shader I used for the glow, once I get this working I will make it customizable so you could set distance, color and strength:

'precision mediump float;',
'varying vec2 vTextureCoord;',
'uniform sampler2D texture;',
'uniform sampler2D originalTexture;',
'void main(void) {',
'    vec4 originalColor = texture2D(originalTexture, vTextureCoord);',
'    vec4 currentColor = texture2D(texture, vTextureCoord);',
'    if (originalColor.a == 0.0) {',
'       gl_FragColor = vec4(1.0 * currentColor.a, 0.0, 0.0, currentColor.a);',
'    } else {',
'       vec4 innerGlow = vec4(1.0 * (1.0 - currentColor.a), 0.0, 0.0, (1.0 - currentColor.a));',
'       gl_FragColor = mix(innerGlow, originalColor, currentColor.a);',
'    };',
'}'
Link to comment
Share on other sites

 

On 06.04.2016 at 5:56 PM, xerver said:

Yeah, that's the point, this filter seems rather slow to me. I've been working on some sophisticated glow with animated patterns based on that glow filter and noticed it starts lagging pretty hard even on my home PC which isn't that great but well above low-end machines. Looking at how the computations are done in it I figured there's way too many steps to calculate values and I thought of using well-optimized blur technique instead.

Here, I've created a Codepen with my glow filter:

http://codepen.io/waterplea/pen/oxpReQ

I haven't done benchmarking but while I was working on it and comparing it to the actual GlowFilter, it seemed much faster. Especially on big shapes. The number of blur passes could be increased if it gets not enough for a complex shape, but that is still faster - that glow filter from the extras takes each pixel and then goes around it over the distance and calculates the weight of each pixel's glow, that is way too slow to use in games.

The only problem is, my glow filter, as it is now, requires some heavy preliminary settings, like this:

glowFilter.originalTexture = shape.texture;
glowFilter.xMultiplier = renderer.width / shape.texture.width;
glowFilter.yMultiplier = renderer.height / shape.texture.height;
glowFilter.xOffset = shape.x / renderer.width;
glowFilter.yOffset = shape.y / renderer.height;

And since it also has padding introduced, you have to update offsets each time you change glow distance. All of these settings could be done mid-render if I get access to the texture - the question I initally asked in this thread. There must be a way to do so, if I can implement it - this glow will be feasible for actual use in animation, games etc, unlike the GlowFilter from the extras.

Link to comment
Share on other sites

So, to reiterate on the blocking issue, if I have this code:

this.tintFilter.syncUniform(this.tintFilter.originalTexture);

I'm getting a ton of this error in console:

WebGL: INVALID_OPERATION: uniform1i: location not for current program

Looks like I have to set the current program for the renderer to which I need to syncUniforms, but I don't know how to do that, I don't know how to access actual shader of my filter (it says shader is empty and it only has fragmentSrc as a string, basically).

 

Link to comment
Share on other sites

  • 1 month later...

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