Skip to content

Commit

Permalink
v-0.10.0 init (mMatrix) -> support p5 v-1.10.0
Browse files Browse the repository at this point in the history
  • Loading branch information
nakednous committed Aug 9, 2024
1 parent fe35b35 commit f82be94
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 85 deletions.
19 changes: 3 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Shader development and space transformations [WEBGL](https://p5js.org/reference/
- [Apply shader](#apply-shader)
- [Post-effects](#post-effects)
- [Macros](#macros)
- [Bind matrices](#bind-matrices)
- [Space transformations](#space-transformations)
- [Matrix operations](#matrix-operations)
- [Matrix queries](#matrix-queries)
Expand All @@ -31,13 +30,13 @@ let iMatrix = invMatrix(matrix)
// iMatrix !== matrix
```

Note that functions in the [Shaders](#shaders) and [Matrix operations](#matrix-operations) sections are available only to `p5`; those in the [Matrix Queries](#matrix-queries), [Bind Matrices](#bind-matrices), [Space Transformations](#space-transformations), [Heads Up Display](#heads-up-display), [Utilities](#utilities), and [Drawing Stuff](#drawing-stuff) sections are accessible to both `p5` and [p5.RendererGL](https://p5js.org/reference/#/p5.Renderer) instances; functions in the [Frustum Queries](#frustum-queries) section are available to `p5`, [p5.RendererGL](https://p5js.org/reference/#/p5.Renderer), and [p5.Matrix](https://github.com/processing/p5.js/blob/main/src/webgl/p5.Matrix.js) instances.
Note that functions in the [Shaders](#shaders) and [Matrix operations](#matrix-operations) sections are available only to `p5`; those in the [Matrix Queries](#matrix-queries), [Space Transformations](#space-transformations), [Heads Up Display](#heads-up-display), [Utilities](#utilities), and [Drawing Stuff](#drawing-stuff) sections are accessible to both `p5` and [p5.RendererGL](https://p5js.org/reference/#/p5.Renderer) instances; functions in the [Frustum Queries](#frustum-queries) section are available to `p5`, [p5.RendererGL](https://p5js.org/reference/#/p5.Renderer), and [p5.Matrix](https://github.com/processing/p5.js/blob/main/src/webgl/p5.Matrix.js) instances.

Parameters for `p5.treegl` functions can be provided in any order, unless specified otherwise.

# Shaders

`p5.treegl` simplifies the creation and application of shaders in `WEBGL`. It covers the essentials from setting up shaders with [`Setup`](#setup), managing shader uniforms through a [uniforms user interface](#uniformsui), applying shaders using [`Apply shader`](#apply-shader), enhancing visuals with [`Post-effects`](#post-effects), setting common uniform variables using several [`Macros`](#macros), and binding matrices in [`Bind matrices`](#bind-matrices).
`p5.treegl` simplifies the creation and application of shaders in `WEBGL`. It covers the essentials from setting up shaders with [`Setup`](#setup), managing shader uniforms through a [uniforms user interface](#uniformsui), applying shaders using [`Apply shader`](#apply-shader), enhancing visuals with [`Post-effects`](#post-effects), and setting common uniform variables using several [`Macros`](#macros).

Have a look at the [toon shading](https://nakednous.github.io/posts/toon/), [blur with focal point](https://nakednous.github.io/posts/blur/), [post-effects](https://nakednous.github.io/posts/post_effects/), and [gpu-based photomosaic](https://nakednous.github.io/posts/photomosaic/) examples.

Expand Down Expand Up @@ -254,18 +253,6 @@ Retrieve image offset, mouse position, pointer position and screen resolution wh
3. `pointerPosition(pointerX, pointerY)` which is the same as: `return [pointerX * this.pixelDensity(), (this.height - pointerY) * this.pixelDensity()]`. Available to both, the `p5` object and [p5.RendererGL](https://p5js.org/reference/#/p5.Renderer) instances. Note that `pointerX` should always be the first parameter and `pointerY` the second.
4. `resolution()` which is the same as: `return [this.width * this.pixelDensity(), this.height * this.pixelDensity()]`. Available to both, the `p5` object and [p5.RendererGL](https://p5js.org/reference/#/p5.Renderer) instances.

## Bind matrices

By specifying additional matrices alongside those already emitted automatically by [p5.js](https://github.com/processing/p5.js/blob/main/contributor_docs/webgl_mode_architecture.md), such as `uProjectionMatrix` and `uViewMatrix`, developers can leverage enhanced transformations in their shaders.

1. `bindMatrices(matrices = Tree.NONE)`: Binds additional matrices to the current renderer specified by the `matrices` bit mask, thereby enabling the following matrix uniforms to be emitted to the shader: `Tree.eMatrix` (emits `uEyeMatrix`), `Tree.mMatrix` (emits `uModelMatrix`), `Tree.pvMatrix` (emits `uProjectionViewMatrix`), and `Tree.pvInvMatrix` (emits `uProjectionViewInverseMatrix`). For example:

```js
// Bind additional eMatrix and mMatrix to the current renderer
// should be called after setAttributes
bindMatrices(Tree.eMatrix | Tree.mMatrix)
```

# Space transformations

This section delves into matrix manipulations and queries which are essential for 3D rendering. It includes functions for matrix operations like creation, inversion, and multiplication in the [Matrix operations](#matrix-operations) subsection, and offers methods to retrieve transformation matrices and perform space conversions in [Matrix queries](#matrix-queries), [Frustum queries](#frustum-queries), and [Coordinate Space conversions](#coordinate-space-conversions), facilitating detailed control over 3D scene transformations.
Expand Down Expand Up @@ -379,7 +366,7 @@ This section comprises a collection of handy functions designed to facilitate co

1. `pixelRatio(location)`: Returns the world to pixel ratio units at given world location, i.e., a line of `n * pixelRatio(location)` world units will be projected with a length of `n` pixels on screen.
2. `mousePicking({ [mMatrix = this.mMatrix()], [x], [y], [size = 50], [shape = Tree.CIRCLE], [eMatrix], [pMatrix], [vMatrix], [pvMatrix] })`: same as `return this.pointerPicking(this.mouseX, this.mouseY, { mMatrix: mMatrix, x: x, y: y, size: size, shape: shape, eMatrix: eMatrix, pMatrix: pMatrix, vMatrix: vMatrix, pvMatrix: pvMatrix })` (see below).
3. `pointerPicking(pointerX, pointerY, { [mMatrix = this.mMatrix()], [x], [y], [size = 50], [shape = Tree.CIRCLE], [eMatrix], [pMatrix], [vMatrix], [pvMatrix] })`: Returns `true` if `pointerX`, `pointerY` lies within the screen space circle centered at (`x`, `y`) and having `size` diameter. Pass `mMatrix` to compute (`x`, `y`) as the screen space projection of the local space origin (defined by `mMatrix`), having `size` as its bounding sphere diameter. Use `Tree.SQUARE` to use a squared shape instead of a circled one. Note that `pointerX` should always be the first parameter and `pointerY` the second.
3. `pointerPicking(pointerX, pointerY, { [mMatrix = this.mMatrix()], [x], [y], [size = 50], [shape = Tree.CIRCLE], [eMatrix], [pMatrix], [vMatrix], [pvMatrix] })`: Returns `true` if `pointerX`, `pointerY` lies within the screen space circle centered at (`x`, `y`) and having `size` diameter. Pass `mMatrix` to compute (`x`, `y`) as the screen space projection of the local space origin (defined by `mMatrix`), having `size` as its bounding sphere diameter. Use `Tree.SQUARE` to use a squared shape instead of a circled one. Note that `pointerX` should always be specified before `pointerY`.
4. `visibility`: Returns object visibility, either as `Tree.VISIBLE`, `Tree.INVISIBLE`, or `Tree.SEMIVISIBLE`. Object may be either a _point_: `visibility({ center, [bounds = this.bounds([{[eMatrix = this.eMatrix()], [vMatrix = this.vMatrix()]}])]})`, a _ball_: `visibility({ center, radius, [bounds = this.bounds()]})` or an _axis-aligned box_: `visibility({ corner1, corner2, [bounds = this.bounds()]})`.
5. `bounds()`: Returns the [general form](http://www.songho.ca/math/plane/plane.html) of the current frustum six plane equations, i.e., _ax + by + cz + d = 0_, formatted as an object literal having keys: `Tree.LEFT`, `Tree.RIGHT`, `Tree.BOTTOM`, `Tree.TOP`, `Tree.NEAR` and `Tree.FAR`, e.g., access the near plane coefficients as:
```js
Expand Down
115 changes: 46 additions & 69 deletions p5.treegl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// TODO's
// blog apps demos docs.
// i. p5-v2; ii. only WEBGL (?); iii. instance mode tests
// i. p5-v2; ii. only WEBGL (?); iii. instance mode tests; iv. ndc vfc is broken; v. mvMatrix testing
// See:
// https://github.com/processing/p5.js/blob/main/contributor_docs/creating_libraries.md
// https://github.com/processing/p5.js/blob/main/src/core/README.md
Expand All @@ -11,7 +11,7 @@
var Tree = (function (ext) {
const INFO = {
LIBRARY: 'p5.treegl',
VERSION: '0.9.8',
VERSION: '0.10.0',
HOMEPAGE: 'https://github.com/VisualComputing/p5.treegl'
};
Object.freeze(INFO);
Expand Down Expand Up @@ -65,13 +65,13 @@ var Tree = (function (ext) {
const mediump = 1;
const highp = 2;
// Matrices
const vMatrix = 1 << 0;
const pMatrix = 1 << 1;
const mvMatrix = 1 << 2;
const pmvMatrix = 1 << 3;
const nMatrix = 1 << 4;
const eMatrix = 1 << 5; // only tree
const mMatrix = 1 << 6; // only tree
const pMatrix = 1 << 0;
const mMatrix = 1 << 1;
const vMatrix = 1 << 2;
const mvMatrix = 1 << 3;
const pmvMatrix = 1 << 4;
const nMatrix = 1 << 5;
const eMatrix = 1 << 6; // only tree
const pvMatrix = 1 << 7; // only tree
const pvInvMatrix = 1 << 8; // only tree
// Varyings
Expand All @@ -91,8 +91,8 @@ var Tree = (function (ext) {
WORLD, EYE, NDC, SCREEN, MODEL,
ORIGIN, i, j, k, _i, _j, _k,
lowp, mediump, highp,
vMatrix, pMatrix, mvMatrix, pmvMatrix, nMatrix,
eMatrix, mMatrix, pvMatrix, pvInvMatrix, // only tree
pMatrix, mMatrix, vMatrix, mvMatrix, pmvMatrix, nMatrix,
eMatrix, pvMatrix, pvInvMatrix, // only tree
color4, texcoords2, normal3, position2, position3, position4
});
return ext;
Expand Down Expand Up @@ -185,6 +185,14 @@ window.Tree = Tree;
return this.uPMatrix.copy();
}

p5.prototype.mMatrix = function (...args) {
return this._renderer.mMatrix(...args);
}

p5.RendererGL.prototype.mMatrix = function () {
return this.uModelMatrix.copy();
}

p5.prototype.mvMatrix = function (...args) {
return this._renderer.mvMatrix(...args);
}
Expand All @@ -193,23 +201,12 @@ window.Tree = Tree;
// otherwise it returns a copy of the current mvMatrix
p5.RendererGL.prototype.mvMatrix = function (
{
vMatrix,
mMatrix
} = {}) {
return mMatrix ? (vMatrix ?? this.vMatrix()).copy().apply(mMatrix) : this.uMVMatrix.copy();
}

p5.prototype.mMatrix = function (...args) {
return this._renderer.mMatrix(...args);
}

// defaults: eMatrix: this.eMatrix, mvMatrix: this.mvMatrix
p5.RendererGL.prototype.mMatrix = function (
{
eMatrix = this.eMatrix(),
mvMatrix = this.mvMatrix()
vMatrix = this._curCamera.cameraMatrix,
mMatrix = this.uModelMatrix
} = {}) {
return eMatrix.copy().apply(mvMatrix);
return vMatrix.copy().apply(mMatrix); // same as: (mMatrix.copy()).mult(vMatrix);
// TODO (upstream) gives different results: return this.uMVMatrix.copy()
// previous: return mMatrix ? (vMatrix ?? this.vMatrix()).copy().apply(mMatrix) : this.uMVMatrix.copy();
}

p5.prototype.nMatrix = function (...args) {
Expand Down Expand Up @@ -426,13 +423,15 @@ window.Tree = Tree;
}

p5.RendererGL.prototype.beginHUD = function () {
this.mv = this.mvMatrix();
this.m = this.mMatrix();
this.v = this.vMatrix();
this.p = this.pMatrix();
this._rendererState = this.push();
let gl = this.drawingContext;
gl.flush();
gl.disable(gl.DEPTH_TEST);
this.uMVMatrix = new p5.Matrix();
this.uModelMatrix = new p5.Matrix();
this.uViewMatrix = new p5.Matrix();
let z = Number.MAX_VALUE;
this._curCamera.ortho(0, this.width, -this.height, 0, -z, z);
// this._curCamera.ortho(0, this.width, 0, -this.height, -z, z); // <- flipped
Expand All @@ -451,7 +450,8 @@ window.Tree = Tree;
gl.enable(gl.DEPTH_TEST);
this.pop(this._rendererState);
this.uPMatrix.set(this.p);
this.uMVMatrix.set(this.mv);
this.uModelMatrix.set(this.m);
this.uViewMatrix.set(this.v);
this._hud = false;
}

Expand Down Expand Up @@ -808,29 +808,6 @@ window.Tree = Tree;

// 3. Shader utilities

const __setMatrixUniforms = p5.Shader.prototype._setMatrixUniforms;

p5.Shader.prototype._setMatrixUniforms = function (...args) {
__setMatrixUniforms.apply(this, ...args);
const matrices = this._renderer._matrices;
if (matrices) {
// this.uniforms.uNormalMatrix condition taken from upstream _setMatrixUniforms
(!this.uniforms.uNormalMatrix && (matrices & Tree.nMatrix) !== 0) && this.setUniform('uNormalMatrix', this._renderer.nMatrix().mat3);
((matrices & Tree.eMatrix) !== 0) && this.setUniform('uEyeMatrix', this._renderer.eMatrix().mat4);
((matrices & Tree.mMatrix) !== 0) && this.setUniform('uModelMatrix', this._renderer.mMatrix().mat4);
((matrices & Tree.pvMatrix) !== 0) && this.setUniform('uProjectionViewMatrix', this._renderer.pvMatrix().mat4);
((matrices & Tree.pvInvMatrix) !== 0) && this.setUniform('uProjectionViewInverseMatrix', this._renderer.pvInvMatrix().mat4);
}
}

p5.prototype.bindMatrices = function (...args) {
this._renderer.bindMatrices(...args);
}

p5.RendererGL.prototype.bindMatrices = function (matrices = Tree.NONE) {
this._matrices = matrices;
}

p5.prototype.parseShader = function (...args) {
const makeCondition = args.some(arg => typeof arg === 'string' && (arg.includes('\n') || arg.includes('\r')));
return makeCondition ? this.makeShader(...args) : this.readShader(...args);
Expand Down Expand Up @@ -1609,23 +1586,22 @@ void main() {

/**
* Returns true if pointer is close enough to pointerX, pointerY screen position.
* @param {p5.Matrix} mMatrix model space matrix origin to compute (x, y) from.
* @param {Number} x screen x coordinate. Default is width / 2.
* @param {Number} y screen y coordinate. Default is height / 2.
* @param {p5.Matrix} mMatrix model space matrix origin to compute (x, y) from.
* @param {Number} size bullseye diameter. Default is 50.
* @param {Number} shape either Tree.CIRCLE, Tree.SQUARE or Tree.PROJECTION. Default is Tree.CIRCLE.
*/
p5.RendererGL.prototype.pointerPicking = function (pointerX, pointerY, {
mMatrix = this.mMatrix(),
x,
y,
size = 50,
shape = Tree.CIRCLE,
eMatrix,
pMatrix,
vMatrix,
pvMatrix
} = {}) {
p5.RendererGL.prototype.pointerPicking = function (...args) {
let pointerX, pointerY, config = {};
args.forEach(arg => {
if (typeof arg === 'number') {
pointerX === undefined ? pointerX = arg : pointerY = arg;
} else if (typeof arg === 'object') {
config = arg;
}
});
let { mMatrix = this.mMatrix(), x, y, size = 50, shape = Tree.CIRCLE, eMatrix, pMatrix, vMatrix, pvMatrix } = config;
if (!(x && y)) {
let screenPosition = this.parsePosition({ from: mMatrix, to: Tree.SCREEN, pMatrix, vMatrix, pvMatrix });
x = screenPosition.x;
Expand All @@ -1634,9 +1610,9 @@ void main() {
}
// TODO implement webgl picking here using a switch statement: Tree.CIRCLE, Tree.SQUARE, Tree.PROJECTION
let radius = size / 2;
return shape === Tree.CIRCLE ?
Math.sqrt(Math.pow((x - pointerX), 2.0) + Math.pow((y - pointerY), 2.0)) < radius :
((Math.abs(pointerX - x) < radius) && (Math.abs(pointerY - y) < radius));
return shape === Tree.CIRCLE
? Math.sqrt(Math.pow((x - pointerX), 2.0) + Math.pow((y - pointerY), 2.0)) < radius
: ((Math.abs(pointerX - x) < radius) && (Math.abs(pointerY - y) < radius));
}

// 5. Drawing stuff
Expand Down Expand Up @@ -1946,7 +1922,8 @@ void main() {
}
// save state
this._rendererState = this.push();
this.uMVMatrix = new p5.Matrix();
this.uModelMatrix = new p5.Matrix();
this.uViewMatrix = new p5.Matrix();
// transform from world space to this eye
this.applyMatrix(...(vMatrix).mat4);
// transform from eye space to world space
Expand Down

0 comments on commit f82be94

Please sign in to comment.