Skip to content

Unable to resize (error thrown when canvas is resized) using p5.Graphics off-screen graphics buffer + WebGL #5814

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

Closed
3 of 17 tasks
jellygatorade opened this issue Sep 25, 2022 · 3 comments · Fixed by #5815
Closed
3 of 17 tasks

Comments

@jellygatorade
Copy link

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

v1.4.2

Web browser and version

Chrome 105.0.5195.127, Firefox 105.0.1, Edge 105.0.1343.50

Operating System

Windows 10 21H1 Build 19043.1889

Steps to reproduce this

Hello 👋 and thanks for your help with this 😊.

I am using the p5.Graphics off-screen buffer in WebGL mode to write a back buffer as exemplified here.

I would like to be able to dynamically resize the p5.Graphics buffer similarly as the method of resizing the main canvas with the browser window:

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

But when my canvas is resized an exception is thrown in the JavaScript console that I assume is related to a problem with resizing my p5.Graphics instance. When I take the p5.Graphics instance out and resize the window this error is not thrown. Here is the stack trace:

Uncaught TypeError: e.setModified is not a function
    at i.default.Texture.update (p5.min.js:3:808990)
    at i.default.Shader.bindTextures (p5.min.js:3:799941)
    at u.default.RendererGL._setFillUniforms (p5.min.js:3:791099)
    at s.default.RendererGL._drawImmediateFill (p5.min.js:3:737282)
    at s.default.RendererGL.endShape (p5.min.js:3:735615)
    at E.default.RendererGL.image (p5.min.js:3:677139)
    at x.default.image (p5.min.js:3:569591)
    at draw (sketch.js:20:14)
    at o.default.redraw (p5.min.js:3:494224)
    at l.default.resizeCanvas (p5.min.js:3:473596)
i.default.Texture.update @ p5.min.js:3
i.default.Shader.bindTextures @ p5.min.js:3
u.default.RendererGL._setFillUniforms @ p5.min.js:3
s.default.RendererGL._drawImmediateFill @ p5.min.js:3
s.default.RendererGL.endShape @ p5.min.js:3
E.default.RendererGL.image @ p5.min.js:3
x.default.image @ p5.min.js:3
draw @ sketch.js:20
o.default.redraw @ p5.min.js:3
l.default.resizeCanvas @ p5.min.js:3
windowResized @ sketch.js:47
o.default._onresize @ p5.min.js:3

I have seen this issue has been discussed previously here and here, but perhaps these instances are not related to WebGL usage of p5.Graphics? The resolutions proposed are not working for me, for example using any of the following within windowResized() :

backbuffer.size(windowWidth, windowHeight); or backbuffer.width = windowWidth; backbuffer.height = windowHeight; or backbuffer.size(width, height);

The same exception as above is thrown when using any of these methods.

So—here is my full code with JS and GLSL:

JavaScript:

let theShader, backbuffer, canvas;

function preload() {
  theShader = loadShader("render.vert", "render.frag");
}

function setup() {
  canvas = createCanvas(windowWidth, windowHeight, WEBGL);

  // create an off-screen canvas to be used as a back buffer
  backbuffer = createGraphics(width, height, WEBGL);
  backbuffer.clear();
}

function draw() {
  // move the image drawn on the main canvas from the previous frame to the back buffer
  backbuffer.clear();
  backbuffer.image(canvas, width * -0.5, height * -0.5, width, height);

  shader(theShader);

  // send the back buffer, where the previous frame was drawn, into the shader program
  theShader.setUniform("buffer", backbuffer);

  // enter a value to calculate according to the current screen size
  theShader.setUniform("res", [width, height]);

  // time as current frame count
  theShader.setUniform("time", [frameCount]);

  // since the mouse coordinates and the position of pixels in the shader are converted into values between 0 and 1, the mouse coordinates are also changed accordingly
  let mx = mouseX / width;
  let my = 1 + (-1 * mouseY) / height;
  theShader.setUniform("mouse", [mx, my]);

  rect(0, 0, width, height);
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  //backbuffer.size(windowWidth, windowHeight);
  //backbuffer.width = windowWidth;
  //backbuffer.height = windowHeight;
  //backbuffer.size(windowWidth, windowHeight);
  //backbuffer.size(width, height);
}

Vertex Shader:

// https://github.com/aferriss/p5jsShaderExamples
// This vertex shader only functions to draw a rectangle to draw the image.

#ifdef GL_ES
precision highp float;
#endif

attribute vec3 aPosition;

void main() {

  // Copy the position data into a vec4, adding 1.0 as the w parameter
  vec4 positionVec4 = vec4(aPosition, 1.0);

  // Scale to make the output fit the canvas
  positionVec4.xy = positionVec4.xy * 2.0 - 1.0; 

  // Send the vertex information on to the fragment shader
  gl_Position = positionVec4;
}

Fragment Shader:

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 res;
uniform sampler2D buffer;
uniform float time;
uniform vec2 mouse;

void main() {
  // gl_FragCoord.xy can be thought of as the position of the pixel
  vec2 st = gl_FragCoord.xy;
  
  vec3 col = vec3(0);
  
  // the pixel position is changing to a value between 0 and 1
  vec2 tc = st / res;
  
  // the pixel position is changing to a value between 0 and 1
  vec2 buffer_tc = st / res;
  // corrected because the back buffer y direction is reversed
  buffer_tc.y = 1. + buffer_tc.y * -1.; 
  
  // get pixel values from the back buffer image with a function called texture2D.
  // texture2D(texture, texture coordinates (between 0 and 1))
  vec3 buffer_samp = texture2D(buffer, buffer_tc).xyz;
  
  // radius of circle
  float r = 0.1;

  // depending on the condition, pixels that meet the criteria of the circle become white.
  float ell = smoothstep(r,r-0.01,length((tc-mouse) * res / res.y));
  
  // adds a darker pixel value from the previous screen to the current screen
  col = vec3(ell) + buffer_samp.xyz * 0.98;

  gl_FragColor = vec4(col, 1.0);
}

Thanks for looking into this. Please let me know if I can give any more information to troubleshoot or if I have missed reading something in the p5.js documentation 😊.

@welcome
Copy link

welcome bot commented Sep 25, 2022

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms. Thank you!

@davepagurek
Copy link
Contributor

Thanks for catching this! This is happening because p5.Texture handles updates to p5.Graphics, but you're making a texture out of the main canvas via a p5.Renderer. I'll add that case into the code and add some tests.

@jellygatorade
Copy link
Author

@davepagurek Thanks for your response! Glad I could help. 😊

I think I have uncovered one more (probably separate?) issue with using p5.Graphics so I will open another issue when I get the chance to write it up later on. Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants