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

Incorrect textureFiltering for Framebuffers #6408

Closed
2 of 17 tasks
KeyboardSounds opened this issue Sep 15, 2023 · 3 comments · Fixed by #6420
Closed
2 of 17 tasks

Incorrect textureFiltering for Framebuffers #6408

KeyboardSounds opened this issue Sep 15, 2023 · 3 comments · Fixed by #6420

Comments

@KeyboardSounds
Copy link
Contributor

KeyboardSounds commented Sep 15, 2023

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

1.7.0

Web browser and version

Chrome 116.0.0.0

Operating System

MacOS 13.3.1 (Ventura)

Steps to reproduce this

Steps:

ThetextureFiltering option of createFramebuffer is ignored by the renderer.

  1. Create a Framebuffer smaller than the canvas, set textureFiltering to NEAREST.
  2. Use a shader to sample the Framebuffer texture and draw it to the canvas. This will upscale it.
  3. Note that the result is blurry around the outline of the circle, indicating that it was upscaled with LINEAR interpolation instead of NEAREST (see output image below)

linear-filtering

Snippet:

See here for the live sketch version.

Copy of the code in the sketch
/*
p5 version: 1.7.0

This code renders a circle to a Framebuffer at a lower resolution, and then uses shaders to upscale it to a higher resolution canvas.

The texture filtering for the Framebuffer is set to NEAREST, but this seems to be ignored, and the LINEAR interpolation is used instead, as shown by the blurry output.
*/

const canvasSize = 512;
const framebufferSize = canvasSize/16;
let myShader;
let framebuffer;

let debug_log_framebuffer = true;

const vs = `
attribute vec3 aPosition;

// texture coordinates
attribute vec2 aTexCoord;

// the varying variable will pass the texture coordinate to our fragment shader
varying vec2 vTexCoord;

void main() {
  // assign attribute to varying, so it can be used in the fragment
  vTexCoord = aTexCoord;

  vec4 positionVec4 = vec4(aPosition, 1.0);
  positionVec4.xy = positionVec4.xy * 2.0 - 1.0;

  gl_Position = positionVec4;
}
  `;

// Sample the texture from the framebuffer
const fs = `
  precision mediump float;
  uniform sampler2D img;

varying vec2 vTexCoord;

void main() {
  // sample texture using coords from vertex shader
  gl_FragColor = texture2D(img, vTexCoord);
}
  `;

function setup() {
  createCanvas(canvasSize, canvasSize, WEBGL);
  // BUG: We set the texture filtering to NEAREST here, but this is is ignored at render time.
  // `noSmooth();` makes no difference, as noted in https://github.com/processing/p5.js/issues/6325
  framebuffer = createFramebuffer({
    width: framebufferSize,
    height: framebufferSize,
    textureFiltering: NEAREST,
    antialias: false
  });
  myShader = createShader(vs, fs);
  strokeWeight(2);
  stroke(0);
}

function draw() {
  // Draw the circle to the framebuffer
  resetShader();
  framebuffer.begin();
  background("cornflowerblue");
  circle(0, 0, framebufferSize / 2);
  framebuffer.end();
      
  shader(myShader);
  // BUG: inspecting the inner framebuffer color texture in the debugger shows that it's using LINEAR interpolation instead of NEAREST
  myShader.setUniform("img", framebuffer.color);
  
  // only log once, not every frame
  if(debug_log_framebuffer) {

    console.log(framebuffer.color.framebuffer.colorP5Texture)
    // The output shows that:
    //   glMinFilter: 9729
    //   glMagFilter: 9729
    // This is the WEBGL constant for Linear interpolation (hex 0x2601) 
    // (see https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants#textures)
    
    debug_log_framebuffer = false;
  }
  rect(0, 0, canvasSize, canvasSize);
}

More Info

I took a look at the Framebuffer class, and it looks like glMinFilter and glMagFilter are being set correctly in here (but I haven't checked in a debugger yet):

this.color = new FramebufferTexture(this, 'colorTexture');
const filter = this.textureFiltering === constants.LINEAR
? gl.LINEAR
: gl.NEAREST;
this.colorP5Texture = new p5.Texture(
this.target._renderer,
this.color,
{
glMinFilter: filter,
glMagFilter: filter
}
);
this.target._renderer.textures.set(this.color, this.colorP5Texture);

so I suspect they're being unexpectedly modified somewhere else.

@KeyboardSounds
Copy link
Contributor Author

If someone more familiar with the codebase could confirm this is a bug and my analysis isn't completely off-base, I'll try putting together a PR to fix it (I know it's probably very low priority because it won't affect many users, so I totally understand if this goes to the bottom of the Issue pile).

The same bug could also be the root cause of #6325 but the comments there say otherwise, so I'm not sure.

@davepagurek
Copy link
Contributor

Yep looks like you're right! I suspect the issue is that in p5.Framebuffer.js, it sets gl(Min|Max)Filter in the settings, but p5.Texture expects them to be called (min|max)Filter:

this.glMinFilter = settings.minFilter || gl.LINEAR;
this.glMagFilter = settings.magFilter || gl.LINEAR;
this.glWrapS = settings.wrapS || gl.CLAMP_TO_EDGE;
this.glWrapT = settings.wrapT || gl.CLAMP_TO_EDGE;

If someone more familiar with the codebase could confirm this is a bug and my analysis isn't completely off-base, I'll try putting together a PR to fix it

Thanks! I'll assign this to you.

@harshsharma-11
Copy link

@KeyboardSounds @davepagurek where can i see the setup guide

@davepagurek davepagurek moved this from In Progress to DONE! 🎉 in p5.js WebGL Projects Oct 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: DONE! 🎉
p5.js WebGL Projects
  
DONE! 🎉
Development

Successfully merging a pull request may close this issue.

3 participants