Skip to content

Add Framebuffer support #6072

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

Merged
merged 20 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import './webgl/p5.Matrix';
import './webgl/p5.RendererGL.Immediate';
import './webgl/p5.RendererGL';
import './webgl/p5.RendererGL.Retained';
import './webgl/p5.Framebuffer';
import './webgl/p5.Shader';
import './webgl/p5.RenderBuffer';
import './webgl/p5.Texture';
Expand Down
30 changes: 30 additions & 0 deletions src/core/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -745,3 +745,33 @@ export const CONTAIN = 'contain';
* @final
*/
export const COVER = 'cover';

/**
* @property {String} UNSIGNED_BYTE
* @final
*/
export const UNSIGNED_BYTE = 'unsigned-byte';

/**
* @property {String} UNSIGNED_INT
* @final
*/
export const UNSIGNED_INT = 'unsigned-int';

/**
* @property {String} FLOAT
* @final
*/
export const FLOAT = 'float';

/**
* @property {String} FLOAT
* @final
*/
export const HALF_FLOAT = 'half-float';

/**
* @property {String} RGBA
* @final
*/
export const RGBA = 'rgba';
13 changes: 13 additions & 0 deletions src/core/p5.Graphics.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,17 @@ p5.Graphics = class extends p5.Element {
}
};

/**
* Creates and returns a new <a href="#/p5.Framebuffer">p5.Framebuffer</a>
* inside a p5.Graphics WebGL context.
*
* This takes the same parameters as the <a href="#/p5/createFramebuffer">global
* createFramebuffer function.</a>
*
* @method createFramebuffer
*/
p5.Graphics.prototype.createFramebuffer = function(options) {
return new p5.Framebuffer(this, options);
};

export default p5.Graphics;
75 changes: 75 additions & 0 deletions src/core/rendering.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,81 @@ p5.prototype.createGraphics = function(w, h, renderer) {
return new p5.Graphics(w, h, renderer, this);
};

/**
* Creates and returns a new <a href="#/p5.Framebuffer">p5.Framebuffer</a>, a
* high-performance WebGL object that you can draw to and then use as a texture.
*
* Options can include:
* - `format`: The data format of the texture, either `UNSIGNED_BYTE`, `FLOAT`, or `HALF_FLOAT`. The default is `UNSIGNED_BYTE`.
* - `channels`: What color channels to store, either `RGB` or `RGBA`. The default is to match the channels in the main canvas (with alpha unless disabled with `setAttributes`.)
* - `depth`: A boolean, whether or not to include a depth buffer. Defaults to true.
* - `depthFormat`: The data format for depth information, either `UNSIGNED_INT` or `FLOAT`. The default is `FLOAT` if available, or `UNSIGNED_INT` otherwise.
* - `antialias`: Boolean or Number, whether or not to render with antialiased edges, and if so, optionally the number of samples to use. Defaults to whether or not the main canvas is antialiased, using a default of 2 samples if so. Antialiasing is only supported when WebGL 2 is available.
* - `width`: The width of the texture. Defaults to matching the main canvas.
* - `height`: The height of the texture. Defaults to matching the main canvas.
* - `density`: The pixel density of the texture. Defaults to the pixel density of the main canvas.
* - `textureFiltering`: Either `LINEAR` (nearby pixels will be interpolated when reading values from the color texture) or `NEAREST` (no interpolation.) Generally, use `LINEAR` when using the texture as an image, and use `NEAREST` if reading the texture as data. Defaults to `LINEAR`.
*
* If `width`, `height`, or `density` are specified, then the framebuffer will
* keep that size until manually changed. Otherwise, it will be autosized, and
* it will update to match the main canvas's size and density when the main
* canvas changes.
*
* @method createFramebuffer
* @param {Object} [options] An optional object with configuration
*
* @example
* <div>
* <code>
* let prev, next, cam;
* function setup() {
* createCanvas(100, 100, WEBGL);
* prev = createFramebuffer({ format: FLOAT });
* next = createFramebuffer({ format: FLOAT });
* cam = createCamera();
* noStroke();
* }
*
* function draw() {
* // Swap prev and next so that we can use the previous
* // frame as a texture when drawing the current frame
* [prev, next] = [next, prev];
*
* // Draw to the framebuffer
* next.begin();
* background(255);
*
* push();
* // Draw the previous texture farther away, but scaled
* // up to fill the screen, plus a bit extra scale so it grows
* translate(0, 0, -200);
* scale(1.001 * (200 + cam.eyeZ) / cam.eyeZ);
* tint(255, 253);
* image(prev, -width/2, -height/2);
* pop();
*
* push();
* normalMaterial();
* translate(25*sin(frameCount * 0.014), 25*sin(frameCount * 0.02), 0);
* rotateX(frameCount * 0.01);
* rotateY(frameCount * 0.01);
* box(12);
* pop();
* next.end();
*
* image(next, -width/2, -height/2);
* }
* </code>
* </div>
*
* @alt
* A red, green, and blue box (using normalMaterial) moves and rotates around
* the canvas, leaving a trail behind it that slowly grows and fades away.
*/
p5.prototype.createFramebuffer = function(options) {
return new p5.Framebuffer(this, options);
};

/**
* Blends the pixels in the display window according to the defined mode.
* There is a choice of the following modes to blend the source pixels (A)
Expand Down
4 changes: 2 additions & 2 deletions src/image/loading_displaying.js
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ function _sAssign(sVal, iVal) {
*
*
* @method image
* @param {p5.Image|p5.Element|p5.Texture} img the image to display
* @param {p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} img the image to display
* @param {Number} x the x-coordinate of the top-left corner of the image
* @param {Number} y the y-coordinate of the top-left corner of the image
* @param {Number} [width] the width to draw the image
Expand Down Expand Up @@ -924,7 +924,7 @@ function _sAssign(sVal, iVal) {
*/
/**
* @method image
* @param {p5.Image|p5.Element|p5.Texture} img
* @param {p5.Image|p5.Element|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} img
* @param {Number} dx the x-coordinate of the destination
* rectangle in which to draw the source image
* @param {Number} dy the y-coordinate of the destination
Expand Down
7 changes: 3 additions & 4 deletions src/webgl/material.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ p5.prototype.resetShader = function() {
* <a href="https://p5js.org/examples/3d-materials.html">example</a>.
*
* @method texture
* @param {p5.Image|p5.MediaElement|p5.Graphics|p5.Texture} tex image to use as texture
* @param {p5.Image|p5.MediaElement|p5.Graphics|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} tex image to use as texture
* @chainable
* @example
* <div>
Expand Down Expand Up @@ -666,9 +666,8 @@ p5.prototype.textureWrap = function(wrapX, wrapY = wrapX) {
this._renderer.textureWrapX = wrapX;
this._renderer.textureWrapY = wrapY;

const textures = this._renderer.textures;
for (let i = 0; i < textures.length; i++) {
textures[i].setWrapMode(wrapX, wrapY);
for (const texture of this._renderer.textures.values()) {
texture.setWrapMode(wrapX, wrapY);
}
};

Expand Down
7 changes: 4 additions & 3 deletions src/webgl/p5.Camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ p5.Camera = function(renderer) {

this.cameraMatrix = new p5.Matrix();
this.projMatrix = new p5.Matrix();
this.yScale = 1;
};
/**
* camera position value on x axis
Expand Down Expand Up @@ -811,7 +812,7 @@ p5.Camera.prototype.perspective = function(fovy, aspect, near, far) {

/* eslint-disable indent */
this.projMatrix.set(f / aspect, 0, 0, 0,
0, -f, 0, 0,
0, -f * this.yScale, 0, 0,
0, 0, (far + near) * nf, -1,
0, 0, (2 * far * near) * nf, 0);
/* eslint-enable indent */
Expand Down Expand Up @@ -895,7 +896,7 @@ p5.Camera.prototype.ortho = function(left, right, bottom, top, near, far) {
const d = far - near;

const x = +2.0 / w;
const y = +2.0 / h;
const y = +2.0 / h * this.yScale;
const z = -2.0 / d;

const tx = -(right + left) / w;
Expand Down Expand Up @@ -991,7 +992,7 @@ p5.Camera.prototype.frustum = function(left, right, bottom, top, near, far) {
const d = far - near;

const x = +(2.0 * near) / w;
const y = +(2.0 * near) / h;
const y = +(2.0 * near) / h * this.yScale;
const z = -(2.0 * far * near) / d;

const tx = (right + left) / w;
Expand Down
Loading