Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIXI fails to create a Filter from custom shader code #4476

Closed
doebi opened this issue Nov 22, 2017 · 30 comments
Closed

PIXI fails to create a Filter from custom shader code #4476

doebi opened this issue Nov 22, 2017 · 30 comments

Comments

@doebi
Copy link

doebi commented Nov 22, 2017

I am struggling to get a custom Filter with my own shader code working with this error message:

VertexArrayObject.js:171 Uncaught TypeError: Cannot read property 'location' of undefined
    at VertexArrayObject.addAttribute (VM1006 pixi.js:2348)
    at Quad.initVao (VM1006 pixi.js:19874)
    at FilterManager.applyFilter (VM1006 pixi.js:18947)
    at Filter.apply (VM1006 pixi.js:18420)
    at FilterManager.popFilter (VM1006 pixi.js:18877)
    at Container.renderAdvancedWebGL (VM1006 pixi.js:9423)
    at Container.renderWebGL (VM1006 pixi.js:9360)
    at Container.renderWebGL (VM1006 pixi.js:9366)
    at WebGLRenderer.render (VM1006 pixi.js:17563)
    at Application.render (VM1006 pixi.js:8043)

Even the official example is failing with this bug:
http://pixijs.io/examples/#/filters/filter-mouse.js

This error message has been related to some compiler optimizations where glslify removed some unused uniforms, which pixi still tried to access. But this even occurs with a completely static fragShader without any uniforms. gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0)

@Cristy94
Copy link
Contributor

The example works for me, what browser are you testing you in?

@doebi
Copy link
Author

doebi commented Nov 23, 2017

Google Chrome Version 62.0.3202.94 (Official Build) (64-bit)
2017-11-23-143829_667x172_scrot

Firefox Quantum 57.0 (64-bit)
2017-11-23-143957_741x236_scrot

OS: Ubuntu 17.10 artful

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Nov 23, 2017

@doebi nice catch! Yeah, optimization removed something (I bet its sampler) and we forgot to check it.

For now, are you sure that you need filter without usage of sampler? In some cases its better to make renderer plugin like https://github.com/pixijs/pixi-plugin-example ?

Second time this day, Im sorry for the mess that shader and filters are in v4. We'll fix it in v5.

@doebi
Copy link
Author

doebi commented Nov 23, 2017

To be honest, i haven't really dug deep into this topic yet. Just wanted to experiment with that feature the other day. I will do some testing with the renderer plugin approach. Thanks for the hint.

Is there already some ETA for v5?

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Nov 23, 2017

2 months or so :)

There are many tricks about filters, that's why I made that article: https://github.com/pixijs/pixi.js/wiki/v4-Creating-Filters

@doebi
Copy link
Author

doebi commented Nov 24, 2017

@ivanpopelyshev Following your tutorial, i ran into the same issue.
I applied a really hacky patch to pixi.js to make it work for me.

diff --git a/js/pixi.js b/js/pixi.js
index 363f09c..d0a321b 100644
--- a/js/pixi.js
+++ b/js/pixi.js
@@ -2344,6 +2344,9 @@ VertexArrayObject.prototype.activate = function()
  */
 VertexArrayObject.prototype.addAttribute = function(buffer, attribute, type, normalized, stride, start)
 {
+  if (!attribute) {
+    return this;
+  }
     this.attributes.push({
         buffer:     buffer,
         attribute:  attribute,

I know this is not a solution, but it enables me to play with shader codes in v4 until v5 is out. (with possibly a better fix) :)

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Nov 24, 2017

That's a good hack!

You can move it into separate js file:

PIXI.glCore.VertexArrayObject.prototype.addAttribute = ...

@germansokolov13
Copy link

I got the same problem. Also with Ubuntu 17.10 artful. Are shaders at all stable in Pixi.js? Can I use them in production? How do I import a pixel shader?

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Feb 15, 2018

Either as filter either as renderer plugin. They are stable but require serious knowledge both about webgl and about pixi architecture.

https://github.com/pixijs/pixi.js/wiki/v4-Creating-Filters
https://github.com/pixijs/pixi-plugin-example/

For N-th time I assure people that it'll be easier in v5.

@germansokolov13
Copy link

germansokolov13 commented Feb 15, 2018

const filterCode = `void main(){
   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}`;
const filter = new PIXI.Filter(null, filterCode);
someSprite.filters = [filter];

This much code leads to this error. Maybe I should go for a different constructor of the Filter? Or should I substitute null with something?

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Feb 15, 2018

For a filter, you have to use texture coord and sampler , otherwise FilterManager fails to get location of attribute.

Renderer plugin doesnt have that requirement, try it. Yeah, its big boilerplate.

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Feb 15, 2018

Try that thing: https://github.com/TazOen/createShaderPlugin . However it ignores the texture, there's no bindTexture there. If you need texture take whole pixi-plugin-example.

@germansokolov13
Copy link

You say it need texture coords and "sampler". Was sample or sampler? A typo?
I managed to make it working with the help of example. Thank you but. Why doesn't this page mention these details?
http://pixijs.io/examples/#/basics/custom-filter.js

@ivanpopelyshev
Copy link
Collaborator

Sampler. However its uniform and I dont think somebody will miss it. Our problem is about attributes.

Thanks to you, it does :) https://github.com/pixijs/pixi.js/wiki/v4-Creating-Filters#cannot-read-property-location-of-undefined

@germansokolov13
Copy link

Oh, so that's where it was. I missed the wiki.

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Feb 15, 2018

Thanks to you, it does

I've added it just now.

Also added notice in filter-mouse demo. We cant fix the issue in v4. We'll do something about it in v5.

@germansokolov13
Copy link

germansokolov13 commented Feb 15, 2018

That appears when some of properties that are required by FilterManager are not used in the shader.

How about to list these properties in there?

@ivanpopelyshev
Copy link
Collaborator

only the attribute, aTextureCoord -> vTextureCoord

@germansokolov13
Copy link

This is getting very strange.
This code works fine:

varying vec2 vTextureCoord;
varying vec4 vColor;

uniform sampler2D uSampler;
uniform vec4 uTextureClamp;
uniform vec4 uColor;

void main(void)
{
    gl_FragColor = texture2D(uSampler, vTextureCoord);
    gl_FragColor.r = 0.0;
    gl_FragColor.g = 0.0;
    gl_FragColor.b = 0.0;
}

But if I add gl_FragColor.a = 0.0; to the end then it says Cannot read property 'location' of undefined. It seems as though I can only change 3 coords out of 4 at most. What is this? What is wrong?

@doebi
Copy link
Author

doebi commented Feb 16, 2018

@germansokolov13 this behaviour makes total sense. Just think about it:
As i mentioned in the original post this error occurs due to glsify optimizing the shader code.

If you add gl_FragColor.a = 0.0; it can optimize your call to texture2D, cause it gets fully overwritten, but until then it takes alpha channel from texture2D

If glsify optimizes the call to texture2D, webgl does not allocate memory for uSampler, hence when pixi wants to upload data to that uniform it fails, cause there is simply no space for that allocated.

You got some options:

  • Apply the same hack as i did (for now), which basically checks if an attribute is allocated before uploading data to it.
  • Use uSampler, so glsify doesn't optimize it away.
  • Or just wait for v5.

Hopefully, this helps.

@ivanpopelyshev
Copy link
Collaborator

ivanpopelyshev commented Feb 16, 2018

Nice catch, @doebi!

Or use renderer plugin.

@germansokolov13
Copy link

Oh, now I get it! Maybe we should add Doebi's patch to the next minor release of Pixi.js? Should I create a PR?

@ivanpopelyshev
Copy link
Collaborator

Yep, PR, but different place.

https://github.com/pixijs/pixi.js/blob/dev/src/core/renderers/webgl/utils/Quad.js#L93
https://github.com/pixijs/pixi.js/blob/dev/src/core/renderers/webgl/managers/FilterManager.js#L242

I suggest extra class which overrides method and that is used in FilterManager.

@tyleet
Copy link

tyleet commented Mar 9, 2018

Hi there,
I'm experiencing a similar problem with my shader code. It is a variation of the default BlurYFilter shader code just with a bigger kernel and a little variation on the gaussian variable, so I'm not entirely sure why it's not working.

It's working fine on Windows, MacOS and Android as far as I tested I only have issues in iOS.
Here's the shader code:
vertex:

attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
uniform float strength;
uniform mat3 projectionMatrix;
varying vec2 vBlurTexCoords[15];
void main(void){
   gl_Position = vec4((projectionMatrix * vec3((aVertexPosition), 1.0)).xy, 0.0, 1.0);
   vBlurTexCoords[0] = aTextureCoord + vec2(0.0, -7.0 * strength);
   vBlurTexCoords[1] = aTextureCoord + vec2(0.0, -6.0 * strength);
   vBlurTexCoords[2] = aTextureCoord + vec2(0.0, -5.0 * strength);
   vBlurTexCoords[3] = aTextureCoord + vec2(0.0, -4.0 * strength);
   vBlurTexCoords[4] = aTextureCoord + vec2(0.0, -3.0 * strength);
   vBlurTexCoords[5] = aTextureCoord + vec2(0.0, -2.0 * strength);
   vBlurTexCoords[6] = aTextureCoord + vec2(0.0, -1.0 * strength);
   vBlurTexCoords[7] = aTextureCoord + vec2(0.0, 0.0 * strength);
   vBlurTexCoords[8] = aTextureCoord + vec2(0.0, 1.0 * strength);
   vBlurTexCoords[9] = aTextureCoord + vec2(0.0, 2.0 * strength);
   vBlurTexCoords[10] = aTextureCoord + vec2(0.0, 3.0 * strength);
   vBlurTexCoords[11] = aTextureCoord + vec2(0.0, 4.0 * strength);
   vBlurTexCoords[12] = aTextureCoord + vec2(0.0, 5.0 * strength);
   vBlurTexCoords[13] = aTextureCoord + vec2(0.0, 6.0 * strength);
   vBlurTexCoords[14] = aTextureCoord + vec2(0.0, 7.0 * strength);
}

fragment:

varying vec2 vBlurTexCoords[15];
uniform sampler2D uSampler;
void main(void){
   gl_FragColor = vec4(0.0);
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[0]) * 0.013068780984604511;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[1]) * 0.013907007172070673;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[2]) * 0.017439264394216315;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[3]) * 0.028762309061254498;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[4]) * 0.05603114255667656;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[5]) * 0.10421702583793174;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[6]) * 0.163461199220823;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[7]) * 0.2062265415448454;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[8]) * 0.163461199220823;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[9]) * 0.10421702583793174;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[10]) * 0.05603114255667656;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[11]) * 0.028762309061254498;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[12]) * 0.017439264394216315;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[13]) * 0.013907007172070673;
   gl_FragColor += texture2D(uSampler, vBlurTexCoords[14]) * 0.013068780984604511;
}

for comparision here are the shaders of the default BlurYFilter:
vert:

attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
uniform float strength;
uniform mat3 projectionMatrix;
varying vec2 vBlurTexCoords[5];
void main(void)
{
  gl_Position = vec4((projectionMatrix * vec3((aVertexPosition), 1.0)).xy, 0.0, 1.0);
  vBlurTexCoords[0] = aTextureCoord + vec2(0.0, -2.0 * strength);
  vBlurTexCoords[1] = aTextureCoord + vec2(0.0, -1.0 * strength);
  vBlurTexCoords[2] = aTextureCoord + vec2(0.0, 0.0 * strength);
  vBlurTexCoords[3] = aTextureCoord + vec2(0.0, 1.0 * strength);
  vBlurTexCoords[4] = aTextureCoord + vec2(0.0, 2.0 * strength);

}

frag:

varying vec2 vBlurTexCoords[5];
uniform sampler2D uSampler;
void main(void)
{
    gl_FragColor = vec4(0.0);
    gl_FragColor += texture2D(uSampler, vBlurTexCoords[0]) * 0.153388;
    gl_FragColor += texture2D(uSampler, vBlurTexCoords[1]) * 0.221461;
    gl_FragColor += texture2D(uSampler, vBlurTexCoords[2]) * 0.250301;
    gl_FragColor += texture2D(uSampler, vBlurTexCoords[3]) * 0.221461;
    gl_FragColor += texture2D(uSampler, vBlurTexCoords[4]) * 0.153388;

}

Does Anybody have any ideas why this could go wrong?

@ivanpopelyshev
Copy link
Collaborator

@tyleet are you sure its the same issue? What do you see in the console?

@tyleet
Copy link

tyleet commented Mar 12, 2018

EDIT:
Nevermind, I found the issue, it seems kernel size of 15 is too much for iOS, if I reduce kernel size to 7 it works fine.

<-----Original post--------->
Hi,
sorry for the late response, I was not able to make some screenshots over the weekend. It looks to me as if it fails on the same line. "attribute" is undefined. Here are the screenshots from the remote console:
image
image

@doebi
Copy link
Author

doebi commented Mar 12, 2018

@ivanpopelyshev shall we close this issue to prevent others from warming it up with similar issues?
I wouldn't consider it an issue anymore, since i got your promise, that it will be fixed in v5.

@ivanpopelyshev
Copy link
Collaborator

@doebi closing.

@ivanpopelyshev
Copy link
Collaborator

@tyleet the number of samples taken from texture can be limited on different systems.

@lock
Copy link

lock bot commented Mar 12, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked and limited conversation to collaborators Mar 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants