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

filter() shader uniforms stop working if you use more than one #6466

Closed
1 of 17 tasks
davepagurek opened this issue Oct 10, 2023 · 3 comments · Fixed by #6482
Closed
1 of 17 tasks

filter() shader uniforms stop working if you use more than one #6466

davepagurek opened this issue Oct 10, 2023 · 3 comments · Fixed by #6482

Comments

@davepagurek
Copy link
Contributor

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build Process
  • Unit Testing
  • Internalization
  • Friendly Errors
  • Other (specify if possible)

p5.js version

main branch

Web browser and version

Firefox, Chrome

Operating System

macOS 14

Steps to reproduce this

Steps:

  1. Create two filter shaders that need uniforms
  2. Apply uniforms and apply both shaders one after the other via filter()
    The uniforms don't get passed in or updated.

Snippet:

let shaderA
let shaderB

function setup() {
  createCanvas(400, 400, WEBGL);
  shaderA = createFilterShader(`
    precision highp float;
    uniform sampler2D tex0;
    uniform float off;
    varying vec2 vTexCoord;
    void main() {
      gl_FragColor = texture2D(tex0, vTexCoord + vec2(-off, 0.));
    }
  `)
  shaderB = createFilterShader(`
    precision highp float;
    uniform sampler2D tex0;
    uniform float off;
    varying vec2 vTexCoord;
    void main() {
      gl_FragColor = texture2D(tex0, vTexCoord + vec2(0, -off));
    }
  `)
}

function draw() {
  background(220)
  rectMode(CENTER)
  rect(0, 0, 20, 20)
  
  // Uncommenting one at a time works, but having both uncommented
  // makes neither shader's uniforms work
  
  shaderA.setUniform('off', map(mouseX, 0, width, -1, 1, true))
  filter(shaderA)
  
  shaderB.setUniform('off', map(mouseY, 0, height, -1, 1, true))
  filter(shaderB)
}

Live: https://editor.p5js.org/davepagurek/sketches/IQyixHYPt

Causes

It seems to be because of this section of code:

let isSameUserShader = (
this.filterShader !== undefined &&
userShader._vertSrc === this.filterShader._vertSrc &&
userShader._fragSrc === this.filterShader._fragSrc
);
if (!isSameUserShader) {
this.filterShader =
new p5.Shader(pg._renderer, userShader._vertSrc, userShader._fragSrc);
this.filterShader.parentShader = userShader;
}

If you switch filter shaders from one to another, it creates a new shader object. This means that the shader actually being run is not the one you are setting the uniforms on.

@aferriss
Copy link
Contributor

Wonder if this is related to #6430 where the uniforms seem to get set at the wrong time.

@davepagurek
Copy link
Contributor Author

For that one, I assume it's because createShader doesn't immediately compile the shader, and instead defers it until it is first used, since we don't know which context (main canvas, graphic, etc) it will be called on. I think we just return early if we haven't compiled the shader here:

setUniform(uniformName, data) {
const uniform = this.uniforms[uniformName];
if (!uniform) {
return;

Once we can get it to go past that, we'll probably run into this issue too though!

@davepagurek davepagurek mentioned this issue Oct 12, 2023
7 tasks
@davepagurek
Copy link
Contributor Author

If we solve #6430 by auto-binding createFilterShader to the filter graphic, then I think we can actually take out these code blocks, which exist to handle the fact that one might pass in a user shader that has been bound to the main canvas:

let isSameUserShader = (
this.filterShader !== undefined &&
userShader._vertSrc === this.filterShader._vertSrc &&
userShader._fragSrc === this.filterShader._fragSrc
);
if (!isSameUserShader) {
this.filterShader =
new p5.Shader(pg._renderer, userShader._vertSrc, userShader._fragSrc);
this.filterShader.parentShader = userShader;
}

let other = this._renderer.filterShader;
if (other !== undefined && other.parentShader === this) {
other.setUniform(uniformName, data);
return;
}

Then, we aren't dynamically regenerating new shaders every frame, and this issue would go away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: DONE! 🎉
Development

Successfully merging a pull request may close this issue.

2 participants