Allows to draw p5js elements to a Looking Glass holographic display
npm install p5-holoplayshell
npm i p5-holoplay
`
and including it in your javascript as a CommonsJS module (it will need bundling to run on the browser)
`js
const { sketchP2d, sketchWebgl } = require('p5-holoplay');
`
Then prepare your _setup_, _draw_, etc. functions as explained below and pass them to the chosen mode, _P2D_ or _WEBGL_.
How to create p5 holograms
This project integrates p5js in instance mode. This means the usual p5 methods and properties are not in the global namespace (available everywhere), but bundled in a variable.
You have to choose one of two drawing modes.
- sketchP2d: Uses p5's P2D renderer. It draws flat (2D) shapes to 3D space by specifying a depth value for each block of drawing code.
- sketchWebgl: Uses p5's WEBGL renderer. It draws 3D shapes and uses lights to show volumes.
The basic usage of both modes is similar. The _sketchP2d_ or _sketchWebgl_ function accepts an object with functions named after the typical p5js functions (_preload_, _setup_, _draw_) and an options object.
`js
sketchp2d({ preload, setup, draw, options });
`
These functions will pass the p variable so you can use the p5 methods and properties. So instead of
`js
function setup() {
background(255);
}
`
You can do
`js
const setup = p => {
p.background(255);
};
`
The functions you provide to each mode are significantly different:
$3
- setup provides _p_, _error_, _meta_ (additional data for advanced work). Creates a canvas of the necessary dimensions (you don't need to create it yourself). Similar to setup(). Runs automatically once at the beginning of the life cycle.
- draw provides _p_, _add_ (essential function to add layers), _meta_. Runs every frame. Allows to add layers in the form of a function and its depth. P5 work commonly done in p5 draw() should work here. Layer functions are run multiple times (one for every camera view, 48 in the case of the Looking Glass Portrait), while the rest of the code is only ran once per frame. So take that into account when deciding what to put inside of an "add" function (probably not an incrementing counter). Similar to draw().
"Add" functions must receive a drawing function and a depth value (positive means further from the viewer, negative is closer to them).
`js
const draw = (p, add) => {
add(() => {
p.fill(255, 0, 0);
p.ellipse(0, 0, 100);
}, 100);
};
`
Depth values between 100 and -100 seem to draw layers with noticeable depth but more or less within the frame of the device. Larger values will produce more impressive effects, but also blurrier graphics (which might be fine, creatively). If depth is omitted, Infinity will be assumed, which is meant for functions that don't rely on depth, like _p.background()_.
Layers are not necessarily drawn in the order your _add_ them. They are drawn from farther to nearer, so don't expect changes you make to things like _stroke_, _fill_ and other to persist between added layers. Set all you need for each layer within its own function. Each added function can be thought of like a mini p5 draw function.
This syntax can get complicated quickly, but is an alternative to thoroughly modifying p5 to make it generate the 'quilt'.
$3
- setup provides _p_, _error_, _meta_. Runs automatically once at the beginning of the life cycle, but _p_ here refers to the preview window, not the canvases where the actual shapes are drawn. This means you can include here things that need to happen only once (like lifecycle events, mouse/keyboard interactions...), but not those that affect the drawings directly (like colors, strokes, fills, fonts...). Similar to setup().
- setupEach provides _p_, _error_, _meta_. Creates all the necessary canvases to build the 3D images from multiple camera perspectives. Runs multiple times due to the complex underlying structure. Specify permanent drawing settings here, like potentially colors, strokes, fills, fonts... Similar to setup().
- preDraw provides _p_, _meta_. Runs once per every new frame of the preview window. It does not affect the final drawn image. You can include code that should run each frame but is not related to each camera view. For example, store mouse positions only once per frame to use in the _draw_ function. Similar to draw().
- draw provides _p_, _meta_. Runs multiple times per frame (once for each virtual camera perspective). Place here the geometries you want to draw, camera work, and style data (stroke, colors...) that changes based on other inputs. The frame and lights reset every frame, so don't rely on them being preserved. Similar to draw().
`js
let ballX, ballY;
const preDraw = p => {
// Store the same mouse positions for all the camera views
ballX = p.mouseX - p.width / 2;
ballY = p.mouseY - p.height / 2;
};
const draw = p => {
normalMaterial();
sphere(ballX, ballY, 50);
};
`
$3
Additionally, a preload function can be passed to both modes.
- preload receives _p_. Useful for loading things like images or fonts before running the p5 sketch. Similar to preload().
meta
A _meta_ object is passed with some functions to enable advanced work. The object can include the following (but not always does, so check the data before using it):
- device: Hardware data from holoplay-core.
- viewerFrame: Frame number of the Looking Glass device. Potential replacement of p5's frameCount Useful because it does not update at p5's normal frame rate.
- previewFrame: (_WEBGL_ only) Frame number of the preview canvas. Potential replacement of p5's frameCount Useful because it does not update at p5's normal frame rate, nor at the Looking Glass rate.
- cam: (_WEBGL_ only) p5.Camera of the view that is currently being drawn. It allows camera transformations like position and field of view.
- millis: (_WEBGL_ only) Time since the stetch started running, in milliseconds. Potential replacement of millis(), which would change while the multiple views are being drawn, this providing unexpected results.
- quilt: Reference to the p5.Graphics holding the 'quilt' being sent to the Looking Glass device. Useful for doing things with that specific canvas, like saving it to a file with [].save()](https://p5js.org/reference/#/p5/save).
- preview: Reference to the p5.Renderer holding the preview visualization.
- p: Reference to the p5 sketch. In _WEBGL_ mode, it can be more representative than the main _p_ of the _draw_ function, as that refers to the camera perspective being drawn at any given time. So use it for things like sketch width, mouse position...
$3
Other p5 functions that would be normally set globally should be set in the setup once the _p_ variable is available.
For example, instead of
`js
function mouseClicked() {
console.log(mouseX, mouseY);
}
`
you would do
`js
setup = p => {
p.mouseClicked = () => {
console.log(p.mouseX, p.mouseY);
};
};
`
For more p5 methods and properties, see the reference.
$3
An _options_ object can also be passed to the main functions.
`js
const options = {
wigglePreview: false,
previewQuilt: true,
adaptSize: false,
depth: 120
};
``