Skip to content

Support for drawing to/reading from framebuffers #6018

Closed
@davepagurek

Description

@davepagurek

Increasing Access

createGraphics is currently the recommended way to create a texture and use it elsewhere in a sketch. While this is very flexible and approachable, it unfortunately comes with inherent performance implications (#5128) that are currently are hard to work around within p5. Framebuffers are the native WebGL solution to this task with the best potential performance.

Giving users access to better performance with, ideally, a simple and familiar interface would let their sketches take better advantage of hardware capabilities and give viewers with lower-end hardware a much smoother viewing experience.

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)

Feature request details

While for technical reasons it will not be feasible to make all graphics used as textures use Framebuffers under the hood, we believe creating an interface for Framebuffers that fits well with existing p5 features will still be beneficial.

Inspiration

High level features

  • A Framebuffer class can be created with createFramebuffer()
  • It may only be used in WebGL environments
  • If WebGL2 is enabled, antialiasing is supported
    • We have decided, at first at least, we will not try to provide an antialiasing fallback on WebGL1
    • The most practical fallback option would be to render at 2x pixel density. However, this has a noticeable performance impact which is especially large on the sorts of older devices that don't have WebGL2 support. For that reason, we believe a more reasonable option is to degrade gracefully to a 1x density non-antialiased Framebuffer if only WebGL1 is available.
  • The Framebuffer can be passed into texture() or setUniform() or image() like a graphic can

Implementation details

  • Things that aren't part of the main motivation but we would get as a side effect:
    • Writing in floating point format
      • This has been asked for directly, but also indirectly after people notice artifacts in feedback sketches
      • Readable depth information (not essential for v1)
      • p5.Framebuffer allows this to be read via the .depth property of a framebuffer
  • How does one choose a framebuffer to draw to?
    • Prior art:
      • p5.Framebuffer: fbo.draw(() => /* ... */)
      • p5Fbo, ofFbo: fbo.begin(); /* ... */ fbo.end();
    • Probably the begin/end version is more similar to push/pop and is what we should go with
      • The callback function version could also potentially be added on top of this as a way to avoid accidental improper nesting of begin/end, but this is not essential
  • Different size support
    • Each fbo has to come with its own camera in order to be able to properly render to a size different from the main canvas
  • We probably do not want to (at least initially) support all texture formats
    • By making users ask for either UNSIGNED_BYTE (default) or FLOAT, this lets us pick the appropriate mode for the environment (WebGL1, WebGL2, etc)
    • Antialiasing support will need lots of testing (p5.Framebuffer supports this but runs into cross-browser version issues often) so letting us pick texture modes that work will give us an avenue for resolving these sorts of issues

Metadata

Metadata

Assignees

Type

No type

Projects

Status

DONE! 🎉

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions