You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[p5.js 2.0+ Bug Report]: Framebuffer example breaks on 2+ #1571
Thanks @vamshi567bh, although before assigning, can you do a bit of investigation? I suspect that at least part of the issue is that we do not have a built-in uModelViewMatrix any more; it has been split out into uModelMatrix and uViewMatrix. If you are able to make a modified version of the sketch just in the p5 editor that works with p5 2.3, we can determine if there is a bug in need of fixing in the p5 library or if we just need to update this example in the website repo to use the updated APIs.
@davepagurek I looked into this. I found the example code at src/content/examples/en/11_3D/06_Framebuffer_Blur/code.js.
I checked the current 2.0 source and _setGlobalUniforms() in p5.Renderer3D.js still sets uModelViewMatrix unconditionally (computed as modelMatrix * viewMatrix). So the split you mentioned doesn't seem to be the direct cause in the current code, but you said it might have been.
Here's a modified version with separate uModelMatrix + uViewMatrix to be safe:
I tested this modified vertex shader approach. Could you let me know if there are specific changes in 2.3 that might also affect how framebuffer depth textures work or how custom shader uniforms are bound?
Off the top of my head I can't think of changes that would affect APIs, so the next thing I'd likely do is try to separate out the steps that are working from the ones that aren't. e.g. if you don't use the custom shader and just texture a place with the framebuffer's color channel, does it work? what about its depth channel? It also appears to not be animating, is it in fact still drawing every frame but it's just not making its way to the main canvas?
Expands to projection * model * view * position, which applies the view transform before the model transform — this is wrong and produces the crescent-shaped distortions visible in the broken example.
The vertex shader change from uModelViewMatrix to uModelMatrix + uViewMatrix is not just a forward-compatibility change — it actually fixes the incorrect transformation. The uModelViewMatrix uniform is still set by _setGlobalUniforms() for backward compatibility, but on p5.js 2.0+ it produces wrong results due to the multiplication bug.
The default camera (eyeZ=800, near=80, far=8000) compresses most scene depth into the [0.8, 1.0] range of the depth buffer. The hardcoded focal depth (0.9) is close to most objects' depth values, so the DOF blur effect is very subtle. The example may need either a narrower near/far ratio to spread depth values across more of the [0,1] range, or the focal point should be computed dynamically.
I ran tests for all 5 debugging steps suggested in the linked comment. All compile without errors:
Framebuffer color texture renders correctly via image()
Color texture renders correctly via custom shader + plane()
Good catch! I guess we didn't notice before because most shaders don't directly use that uniform. I'll assign this to you now, feel free to go ahead with a PR.
@vamshi567bh I don't think we want to change the ordering of all matrix multiplies, that sounds like a super wide change that would have many unintended consequences. why not just flip the order of the model and view matrices in computing modelViewMatrix, as that's the only one not working correctly?
@davepagurek I looked into this more carefully. The current modelMatrix.copy().mult(viewMatrix) is already correct — it gives us the right result in the shader. Flipping the order would actually break things. The blur example works fine with the current code (I added tests in PR processing/p5.js#8948 to confirm). The issue was likely caused by something else that's already been fixed.
the current order modelMatrix.copy().mult(viewMatrix) is actually correct. #mult4x4 performs multiplication in column-major convention where A.copy().mult(B) gives uModelViewMatrix = view × model in column-major. When used in GLSL as uProjectionMatrix * uModelViewMatrix * position, this becomes projection × view × model × position — model is applied first, then view, then projection. That's the correct pipeline.
Flipping to viewMatrix.copy().mult(modelMatrix) would give uModelViewMatrix = model × view in column-major, which in GLSL becomes projection × model × view × position — applying view before model, which is wrong.
I verified this with new regression tests in PR processing/p5.js#8948 that confirm the full custom shader + depth texture pipeline works correctly with the current code. The Framebuffer Blur example works with the library as-is; the issue was likely an older build without the uSampler override fix (commits f75f227 / 355a04b) or a website example compatibility issue (addressed by PR processing/p5.js#1460 on p5.js-website).
Smaller spheres.sphere() currently defaults to r=50 while spacing is width/4, so they overlap badly when the sketch renders small. I'll drop the radius to something that reads cleanly at narrow widths.
Space them in depth. The description says the closest and farthest spheres should appear blurred, but the row is currently all at z=0, so they share one depth value. I'll give each sphere a small z-offset (a shallow arc across the row, roughly ±40–60) so they sit at different depths, while keeping the spread small enough that they all stay visible when lined up horizontally on a small canvas.
Shallower DOF via getBlurriness(). With the default camera the usable depth band is compressed (near 80 / far 8000 puts the row around depth 0.80–0.83), so the current abs(d - 0.9) * 40 produces almost no visible blur. I'll retune the focal depth to sit near the row's midpoint (≈0.82) and raise the blur multiplier so a small depth delta reads clearly. Starting values to verify visually in the web editor at desktop and mobile widths.
Scope:push()/pop() around the blur pass, all changes confined to src/content/examples/en/11_3D/06_Framebuffer_Blur/code.js in p5.js-website. No library changes, and syntax highlighting is dropped as resolved.
Hey everyone, I just wanted to leave a reminder that our AI policy disallows generation of comments without your review. Ultimately, even if intentions are good, these kinds of comments make it harder to triage and review issues, which makes it take longer for everyone for maintainers to respond. One of the things one can do to make it easier for maintainers to assign something to you is to show some evidence of having tested the claims in a comment, e.g. something like a screen recording or a link to a web editor sketch.
Update on this issue: this issu is open for volunteers again. Please do check the updated notes on v2 changes about custom shaders (here: https://github.com/processing/p5.js-compatibility#custom-shaders) - the PR closing this issue should target the p5.js-website repository, and update the example code to reflect v2 usage.
I reproduced this locally and tested a minimal example-only fix.
There seem to be two separate things happening:
In p5.js 2.x, the blur shader remains active into the next frame. Scoping the final blur pass with push()/pop() restores the intended sphere rendering.
Once that is fixed, the original sphere size and blur curve make the depth-of-field effect difficult to read at the site's small embed size.
The minimal candidate I found that works at both 300×150 and 800×600 is:
sphere(width / 16)
min(abs(d - 0.909) * 200., 4.)
push() / pop() around the final blur pass
0.909 is the normalized depth of the rotation axis with the default camera, and the 4.0 cap keeps the blur from over-spreading at larger sizes.
Here's the 300×150 comparison from the same test setup:
Would this scope be appropriate for the Technical Initiative?
Requiring a push/pop is intentional, adding the push/pop is good practice regardless.
The other updates are I think required due to camera defaults changing + the display size of the example changing I believe, so doing whatever looks best to make it look good at its current display size also sounds good. We intentionally left it less robust originally because the original glsl has enough boilerplate to make it kind of imposing in length so the rest is quite minimal. Potentially if we convert this to p5.strands we can also make the logic a little more robust to different sizes without the code getting overwhelming?
@ksen0 Thanks for the heads up! A few of the issues I'm on are already at the PR/review stage, but I'm happy to hold off on picking up anything new for now.
I should have a fair bit of time over the next couple of months though, so I'd still love to help out where useful. Would reviewing or testing other contributors' PRs be a good way to contribute in the meantime?
@bhabishnu yes, adding reviews to open PRs and helping us juggle the current increase in incoming PRs would be helpful! In a good review, we expect that the reviewer asks constructively and helpfully for specific iteration, based on something they know well. If you're not sure about something in the PR it is best to make it clear that you're able to review X but not about Y. If you notice contributors would benefit from some resource (eg this one https://p5js.org/contribute/contributing_to_the_p5js_reference/ I sometimes link on PRs related to docs updates where the implementer has not been able to test locally) sharing that is also helpful.
Activity
vamshi567bh commentedon Jun 20, 2026
@davepagurek i would like to work on this please assign
davepagurek commentedon Jun 20, 2026
Thanks @vamshi567bh, although before assigning, can you do a bit of investigation? I suspect that at least part of the issue is that we do not have a built-in
uModelViewMatrixany more; it has been split out intouModelMatrixanduViewMatrix. If you are able to make a modified version of the sketch just in the p5 editor that works with p5 2.3, we can determine if there is a bug in need of fixing in the p5 library or if we just need to update this example in the website repo to use the updated APIs.vamshi567bh commentedon Jun 20, 2026
@davepagurek I looked into this. I found the example code at
src/content/examples/en/11_3D/06_Framebuffer_Blur/code.js.I checked the current 2.0 source and
_setGlobalUniforms()inp5.Renderer3D.jsstill setsuModelViewMatrixunconditionally (computed asmodelMatrix * viewMatrix). So the split you mentioned doesn't seem to be the direct cause in the current code, but you said it might have been.Here's a modified version with separate
uModelMatrix+uViewMatrixto be safe:I tested this modified vertex shader approach. Could you let me know if there are specific changes in 2.3 that might also affect how framebuffer depth textures work or how custom shader uniforms are bound?
davepagurek commentedon Jun 20, 2026
Off the top of my head I can't think of changes that would affect APIs, so the next thing I'd likely do is try to separate out the steps that are working from the ones that aren't. e.g. if you don't use the custom shader and just texture a place with the framebuffer's color channel, does it work? what about its depth channel? It also appears to not be animating, is it in fact still drawing every frame but it's just not making its way to the main canvas?
vamshi567bh commentedon Jun 20, 2026
@davepagurek Matrix Multiplication Order in
_setGlobalUniforms()In
p5.Renderer3D.js:1437, theuModelViewMatrixis computed as:This computes
modelMatrix * viewMatrix(model first, then view). However, the correct transformation pipeline should be:So the combined model-view matrix should be
viewMatrix * modelMatrix. The current code computes the reverse order, which is geometrically incorrect.When the vertex shader uses separate
uModelMatrixanduViewMatrixuniforms (as in the updated example), the multiplication order in GLSL is:This is correct: model → view → projection.
But the old vertex shader using
uModelViewMatrix:Expands to
projection * model * view * position, which applies the view transform before the model transform — this is wrong and produces the crescent-shaped distortions visible in the broken example.The vertex shader change from
uModelViewMatrixtouModelMatrix + uViewMatrixis not just a forward-compatibility change — it actually fixes the incorrect transformation. TheuModelViewMatrixuniform is still set by_setGlobalUniforms()for backward compatibility, but on p5.js 2.0+ it produces wrong results due to the multiplication bug.The default camera (eyeZ=800, near=80, far=8000) compresses most scene depth into the [0.8, 1.0] range of the depth buffer. The hardcoded focal depth (0.9) is close to most objects' depth values, so the DOF blur effect is very subtle. The example may need either a narrower near/far ratio to spread depth values across more of the [0,1] range, or the focal point should be computed dynamically.
I ran tests for all 5 debugging steps suggested in the linked comment. All compile without errors:
The
uModelViewMatrixuniform is still set in_setGlobalUniforms()so shaders using it do compile, but produce geometrically incorrect results.The fix also needs to be applied to the example in the main p5.js repo (in
src/content/examples/en/11_3D/06_Framebuffer_Blur/).vamshi567bh commentedon Jun 20, 2026
@davepagurek if ok i will go with the pr thanks!
davepagurek commentedon Jun 20, 2026
Good catch! I guess we didn't notice before because most shaders don't directly use that uniform. I'll assign this to you now, feel free to go ahead with a PR.
vamshi567bh commentedon Jun 20, 2026
PR opened on p5.js-website: #1460
davepagurek commentedon Jun 20, 2026
I think we should also fix the matrix ordering in the p5 library too, if you're open to it
davepagurek commentedon Jun 20, 2026
@vamshi567bh I don't think we want to change the ordering of all matrix multiplies, that sounds like a super wide change that would have many unintended consequences. why not just flip the order of the model and view matrices in computing modelViewMatrix, as that's the only one not working correctly?
test: add regression tests for custom shader with framebuffer depth t…
vamshi567bh commentedon Jun 21, 2026
@davepagurek I looked into this more carefully. The current
modelMatrix.copy().mult(viewMatrix)is already correct — it gives us the right result in the shader. Flipping the order would actually break things. The blur example works fine with the current code (I added tests in PR processing/p5.js#8948 to confirm). The issue was likely caused by something else that's already been fixed.vamshi567bh commentedon Jun 21, 2026
the current order modelMatrix.copy().mult(viewMatrix) is actually correct. #mult4x4 performs multiplication in column-major convention where A.copy().mult(B) gives uModelViewMatrix = view × model in column-major. When used in GLSL as uProjectionMatrix * uModelViewMatrix * position, this becomes projection × view × model × position — model is applied first, then view, then projection. That's the correct pipeline.
Flipping to viewMatrix.copy().mult(modelMatrix) would give uModelViewMatrix = model × view in column-major, which in GLSL becomes projection × model × view × position — applying view before model, which is wrong.
I verified this with new regression tests in PR processing/p5.js#8948 that confirm the full custom shader + depth texture pipeline works correctly with the current code. The Framebuffer Blur example works with the library as-is; the issue was likely an older build without the uSampler override fix (commits f75f227 / 355a04b) or a website example compatibility issue (addressed by PR processing/p5.js#1460 on p5.js-website).
17 remaining items
BHARATH0153 commentedon Aug 12, 2026
@davepagurek thanks — that all makes sense
Smaller spheres.
sphere()currently defaults to r=50 while spacing iswidth/4, so they overlap badly when the sketch renders small. I'll drop the radius to something that reads cleanly at narrow widths.Space them in depth. The description says the closest and farthest spheres should appear blurred, but the row is currently all at z=0, so they share one depth value. I'll give each sphere a small z-offset (a shallow arc across the row, roughly ±40–60) so they sit at different depths, while keeping the spread small enough that they all stay visible when lined up horizontally on a small canvas.
Shallower DOF via
getBlurriness(). With the default camera the usable depth band is compressed (near 80 / far 8000 puts the row around depth 0.80–0.83), so the currentabs(d - 0.9) * 40produces almost no visible blur. I'll retune the focal depth to sit near the row's midpoint (≈0.82) and raise the blur multiplier so a small depth delta reads clearly. Starting values to verify visually in the web editor at desktop and mobile widths.Scope:
push()/pop()around the blur pass, all changes confined tosrc/content/examples/en/11_3D/06_Framebuffer_Blur/code.jsin p5.js-website. No library changes, and syntax highlighting is dropped as resolved.BHARATH0153 commentedon Aug 12, 2026
@davepagurek done #1572
davepagurek commentedon Aug 12, 2026
Hey everyone, I just wanted to leave a reminder that our AI policy disallows generation of comments without your review. Ultimately, even if intentions are good, these kinds of comments make it harder to triage and review issues, which makes it take longer for everyone for maintainers to respond. One of the things one can do to make it easier for maintainers to assign something to you is to show some evidence of having tested the claims in a comment, e.g. something like a screen recording or a link to a web editor sketch.
ksen0 commentedon Aug 13, 2026
Update on this issue: this issu is open for volunteers again. Please do check the updated notes on v2 changes about custom shaders (here: https://github.com/processing/p5.js-compatibility#custom-shaders) - the PR closing this issue should target the p5.js-website repository, and update the example code to reflect v2 usage.
bhabishnu commentedon Oct 13, 2026
I reproduced this locally and tested a minimal example-only fix.
There seem to be two separate things happening:
push()/pop()restores the intended sphere rendering.The minimal candidate I found that works at both 300×150 and 800×600 is:
sphere(width / 16)min(abs(d - 0.909) * 200., 4.)push()/pop()around the final blur pass0.909is the normalized depth of the rotation axis with the default camera, and the4.0cap keeps the blur from over-spreading at larger sizes.Here's the 300×150 comparison from the same test setup:
Would this scope be appropriate for the Technical Initiative?
ksen0 commentedon Oct 13, 2026
Thanks @bhabishnu ! I'll assign, that seems reasonable.
But tagging @davepagurek in case blur shader behavior in 2x is unintended?
EDIT: I've noticed you have some other work currently open so I won't assign additional tasks for now. Thanks for understanding
davepagurek commentedon Oct 13, 2026
Requiring a push/pop is intentional, adding the push/pop is good practice regardless.
The other updates are I think required due to camera defaults changing + the display size of the example changing I believe, so doing whatever looks best to make it look good at its current display size also sounds good. We intentionally left it less robust originally because the original glsl has enough boilerplate to make it kind of imposing in length so the rest is quite minimal. Potentially if we convert this to p5.strands we can also make the logic a little more robust to different sizes without the code getting overwhelming?
bhabishnu commentedon Oct 14, 2026
@ksen0 Thanks for the heads up! A few of the issues I'm on are already at the PR/review stage, but I'm happy to hold off on picking up anything new for now.
I should have a fair bit of time over the next couple of months though, so I'd still love to help out where useful. Would reviewing or testing other contributors' PRs be a good way to contribute in the meantime?
bhabishnu commentedon Oct 14, 2026
@davepagurek Thanks, that makes sense. I'll keep the fix focused on the current example and avoid making it any bigger than it needs to be.
ksen0 commentedon Oct 14, 2026
@bhabishnu yes, adding reviews to open PRs and helping us juggle the current increase in incoming PRs would be helpful! In a good review, we expect that the reviewer asks constructively and helpfully for specific iteration, based on something they know well. If you're not sure about something in the PR it is best to make it clear that you're able to review X but not about Y. If you notice contributors would benefit from some resource (eg this one https://p5js.org/contribute/contributing_to_the_p5js_reference/ I sometimes link on PRs related to docs updates where the implementer has not been able to test locally) sharing that is also helpful.
bhabishnu commentedon Oct 14, 2026
@ksen0 Appreciate the guidance! I’ll keep an eye out for places where I can help with reviews and testing.